Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * Encrypt a text using AES encryption in Counter mode of operation
- *
- * Unicode multi-byte character safe
- *
- * @param plaintext Source text to be encrypted
- * @param password The password to use to generate a key
- * @param nBits Number of bits to be used in the key (128, 192, or 256)
- * @returns Encrypted text
- */
- public function encrypt(plaintext : String, password : String, nBits : int) : String //Done in LV
- {
- var blockSize : int = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
- if (!(nBits == BIT_KEY_128 || nBits == BIT_KEY_192 || nBits == BIT_KEY_256))
- {
- // standard allows 128/192/256 bit keys
- throw new Error("Must be a key mode of either 128, 192, 256 bits");
- }
- plaintext = Utf8.encode(plaintext);
- password = Utf8.encode(password);
- // use AES itself to encrypt password to get cipher key (using plain password as source for key
- // expansion) - gives us well encrypted key
- var nBytes : int = nBits / 8; // no bytes in key
- var pwBytes : Array = new Array(nBytes);
- for (var i : int = 0;i < nBytes;i++)
- {
- pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i);
- }
- var key : Array = cipher(pwBytes, keyExpansion(pwBytes)); // gives us 16-byte key
- key = key.concat(key.slice(0, nBytes - 16)); // expand key to 16/24/32 bytes long
- // initialise counter block (NIST SP800-38A ยงB.2): millisecond time-stamp for nonce in 1st 8 bytes,
- // block counter in 2nd 8 bytes
- var counterBlock : Array = new Array(blockSize);
- var nonce : int = 123456789;////DEBUG!!!(new Date()).getTime(); // timestamp: milliseconds since 1-Jan-1970
- var nonceSec : int = Math.floor(nonce / 1000);
- var nonceMs : int = nonce % 1000;
- // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes
- for (i = 0;i < 4;i++)
- {
- counterBlock[i] = (nonceSec >>> (i * 8)) & 0xff;
- }
- for (i = 0;i < 4;i++)
- {
- counterBlock[i + 4] = nonceMs & 0xff;
- }
- // and convert it to a string to go on the front of the ciphertext
- var ctrTxt : String = '';
- for (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 : Array = keyExpansion(key);
- var blockCount : int = Math.ceil(plaintext.length / blockSize);
- var ciphertxt : Array = new Array(blockCount); // ciphertext as array of strings
- for (var b : int = 0;b < blockCount;b++)
- {
- // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
- // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
- for (var c : int = 0;c < 4;c++)
- {
- counterBlock[15 - c] = (b >>> (c * 8)) & 0xff;
- }
- for (c = 0;c < 4;c++)
- {
- counterBlock[15 - c - 4] = (b / 0x100000000 >>> c * 8);
- }
- var cipherCntr : Array = cipher(counterBlock, keySchedule); // -- encrypt counter block --
- // block size is reduced on final block
- var blockLength : int = b < blockCount - 1 ? blockSize : (plaintext.length - 1) % blockSize + 1;
- var cipherChar : Array = new Array(blockLength);
- for (i = 0;i < blockLength;i++)
- {
- // -- xor plaintext with ciphered counter char-by-char --
- cipherChar[i] = cipherCntr[i] ^ plaintext.charCodeAt(b * blockSize + i);
- //trace("i=",i,"plaintext.charCodeAt(b * blockSize + i)",plaintext.charCodeAt(b * blockSize + i),"cipherChar[i]=",cipherChar[i]);
- cipherChar[i] = String.fromCharCode(cipherChar[i]);
- }
- ciphertxt[b] = cipherChar.join('');
- //trace(ciphertxt);
- }
- // Array.join is more efficient than repeated string concatenation in IE
- var ciphertext : String = ctrTxt + ciphertxt.join('');
- //trace("before 64 encode:",ciphertext);
- ciphertext = Base64.encode(ciphertext); // encode in base64
- //trace("after 64 encode:",ciphertext);
- //alert((new Date()) - t);
- return ciphertext;
- }
- /**
- * Decrypt a text encrypted by AES in counter mode of operation
- *
- * @param ciphertext Source text to be encrypted
- * @param password The password to use to generate a key
- * @param nBits Number of bits to be used in the key (128, 192, or 256)
- * @returns Decrypted text
- */
- public function decrypt(ciphertext : String, password : String, nBits : int) : String
- {
- var blockSize : int = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
- if (!(nBits == BIT_KEY_128 || nBits == BIT_KEY_192 || nBits == BIT_KEY_256)) {
- // standard allows 128/192/256 bit keys
- throw new Error("Must be a key mode of either 128, 192, 256 bits");
- }
- ciphertext = Base64.decode(ciphertext.split("n").join(""));
- password = Utf8.encode(password);
- //var t = new Date(); // timer
- // use AES to encrypt password (mirroring encrypt routine)
- var nBytes : int = nBits / 8; // no bytes in key
- var pwBytes : Array = new Array(nBytes);
- for (var i : int = 0;i < nBytes;i++)
- {
- pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i);
- }
- var key : Array = cipher(pwBytes, keyExpansion(pwBytes));
- key = key.concat(key.slice(0, nBytes - 16)); // expand key to 16/24/32 bytes long
- // recover nonce from 1st 8 bytes of ciphertext
- var counterBlock : Array = new Array(8);
- var ctrTxt : String = ciphertext.slice(0, 8);
- for (i = 0;i < 8;i++)
- {
- counterBlock[i] = ctrTxt.charCodeAt(i);
- }
- // generate key schedule
- var keySchedule : Array = keyExpansion(key);
- // separate ciphertext into blocks (skipping past initial 8 bytes)
- var nBlocks : int = Math.ceil((ciphertext.length - 8) / blockSize);
- var ct : Array = new Array(nBlocks);
- for (b = 0;b < nBlocks;b++)
- {
- ct[b] = ciphertext.slice(8 + b * blockSize, 8 + b * blockSize + blockSize);
- //trace("ct[b]=",ct[b],"blockSize=",blockSize,8 + b * blockSize, 8 + b * blockSize + blockSize);
- }
- //var temp:String=ct[1];
- // for (var i:int=0;i<temp.length;i++)
- // {
- // trace("ct[1]Byte Array:",temp.charCodeAt(i));
- // }
- var ciphertextArr : Array = ct; // ciphertext is now array of block-length strings
- // plaintext will get generated block-by-block into array of block-length strings
- var plaintxt : Array = new Array(ciphertextArr.length);
- for (var b : int = 0;b < nBlocks;b++)
- {
- // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
- for (var c : int = 0;c < 4;c++)
- {
- counterBlock[15 - c] = ((b) >>> c * 8) & 0xff;
- }
- for (c = 0;c < 4;c++)
- {
- counterBlock[15 - c - 4] = (((b + 1) / 0x100000000 - 1) >>> c * 8) & 0xff;
- }
- //trace(counterBlock);
- var cipherCntr : Array = cipher(counterBlock, keySchedule); // encrypt counter block
- //trace(cipherCntr);
- var plaintxtByte : Array = new Array(String(ciphertextArr[b]).length);
- for (i = 0;i < String(ciphertextArr[b]).length;i++)
- {
- // -- xor plaintxt with ciphered counter byte-by-byte --
- plaintxtByte[i] = cipherCntr[i] ^ String(ciphertextArr[b]).charCodeAt(i);
- //trace("i=",i,"plaintxtByte[i]=",plaintxtByte[i],"cipherCntr[i]=",cipherCntr[i],"String(ciphertextArr[b]).charCodeAt(i)=",String(ciphertextArr[b]).charCodeAt(i));
- //trace(plaintxtByte[i]);
- plaintxtByte[i] = String.fromCharCode(plaintxtByte[i]);
- }
- plaintxt[b] = plaintxtByte.join('');
- }
- // join array of blocks into single plaintext string
- var plaintext : String = plaintxt.join('');
- plaintext = Utf8.decode(plaintext); // decode from UTF8 back to Unicode multi-byte chars
- return plaintext;
- }
Add Comment
Please, Sign In to add comment