15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * AES Cipher function: encrypt 'input' with Rijndael algorithm
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   takes   byte-array 'input' (16 bytes)
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *           2D byte-array key schedule 'w' (Nr+1 x Nb bytes)
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   returns byte-array encrypted value (16 bytes)
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function Cipher(input, w) {    // main Cipher function [§5.1]
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var Nb = 4;               // block size (in words): no of columns in state (fixed at 4 for AES)
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var state = [[],[],[],[]];  // initialise 4xNb byte-array 'state' with input [§3.4]
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i];
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  state = AddRoundKey(state, w, 0, Nb);
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var round=1; round<Nr; round++) {
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    state = SubBytes(state, Nb);
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    state = ShiftRows(state, Nb);
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    state = MixColumns(state, Nb);
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    state = AddRoundKey(state, w, round, Nb);
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  state = SubBytes(state, Nb);
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  state = ShiftRows(state, Nb);
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  state = AddRoundKey(state, w, Nr, Nb);
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var output = new Array(4*Nb);  // convert state to 1-d array before returning [§3.4]
345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<4*Nb; i++) output[i] = state[i%4][Math.floor(i/4)];
355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return output;
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function SubBytes(s, Nb) {    // apply SBox to state S [§5.1.1]
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var r=0; r<4; r++) {
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var c=0; c<Nb; c++) s[r][c] = Sbox[s[r][c]];
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return s;
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function ShiftRows(s, Nb) {    // shift row r of state S left by r bytes [§5.1.2]
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var t = new Array(4);
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var r=1; r<4; r++) {
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var c=0; c<4; c++) t[c] = s[r][(c+r)%Nb];  // shift into temp copy
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var c=0; c<4; c++) s[r][c] = t[c];         // and copy back
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }          // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return s;  // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function MixColumns(s, Nb) {   // combine bytes of each col of state S [§5.1.3]
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var c=0; c<4; c++) {
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var a = new Array(4);  // 'a' is a copy of the current column from 's'
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var b = new Array(4);  // 'b' is a•{02} in GF(2^8)
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i=0; i<4; i++) {
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      a[i] = s[i][c];
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      b[i] = s[i][c]&0x80 ? s[i][c]<<1 ^ 0x011b : s[i][c]<<1;
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // a[n] ^ b[n] is a•{03} in GF(2^8)
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    s[0][c] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3]; // 2*a0 + 3*a1 + a2 + a3
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    s[1][c] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3]; // a0 * 2*a1 + 3*a2 + a3
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    s[2][c] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3]; // a0 + a1 + 2*a2 + 3*a3
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    s[3][c] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3]; // 3*a0 + a1 + a2 + 2*a3
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return s;
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function AddRoundKey(state, w, rnd, Nb) {  // xor Round Key into state S [§5.1.4]
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var r=0; r<4; r++) {
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var c=0; c<Nb; c++) state[r][c] ^= w[rnd*4+c][r];
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return state;
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function KeyExpansion(key) {  // generate Key Schedule (byte-array Nr+1 x Nb) from Key [§5.2]
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var Nb = 4;            // block size (in words): no of columns in state (fixed at 4 for AES)
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var Nk = key.length/4  // key length (in words): 4/6/8 for 128/192/256-bit keys
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var Nr = Nk + 6;       // no of rounds: 10/12/14 for 128/192/256-bit keys
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var w = new Array(Nb*(Nr+1));
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var temp = new Array(4);
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<Nk; i++) {
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var r = [key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]];
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    w[i] = r;
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=Nk; i<(Nb*(Nr+1)); i++) {
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    w[i] = new Array(4);
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var t=0; t<4; t++) temp[t] = w[i-1][t];
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (i % Nk == 0) {
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      temp = SubWord(RotWord(temp));
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      for (var t=0; t<4; t++) temp[t] ^= Rcon[i/Nk][t];
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    } else if (Nk > 6 && i%Nk == 4) {
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      temp = SubWord(temp);
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t];
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return w;
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function SubWord(w) {    // apply SBox to 4-byte word w
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<4; i++) w[i] = Sbox[w[i]];
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return w;
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function RotWord(w) {    // rotate 4-byte word w left by one byte
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  w[4] = w[0];
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<4; i++) w[i] = w[i+1];
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return w;
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1]
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var Sbox =  [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16];
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2]
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var Rcon = [ [0x00, 0x00, 0x00, 0x00],
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x01, 0x00, 0x00, 0x00],
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x02, 0x00, 0x00, 0x00],
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x04, 0x00, 0x00, 0x00],
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x08, 0x00, 0x00, 0x00],
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x10, 0x00, 0x00, 0x00],
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x20, 0x00, 0x00, 0x00],
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x40, 0x00, 0x00, 0x00],
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x80, 0x00, 0x00, 0x00],
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x1b, 0x00, 0x00, 0x00],
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)             [0x36, 0x00, 0x00, 0x00] ];
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Use AES to encrypt 'plaintext' with 'password' using 'nBits' key, in 'Counter' mode of operation
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *                           - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   for each block
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   - outputblock = cipher(counter, key)
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   - cipherblock = plaintext xor outputblock
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function AESEncryptCtr(plaintext, password, nBits) {
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  if (!(nBits==128 || nBits==192 || nBits==256)) return '';  // standard allows 128/192/256 bit keys
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // for this example script, generate the key by applying Cipher to 1st 16/24/32 chars of password;
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // for real-world applications, a more secure approach would be to hash the password e.g. with SHA-1
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var nBytes = nBits/8;  // no bytes in key
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var pwBytes = new Array(nBytes);
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var key = Cipher(pwBytes, KeyExpansion(pwBytes));
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  key = key.concat(key.slice(0, nBytes-16));  // key is now 16/24/32 bytes long
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in 1st 8 bytes,
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // block counter in 2nd 8 bytes
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var blockSize = 16;  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var counterBlock = new Array(blockSize);  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var nonce = (new Date()).getTime();  // milliseconds since 1-Jan-1970
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // encode nonce in two stages to cater for JavaScript 32-bit limit on bitwise ops
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<4; i++) counterBlock[i] = (nonce >>> i*8) & 0xff;
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff;
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // generate key schedule - an expansion of the key into distinct Key Rounds for each round
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var keySchedule = KeyExpansion(key);
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var blockCount = Math.ceil(plaintext.length/blockSize);
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var ciphertext = new Array(blockCount);  // ciphertext as array of strings
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var b=0; b<blockCount; b++) {
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // again done in two stages for 32-bit ops
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff;
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8)
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var cipherCntr = Cipher(counterBlock, keySchedule);  // -- encrypt counter block --
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // calculate length of final block:
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1;
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var ct = '';
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i=0; i<blockLength; i++) {  // -- xor plaintext with ciphered counter byte-by-byte --
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      var plaintextByte = plaintext.charCodeAt(b*blockSize+i);
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      var cipherByte = plaintextByte ^ cipherCntr[i];
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      ct += String.fromCharCode(cipherByte);
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // ct is now ciphertext for this block
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ciphertext[b] = escCtrlChars(ct);  // escape troublesome characters in ciphertext
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // convert the nonce to a string to go on the front of the ciphertext
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var ctrTxt = '';
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]);
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ctrTxt = escCtrlChars(ctrTxt);
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // use '-' to separate blocks, use Array.join to concatenate arrays of strings for efficiency
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return ctrTxt + '-' + ciphertext.join('-');
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Use AES to decrypt 'ciphertext' with 'password' using 'nBits' key, in Counter mode of operation
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   for each block
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   - outputblock = cipher(counter, key)
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *   - cipherblock = plaintext xor outputblock
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function AESDecryptCtr(ciphertext, password, nBits) {
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  if (!(nBits==128 || nBits==192 || nBits==256)) return '';  // standard allows 128/192/256 bit keys
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var nBytes = nBits/8;  // no bytes in key
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var pwBytes = new Array(nBytes);
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var pwKeySchedule = KeyExpansion(pwBytes);
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var key = Cipher(pwBytes, pwKeySchedule);
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  key = key.concat(key.slice(0, nBytes-16));  // key is now 16/24/32 bytes long
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var keySchedule = KeyExpansion(key);
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ciphertext = ciphertext.split('-');  // split ciphertext into array of block-length strings
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // recover nonce from 1st element of ciphertext
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var blockSize = 16;  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var counterBlock = new Array(blockSize);
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var ctrTxt = unescCtrlChars(ciphertext[0]);
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<8; i++) counterBlock[i] = ctrTxt.charCodeAt(i);
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var plaintext = new Array(ciphertext.length-1);
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var b=1; b<ciphertext.length; b++) {
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var c=0; c<4; c++) counterBlock[15-c] = ((b-1) >>> c*8) & 0xff;
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var c=0; c<4; c++) counterBlock[15-c-4] = ((b/0x100000000-1) >>> c*8) & 0xff;
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var cipherCntr = Cipher(counterBlock, keySchedule);  // encrypt counter block
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ciphertext[b] = unescCtrlChars(ciphertext[b]);
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    var pt = '';
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (var i=0; i<ciphertext[b].length; i++) {
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      // -- xor plaintext with ciphered counter byte-by-byte --
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      var ciphertextByte = ciphertext[b].charCodeAt(i);
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      var plaintextByte = ciphertextByte ^ cipherCntr[i];
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      pt += String.fromCharCode(plaintextByte);
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // pt is now plaintext for this block
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    plaintext[b-1] = pt;  // b-1 'cos no initial nonce block in plaintext
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  }
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return plaintext.join('');
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function escCtrlChars(str) {  // escape control chars which might cause problems handling ciphertext
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return str.replace(/[\0\t\n\v\f\r\xa0'"!-]/g, function(c) { return '!' + c.charCodeAt(0) + '!'; });
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}  // \xa0 to cater for bug in Firefox; include '-' to leave it free for use as a block marker
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function unescCtrlChars(str) {  // unescape potentially problematic control characters
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return str.replace(/!\d\d?\d?!/g, function(c) { return String.fromCharCode(c.slice(1,-1)); });
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * if escCtrlChars()/unescCtrlChars() still gives problems, use encodeBase64()/decodeBase64() instead
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function encodeBase64(str) {  // http://tools.ietf.org/html/rfc4648
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   str = encodeUTF8(str);  // encode multi-byte chars into UTF-8 for byte-array
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   do {  // pack three octets into four hexets
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      o1 = str.charCodeAt(i++);
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      o2 = str.charCodeAt(i++);
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      o3 = str.charCodeAt(i++);
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      bits = o1<<16 | o2<<8 | o3;
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      h1 = bits>>18 & 0x3f;
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      h2 = bits>>12 & 0x3f;
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      h3 = bits>>6 & 0x3f;
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      h4 = bits & 0x3f;
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      // end of string? index to '=' in b64
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      if (isNaN(o3)) h4 = 64;
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      if (isNaN(o2)) h3 = 64;
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      // use hexets to index into b64, and append result to encoded string
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   } while (i < str.length);
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   return enc;
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function decodeBase64(str) {
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   do {  // unpack four hexets into three octets using index points in b64
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      h1 = b64.indexOf(str.charAt(i++));
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      h2 = b64.indexOf(str.charAt(i++));
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      h3 = b64.indexOf(str.charAt(i++));
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      h4 = b64.indexOf(str.charAt(i++));
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      bits = h1<<18 | h2<<12 | h3<<6 | h4;
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      o1 = bits>>16 & 0xff;
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      o2 = bits>>8 & 0xff;
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      o3 = bits & 0xff;
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      if (h3 == 64)      enc += String.fromCharCode(o1);
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      else if (h4 == 64) enc += String.fromCharCode(o1, o2);
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      else               enc += String.fromCharCode(o1, o2, o3);
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   } while (i < str.length);
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)   return decodeUTF8(enc);  // decode UTF-8 byte-array back to Unicode
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function encodeUTF8(str) {  // encode multi-byte string into utf-8 multiple single-byte characters
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  str = str.replace(
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      /[\u0080-\u07ff]/g,  // U+0080 - U+07FF = 2-byte chars
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      function(c) {
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var cc = c.charCodeAt(0);
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); }
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    );
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  str = str.replace(
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      /[\u0800-\uffff]/g,  // U+0800 - U+FFFF = 3-byte chars
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      function(c) {
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var cc = c.charCodeAt(0);
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); }
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    );
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return str;
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function decodeUTF8(str) {  // decode utf-8 encoded string back into multi-byte characters
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  str = str.replace(
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      /[\u00c0-\u00df][\u0080-\u00bf]/g,                 // 2-byte chars
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      function(c) {
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f;
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return String.fromCharCode(cc); }
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    );
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  str = str.replace(
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      /[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g,  // 3-byte chars
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      function(c) {
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        var cc = (c.charCodeAt(0)&0x0f)<<12 | (c.charCodeAt(1)&0x3f<<6) | c.charCodeAt(2)&0x3f;
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return String.fromCharCode(cc); }
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    );
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return str;
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)function byteArrayToHexStr(b) {  // convert byte array to hex string for displaying test vectors
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  var s = '';
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  for (var i=0; i<b.length; i++) s += b[i].toString(16) + ' ';
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  return s;
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var plainText = "ROMEO: But, soft! what light through yonder window breaks?\n\
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)It is the east, and Juliet is the sun.\n\
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Arise, fair sun, and kill the envious moon,\n\
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Who is already sick and pale with grief,\n\
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)That thou her maid art far more fair than she:\n\
3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Be not her maid, since she is envious;\n\
3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Her vestal livery is but sick and green\n\
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)And none but fools do wear it; cast it off.\n\
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)It is my lady, O, it is my love!\n\
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)O, that she knew she were!\n\
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)She speaks yet she says nothing: what of that?\n\
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Her eye discourses; I will answer it.\n\
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)I am too bold, 'tis not to me she speaks:\n\
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Two of the fairest stars in all the heaven,\n\
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Having some business, do entreat her eyes\n\
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)To twinkle in their spheres till they return.\n\
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)What if her eyes were there, they in her head?\n\
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)The brightness of her cheek would shame those stars,\n\
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)As daylight doth a lamp; her eyes in heaven\n\
4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Would through the airy region stream so bright\n\
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)That birds would sing and think it were not night.\n\
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)See, how she leans her cheek upon her hand!\n\
4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)O, that I were a glove upon that hand,\n\
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)That I might touch that cheek!\n\
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)JULIET: Ay me!\n\
4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)ROMEO: She speaks:\n\
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)O, speak again, bright angel! for thou art\n\
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)As glorious to this night, being o'er my head\n\
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)As is a winged messenger of heaven\n\
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Unto the white-upturned wondering eyes\n\
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Of mortals that fall back to gaze on him\n\
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)When he bestrides the lazy-pacing clouds\n\
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)And sails upon the bosom of the air.";
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var password = "O Romeo, Romeo! wherefore art thou Romeo?";
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var cipherText = AESEncryptCtr(plainText, password, 256);
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)var decryptedText = AESDecryptCtr(cipherText, password, 256);
423