JavaScript AES Client-side Encryption and Decryption
We can use JavaScript encryption in the Web browser using a Javascript integration from https://www.fourmilab.ch. In this example, we will use either a pre-generated key or a random one, and use AES (Rijndael) encryption
The code uses (from https://www.fourmilab.ch):
var ct = rijndaelEncrypt(header + plaintext, key, "CBC");
The full code is:
function Encrypt_text() { var v, i; var prefix = "##### Encrypted:\n", suffix = "##### End encrypted message\n"; if (document.key.text.value.length == 0) { alert("Please specify a key with which to encrypt the message."); return; } if (document.plain.text.value.length == 0) { alert("No plain text to encrypt! Please enter or paste plain text in the field above."); return; } document.cipher.text.value = ""; setKey(); addEntropyTime(); prng = new AESprng(keyFromEntropy()); var plaintext = encode_utf8(document.plain.text.value); // Compute MD5 sum of message text and add to header md5_init(); for (i = 0; i < plaintext.length; i++) { md5_update(plaintext.charCodeAt(i)); } md5_finish(); var header = ""; for (i = 0; i < digestBits.length; i++) { header += String.fromCharCode(digestBits[i]); } // Add message length in bytes to header i = plaintext.length; header += String.fromCharCode(i >>> 24); header += String.fromCharCode(i >>> 16); header += String.fromCharCode(i >>> 8); header += String.fromCharCode(i & 0xFF); /* The format of the actual message passed to rijndaelEncrypt is: Bytes Content 0-15 MD5 signature of plaintext 16-19 Length of plaintext, big-endian order 20-end Plaintext Note that this message will be padded with zero bytes to an integral number of AES blocks (blockSizeInBits / 8). This does not include the initial vector for CBC encryption, which is added internally by rijndaelEncrypt. */ var ct = rijndaelEncrypt(header + plaintext, key, "CBC"); if (document.plain.encoding[0].checked) { v = armour_codegroup(ct); } else if (document.plain.encoding[1].checked) { v = armour_hex(ct); } else if (document.plain.encoding[2].checked) { v = armour_base64(ct); } document.cipher.text.value = prefix + v + suffix; delete prng; }
The code used to decrypt is then:
function Decrypt_text() { if (document.key.text.value.length == 0) { alert("Please specify a key with which to decrypt the message."); return; } if (document.cipher.text.value.length == 0) { alert("No cipher text to decrypt! Please enter or paste cipher text in the field above."); return; } setKey(); var ct = new Array(), kt; kt = determineArmourType(document.cipher.text.value); if (kt == 0) { ct = disarm_codegroup(document.cipher.text.value); } else if (kt == 1) { ct = disarm_hex(document.cipher.text.value); } else if (kt == 2) { ct = disarm_base64(document.cipher.text.value); } var result = rijndaelDecrypt(ct, key, "CBC"); var header = result.slice(0, 20); result = result.slice(20); var dl = (header[16] << 24) | (header[17] << 16) | (header[18] << 8) | header[19]; if ((dl < 0) || (dl > result.length)) { alert("Message (length " + result.length + ") truncated. " + dl + " characters expected."); // Try to sauve qui peut by setting length to entire message dl = result.length; } var i, plaintext = ""; md5_init(); for (i = 0; i < dl; i++) { plaintext += String.fromCharCode(result[i]); md5_update(result[i]); } md5_finish(); for (i = 0; i < digestBits.length; i++) { if (digestBits[i] != header[i]) { alert("Message corrupted. Checksum of decrypted message does not match."); break; } } document.plain2.text.value = decode_utf8(plaintext); }
Ref: https://www.fourmilab.ch/javascrypt