Roll leveldb 3f7758:803d69 (v1.17 -> v1.18)
[chromium-blink-merge.git] / chrome / test / data / dromaeo / tests / sunspider-crypto-aes.html
blob758a150f8032d69ab93bd86d98b8e6a7d980abc8
1 <html>
2 <head>
3 <script src="../htmlrunner.js"></script>
4 <script>
5 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
7 /*
8 * AES Cipher function: encrypt 'input' with Rijndael algorithm
10 * takes byte-array 'input' (16 bytes)
11 * 2D byte-array key schedule 'w' (Nr+1 x Nb bytes)
13 * applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage
15 * returns byte-array encrypted value (16 bytes)
17 function Cipher(input, w) { // main Cipher function [§5.1]
18 var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
19 var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
21 var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4]
22 for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i];
24 state = AddRoundKey(state, w, 0, Nb);
26 for (var round=1; round<Nr; round++) {
27 state = SubBytes(state, Nb);
28 state = ShiftRows(state, Nb);
29 state = MixColumns(state, Nb);
30 state = AddRoundKey(state, w, round, Nb);
33 state = SubBytes(state, Nb);
34 state = ShiftRows(state, Nb);
35 state = AddRoundKey(state, w, Nr, Nb);
37 var output = new Array(4*Nb); // convert state to 1-d array before returning [§3.4]
38 for (var i=0; i<4*Nb; i++) output[i] = state[i%4][Math.floor(i/4)];
39 return output;
43 function SubBytes(s, Nb) { // apply SBox to state S [§5.1.1]
44 for (var r=0; r<4; r++) {
45 for (var c=0; c<Nb; c++) s[r][c] = Sbox[s[r][c]];
47 return s;
51 function ShiftRows(s, Nb) { // shift row r of state S left by r bytes [§5.1.2]
52 var t = new Array(4);
53 for (var r=1; r<4; r++) {
54 for (var c=0; c<4; c++) t[c] = s[r][(c+r)%Nb]; // shift into temp copy
55 for (var c=0; c<4; c++) s[r][c] = t[c]; // and copy back
56 } // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
57 return s; // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
61 function MixColumns(s, Nb) { // combine bytes of each col of state S [§5.1.3]
62 for (var c=0; c<4; c++) {
63 var a = new Array(4); // 'a' is a copy of the current column from 's'
64 var b = new Array(4); // 'b' is a•{02} in GF(2^8)
65 for (var i=0; i<4; i++) {
66 a[i] = s[i][c];
67 b[i] = s[i][c]&0x80 ? s[i][c]<<1 ^ 0x011b : s[i][c]<<1;
69 // a[n] ^ b[n] is a•{03} in GF(2^8)
70 s[0][c] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3]; // 2*a0 + 3*a1 + a2 + a3
71 s[1][c] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3]; // a0 * 2*a1 + 3*a2 + a3
72 s[2][c] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3]; // a0 + a1 + 2*a2 + 3*a3
73 s[3][c] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3]; // 3*a0 + a1 + a2 + 2*a3
75 return s;
79 function AddRoundKey(state, w, rnd, Nb) { // xor Round Key into state S [§5.1.4]
80 for (var r=0; r<4; r++) {
81 for (var c=0; c<Nb; c++) state[r][c] ^= w[rnd*4+c][r];
83 return state;
87 function KeyExpansion(key) { // generate Key Schedule (byte-array Nr+1 x Nb) from Key [§5.2]
88 var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
89 var Nk = key.length/4 // key length (in words): 4/6/8 for 128/192/256-bit keys
90 var Nr = Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys
92 var w = new Array(Nb*(Nr+1));
93 var temp = new Array(4);
95 for (var i=0; i<Nk; i++) {
96 var r = [key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]];
97 w[i] = r;
100 for (var i=Nk; i<(Nb*(Nr+1)); i++) {
101 w[i] = new Array(4);
102 for (var t=0; t<4; t++) temp[t] = w[i-1][t];
103 if (i % Nk == 0) {
104 temp = SubWord(RotWord(temp));
105 for (var t=0; t<4; t++) temp[t] ^= Rcon[i/Nk][t];
106 } else if (Nk > 6 && i%Nk == 4) {
107 temp = SubWord(temp);
109 for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t];
112 return w;
115 function SubWord(w) { // apply SBox to 4-byte word w
116 for (var i=0; i<4; i++) w[i] = Sbox[w[i]];
117 return w;
120 function RotWord(w) { // rotate 4-byte word w left by one byte
121 w[4] = w[0];
122 for (var i=0; i<4; i++) w[i] = w[i+1];
123 return w;
127 // Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1]
128 var Sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
129 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
130 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
131 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
132 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
133 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
134 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
135 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
136 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
137 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
138 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
139 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
140 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
141 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
142 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
143 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16];
145 // Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2]
146 var Rcon = [ [0x00, 0x00, 0x00, 0x00],
147 [0x01, 0x00, 0x00, 0x00],
148 [0x02, 0x00, 0x00, 0x00],
149 [0x04, 0x00, 0x00, 0x00],
150 [0x08, 0x00, 0x00, 0x00],
151 [0x10, 0x00, 0x00, 0x00],
152 [0x20, 0x00, 0x00, 0x00],
153 [0x40, 0x00, 0x00, 0x00],
154 [0x80, 0x00, 0x00, 0x00],
155 [0x1b, 0x00, 0x00, 0x00],
156 [0x36, 0x00, 0x00, 0x00] ];
159 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
162 * Use AES to encrypt 'plaintext' with 'password' using 'nBits' key, in 'Counter' mode of operation
163 * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
164 * for each block
165 * - outputblock = cipher(counter, key)
166 * - cipherblock = plaintext xor outputblock
168 function AESEncryptCtr(plaintext, password, nBits) {
169 if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
171 // for this example script, generate the key by applying Cipher to 1st 16/24/32 chars of password;
172 // for real-world applications, a more secure approach would be to hash the password e.g. with SHA-1
173 var nBytes = nBits/8; // no bytes in key
174 var pwBytes = new Array(nBytes);
175 for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
176 var key = Cipher(pwBytes, KeyExpansion(pwBytes));
177 key = key.concat(key.slice(0, nBytes-16)); // key is now 16/24/32 bytes long
179 // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in 1st 8 bytes,
180 // block counter in 2nd 8 bytes
181 var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
182 var counterBlock = new Array(blockSize); // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
183 var nonce = (new Date()).getTime(); // milliseconds since 1-Jan-1970
185 // encode nonce in two stages to cater for JavaScript 32-bit limit on bitwise ops
186 for (var i=0; i<4; i++) counterBlock[i] = (nonce >>> i*8) & 0xff;
187 for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff;
189 // generate key schedule - an expansion of the key into distinct Key Rounds for each round
190 var keySchedule = KeyExpansion(key);
192 var blockCount = Math.ceil(plaintext.length/blockSize);
193 var ciphertext = new Array(blockCount); // ciphertext as array of strings
195 for (var b=0; b<blockCount; b++) {
196 // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
197 // again done in two stages for 32-bit ops
198 for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff;
199 for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8)
201 var cipherCntr = Cipher(counterBlock, keySchedule); // -- encrypt counter block --
203 // calculate length of final block:
204 var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1;
206 var ct = '';
207 for (var i=0; i<blockLength; i++) { // -- xor plaintext with ciphered counter byte-by-byte --
208 var plaintextByte = plaintext.charCodeAt(b*blockSize+i);
209 var cipherByte = plaintextByte ^ cipherCntr[i];
210 ct += String.fromCharCode(cipherByte);
212 // ct is now ciphertext for this block
214 ciphertext[b] = escCtrlChars(ct); // escape troublesome characters in ciphertext
217 // convert the nonce to a string to go on the front of the ciphertext
218 var ctrTxt = '';
219 for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]);
220 ctrTxt = escCtrlChars(ctrTxt);
222 // use '-' to separate blocks, use Array.join to concatenate arrays of strings for efficiency
223 return ctrTxt + '-' + ciphertext.join('-');
228 * Use AES to decrypt 'ciphertext' with 'password' using 'nBits' key, in Counter mode of operation
230 * for each block
231 * - outputblock = cipher(counter, key)
232 * - cipherblock = plaintext xor outputblock
234 function AESDecryptCtr(ciphertext, password, nBits) {
235 if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
237 var nBytes = nBits/8; // no bytes in key
238 var pwBytes = new Array(nBytes);
239 for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
240 var pwKeySchedule = KeyExpansion(pwBytes);
241 var key = Cipher(pwBytes, pwKeySchedule);
242 key = key.concat(key.slice(0, nBytes-16)); // key is now 16/24/32 bytes long
244 var keySchedule = KeyExpansion(key);
246 ciphertext = ciphertext.split('-'); // split ciphertext into array of block-length strings
248 // recover nonce from 1st element of ciphertext
249 var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
250 var counterBlock = new Array(blockSize);
251 var ctrTxt = unescCtrlChars(ciphertext[0]);
252 for (var i=0; i<8; i++) counterBlock[i] = ctrTxt.charCodeAt(i);
254 var plaintext = new Array(ciphertext.length-1);
256 for (var b=1; b<ciphertext.length; b++) {
257 // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
258 for (var c=0; c<4; c++) counterBlock[15-c] = ((b-1) >>> c*8) & 0xff;
259 for (var c=0; c<4; c++) counterBlock[15-c-4] = ((b/0x100000000-1) >>> c*8) & 0xff;
261 var cipherCntr = Cipher(counterBlock, keySchedule); // encrypt counter block
263 ciphertext[b] = unescCtrlChars(ciphertext[b]);
265 var pt = '';
266 for (var i=0; i<ciphertext[b].length; i++) {
267 // -- xor plaintext with ciphered counter byte-by-byte --
268 var ciphertextByte = ciphertext[b].charCodeAt(i);
269 var plaintextByte = ciphertextByte ^ cipherCntr[i];
270 pt += String.fromCharCode(plaintextByte);
272 // pt is now plaintext for this block
274 plaintext[b-1] = pt; // b-1 'cos no initial nonce block in plaintext
277 return plaintext.join('');
280 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
282 function escCtrlChars(str) { // escape control chars which might cause problems handling ciphertext
283 return str.replace(/[\0\t\n\v\f\r\xa0'"!-]/g, function(c) { return '!' + c.charCodeAt(0) + '!'; });
284 } // \xa0 to cater for bug in Firefox; include '-' to leave it free for use as a block marker
286 function unescCtrlChars(str) { // unescape potentially problematic control characters
287 return str.replace(/!\d\d?\d?!/g, function(c) { return String.fromCharCode(c.slice(1,-1)); });
289 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
292 * if escCtrlChars()/unescCtrlChars() still gives problems, use encodeBase64()/decodeBase64() instead
294 var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
296 function encodeBase64(str) { // http://tools.ietf.org/html/rfc4648
297 var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
299 str = encodeUTF8(str); // encode multi-byte chars into UTF-8 for byte-array
301 do { // pack three octets into four hexets
302 o1 = str.charCodeAt(i++);
303 o2 = str.charCodeAt(i++);
304 o3 = str.charCodeAt(i++);
306 bits = o1<<16 | o2<<8 | o3;
308 h1 = bits>>18 & 0x3f;
309 h2 = bits>>12 & 0x3f;
310 h3 = bits>>6 & 0x3f;
311 h4 = bits & 0x3f;
313 // end of string? index to '=' in b64
314 if (isNaN(o3)) h4 = 64;
315 if (isNaN(o2)) h3 = 64;
317 // use hexets to index into b64, and append result to encoded string
318 enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
319 } while (i < str.length);
321 return enc;
324 function decodeBase64(str) {
325 var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
327 do { // unpack four hexets into three octets using index points in b64
328 h1 = b64.indexOf(str.charAt(i++));
329 h2 = b64.indexOf(str.charAt(i++));
330 h3 = b64.indexOf(str.charAt(i++));
331 h4 = b64.indexOf(str.charAt(i++));
333 bits = h1<<18 | h2<<12 | h3<<6 | h4;
335 o1 = bits>>16 & 0xff;
336 o2 = bits>>8 & 0xff;
337 o3 = bits & 0xff;
339 if (h3 == 64) enc += String.fromCharCode(o1);
340 else if (h4 == 64) enc += String.fromCharCode(o1, o2);
341 else enc += String.fromCharCode(o1, o2, o3);
342 } while (i < str.length);
344 return decodeUTF8(enc); // decode UTF-8 byte-array back to Unicode
347 function encodeUTF8(str) { // encode multi-byte string into utf-8 multiple single-byte characters
348 str = str.replace(
349 /[\u0080-\u07ff]/g, // U+0080 - U+07FF = 2-byte chars
350 function(c) {
351 var cc = c.charCodeAt(0);
352 return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); }
354 str = str.replace(
355 /[\u0800-\uffff]/g, // U+0800 - U+FFFF = 3-byte chars
356 function(c) {
357 var cc = c.charCodeAt(0);
358 return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); }
360 return str;
363 function decodeUTF8(str) { // decode utf-8 encoded string back into multi-byte characters
364 str = str.replace(
365 /[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
366 function(c) {
367 var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f;
368 return String.fromCharCode(cc); }
370 str = str.replace(
371 /[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
372 function(c) {
373 var cc = (c.charCodeAt(0)&0x0f)<<12 | (c.charCodeAt(1)&0x3f<<6) | c.charCodeAt(2)&0x3f;
374 return String.fromCharCode(cc); }
376 return str;
380 function byteArrayToHexStr(b) { // convert byte array to hex string for displaying test vectors
381 var s = '';
382 for (var i=0; i<b.length; i++) s += b[i].toString(16) + ' ';
383 return s;
386 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
389 var plainText = "ROMEO: But, soft! what light through yonder window breaks?\n\
390 It is the east, and Juliet is the sun.\n\
391 Arise, fair sun, and kill the envious moon,\n\
392 Who is already sick and pale with grief,\n\
393 That thou her maid art far more fair than she:\n\
394 Be not her maid, since she is envious;\n\
395 Her vestal livery is but sick and green\n\
396 And none but fools do wear it; cast it off.\n\
397 It is my lady, O, it is my love!\n\
398 O, that she knew she were!\n\
399 She speaks yet she says nothing: what of that?\n\
400 Her eye discourses; I will answer it.\n\
401 I am too bold, 'tis not to me she speaks:\n\
402 Two of the fairest stars in all the heaven,\n\
403 Having some business, do entreat her eyes\n\
404 To twinkle in their spheres till they return.\n\
405 What if her eyes were there, they in her head?\n\
406 The brightness of her cheek would shame those stars,\n\
407 As daylight doth a lamp; her eyes in heaven\n\
408 Would through the airy region stream so bright\n\
409 That birds would sing and think it were not night.\n\
410 See, how she leans her cheek upon her hand!\n\
411 O, that I were a glove upon that hand,\n\
412 That I might touch that cheek!\n\
413 JULIET: Ay me!\n\
414 ROMEO: She speaks:\n\
415 O, speak again, bright angel! for thou art\n\
416 As glorious to this night, being o'er my head\n\
417 As is a winged messenger of heaven\n\
418 Unto the white-upturned wondering eyes\n\
419 Of mortals that fall back to gaze on him\n\
420 When he bestrides the lazy-pacing clouds\n\
421 And sails upon the bosom of the air.";
423 var password = "O Romeo, Romeo! wherefore art thou Romeo?";
424 var cipherText, decryptedText;
426 window.onload = function(){ startTest("sunspider-crypto-aes", 'e80e78f2');
428 test("AES Encrypt", function(){
429 cipherText = AESEncryptCtr(plainText, password, 256);
432 test("AES Decrypt", function(){
433 decryptedText = AESDecryptCtr(cipherText, password, 256);
435 if ( decryptedText !== plainText )
436 throw "Decryption failed.";
439 endTest(); };
440 </script>
441 </head>
442 <body></body>
443 </html>