Created
January 16, 2018 16:57
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
lovely, thanks a lot for making this 😄