/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* AES implementation in JavaScript (c) Chris Veness 2005-2014 / MIT Licence */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* jshint node:true *//* global define */ 'use strict'; /** * AES (Rijndael cipher) encryption routines, * * Reference implementation of FIPS-197 http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf. * * @namespace */ var Aes = {}; /** * AES Cipher function: encrypt 'input' state with Rijndael algorithm [§5.1]; * applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage. * * @param {number[]} input - 16-byte (128-bit) input state array. * @param {number[][]} w - Key schedule as 2D byte-array (Nr+1 x Nb bytes). * @returns {number[]} Encrypted output state array. */ Aes.cipher = function(input, w) { var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES) var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4] for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i]; state = Aes.addRoundKey(state, w, 0, Nb); for (var round=1; round 6 && i%Nk == 4) { temp = Aes.subWord(temp); } // xor w[i] with w[i-1] and w[i-Nk] for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t]; } return w; }; /** * Apply SBox to state S [§5.1.1] * @private */ Aes.subBytes = function(s, Nb) { for (var r=0; r<4; r++) { for (var c=0; c>> i*8) & 0xff; for (var i=0; i<2; i++) counterBlock[i+2] = (nonceRnd >>> i*8) & 0xff; for (var i=0; i<4; i++) counterBlock[i+4] = (nonceSec >>> i*8) & 0xff; // and convert it to a string to go on the front of the ciphertext var ctrTxt = ''; for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]); // generate key schedule - an expansion of the key into distinct Key Rounds for each round var keySchedule = Aes.keyExpansion(key); var blockCount = Math.ceil(plaintext.length/blockSize); var ciphertxt = new Array(blockCount); // ciphertext as array of strings for (var b=0; b>> c*8) & 0xff; for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8); var cipherCntr = Aes.cipher(counterBlock, keySchedule); // -- encrypt counter block -- // block size is reduced on final block var blockLength = b>> c*8) & 0xff; for (var c=0; c<4; c++) counterBlock[15-c-4] = (((b+1)/0x100000000-1) >>> c*8) & 0xff; var cipherCntr = Aes.cipher(counterBlock, keySchedule); // encrypt counter block var plaintxtByte = new Array(ciphertext[b].length); for (var i=0; i