Skip to content

Instantly share code, notes, and snippets.

@guillaumef
Created January 16, 2018 16:57
Show Gist options
  • Save guillaumef/2944e9e9a567cb308639973c90353ace to your computer and use it in GitHub Desktop.
Save guillaumef/2944e9e9a567cb308639973c90353ace to your computer and use it in GitHub Desktop.
JS - AES 256 crypt/decrypt compatible with 'openssl enc' format - depends on sjcl for SHA256 Raw
/*
* AES 256 crypt/decrypt compatible with 'openssl enc' format
* Depends on sjcl for SHA256: https://bitwiseshiftleft.github.io/sjcl/
*
* Usage:
<script type="text/javascript" src="sjcl.js"></script>
<script type="text/javascript" src="this_file.js"></script>
*
* Author: Zorro Aka Diego de la Vega
*
*/
function hexToBin(hex)
{
var bytes = new Array(hex.length / 2);
var i = 0;
for(; i < hex.length; i += 2) {
bytes[i / 2] = (parseInt(hex.substr(i, 2), 16));
}
return bytes;
}
function binToHex(bin)
{
var hex = "";
bin.forEach(function(b) {
hex += ('0' + (b & 0xFF).toString(16)).slice(-2);
});
return hex;
}
// EVP_BytesToKey (With Stanford Javascript Crypto Library For SHA256)
// (GitHub = https://github.com/bitwiseshiftleft/sjcl/)
function EVP_BytesToKey(salt, passphrase, nkey, niv)
{
var md_buf = null;
var key = [];
var iv = [];
var addmd = 0;
var i = 0;
while(key.length < nkey || iv.length < niv) {
var sha = new sjcl.hash.sha256();
if (addmd) {
sha.update(md_buf);
} else {
addmd++;
}
sha.update(passphrase);
sha.update(salt);
md_buf = sha.finalize();
var md_buf2 = sjcl.codec.hex.fromBits(md_buf);
var md_buf3 = hexToBin(md_buf2);
md_buf2 = hexToBin(md_buf2);
if (key.length < nkey) {
var pos = nkey - key.length;
for(i = 0; i < pos; i++) {
key.push(md_buf2[i]);
}
md_buf2 = [];
for(; i < md_buf3.length; i++) {
md_buf2.push(md_buf3[i]);
}
}
if (iv.length < niv) {
var diff = niv - iv.length;
for(i = 0; i < diff; i++) {
if (i >= md_buf2.length) {
break;
}
iv.push(md_buf2[i]);
}
}
}
return [key, iv];
}
// AES-CBC Encrypt Function (With window.crypto.subtle.encrypt Function)
// (Doc = https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt)
const encryptText = async (plainText, password, iv) => {
const ptUtf8 = new TextEncoder().encode(plainText);
const pwHash = new Uint8Array(password).buffer;
const myiv = new Uint8Array(iv);
const alg = { name: "AES-CBC", iv: myiv };
const key = await crypto.subtle.importKey('raw', pwHash, alg, false, ['encrypt']);
return crypto.subtle.encrypt(alg, key, ptUtf8);
}
// AES-CBC Decrypt Function (With window.crypto.subtle.decrypt Function)
// (Doc = https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt)
const decryptText = async (encBuffer, password, iv) => {
const pwHash = new Uint8Array(password).buffer;
const myiv = new Uint8Array(iv);
const alg = { name: "AES-CBC", iv: myiv };
const key = await crypto.subtle.importKey('raw', pwHash, alg, false, ['decrypt']);
return crypto.subtle.decrypt(alg, key, encBuffer);
}
// Set Values
var salt = "\x01\x02\x03\x04\x05\x06\x07\x08"; // TODO Random
var pass = "et";
var data = "toto";
// Get Key/IV
var aKeyIV = EVP_BytesToKey(salt, pass, 32, 16);
console.log("KEY = ", binToHex(aKeyIV[0]))
console.log("IV = ", binToHex(aKeyIV[1]));
// Pad Data
var pad = 16 - data.length % 16;
var i = 0;
for(; i < pad; i++) {
data += String.fromCharCode(pad);
}
// Encrypt/Decrypt Data
(async () => {
var enc = await encryptText(data, aKeyIV[0], aKeyIV[1]);
var ret = new Uint8Array(enc.slice(0, enc.byteLength - 16)); // Remove 16Bytes Because Encrypt '\0'
var txt = "Salted__" + salt + String.fromCharCode.apply(null, ret);
console.log("ENC = ", btoa(txt));
// Decrypt (TODO Base64 Decode, Get Salt...)
var dec = await decryptText(enc, aKeyIV[0], aKeyIV[1]);
ret = String.fromCharCode.apply(null, new Uint8Array(dec));
// Remove Padding
var i = 0;
for(i = ret.length; i >= 0; i--) {
if (ret.charCodeAt(i) > 16) {
break;
}
}
if (i > 0) {
txt = ret.substr(0, i + 1);
} else {
txt = "";
}
console.log("DEC = ", txt);
})();
@epsilon-0
Copy link

lovely, thanks a lot for making this 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment