Skip to content

Instantly share code, notes, and snippets.

@9876691
Created August 11, 2011 14:53
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save 9876691/1139867 to your computer and use it in GitHub Desktop.
Save 9876691/1139867 to your computer and use it in GitHub Desktop.
Sam7 js encryption
function pbkdf_aes_key(aes, pObj) {
var pidcrypt = aes.pidcrypt;
var retObj = {};
var count = 1;
var miter = 3;
if(!pObj) pObj = {};
if(pObj.rounds) {
count = pObj.rounds;
}
if(!pObj.salt) {
pObj.salt = pidcrypt.getRandomBytes(8);
pObj.salt = pidCryptUtil.convertToHex(pidCryptUtil.byteArray2String(pObj.salt));
pidcrypt.setParams({salt: pObj.salt});
}
var pass = pObj.password;
if (typeof pass != "string") {
pass = pidCryptUtil.byteArray2String(pass);
}
var data00 = pass + pidCryptUtil.convertFromHex(pObj.salt);
var hashtarget = '';
var result = '';
var keymaterial = '';
var loop = 0;
keymaterial[loop++] = data00;
for(var j=0; j<miter; j++){
result = result + data00;
result = pidCryptUtil.toByteArray(result);
for(var c=0; c<count; c++){
result = Crypto.SHA256(result, {asBytes: true});
}
result = pidCryptUtil.byteArray2String(result);
keymaterial += result;
}
switch(pObj.bits){
case 128://128 bit
retObj.key = pidCryptUtil.convertToHex(keymaterial.slice(0, 16));
retObj.iv = pidCryptUtil.convertToHex(keymaterial.slice(16, 32));
break;
case 192://192 bit
retObj.key = pidCryptUtil.convertToHex(keymaterial.slice(0, 24));
retObj.iv = pidCryptUtil.convertToHex(keymaterial.slice(24, 40));
break;
case 256://256 bit
retObj.key = pidCryptUtil.convertToHex(keymaterial.slice(0, 32));
retObj.iv = pidCryptUtil.convertToHex(keymaterial.slice(32, 48));
break;
default:
pidcrypt.appendError('get_aes_key: Sorry, only 128, 192 and 256 bits are supported.\nBits('+typeof(pObj.bits)+') = '+pObj.bits);
}
return retObj;
}
function aes_encrypt_raw_nopadding(aescbc, byteArray) {
var pidcrypt = aescbc.pidcrypt;
var aes = aescbc.aes;
var p = pidcrypt.getParams(); //get parameters for operation set by init
if(!byteArray)
byteArray = p.encryptIn;
pidcrypt.setParams({encryptIn: byteArray});
if(!p.dataIn) pidcrypt.setParams({dataIn:byteArray});
var iv = pidCryptUtil.convertFromHex(p.iv);
var charDiv = (byteArray.length % p.blockSize);
if (charDiv > 0) {
charDiv = p.blockSize - charDiv;
}
for(var c=0;c<charDiv;c++) byteArray[byteArray.length] = charDiv;
var nBytes = Math.floor(p.nBits/8); // nr of bytes in key
var keyBytes = new Array(nBytes);
var key = pidCryptUtil.convertFromHex(p.key);
for (var i=0; i<nBytes; i++) {
keyBytes[i] = isNaN(key.charCodeAt(i)) ? 0 : key.charCodeAt(i);
}
// generate key schedule
var keySchedule = aes.expandKey(keyBytes);
var blockCount = Math.ceil(byteArray.length/p.blockSize);
var ciphertxt = new Array(blockCount); // ciphertext as array of strings
var textBlock = [];
var state = pidCryptUtil.toByteArray(iv);
for (var b=0; b<blockCount; b++) {
// XOR last block and next data block, then encrypt that
textBlock = byteArray.slice(b*p.blockSize, b*p.blockSize+p.blockSize);
state = aes.xOr_Array(state, textBlock);
state = aes.encrypt(state.slice(), keySchedule); // -- encrypt block --
ciphertxt[b] = pidCryptUtil.byteArray2String(state);
}
var ciphertext = ciphertxt.join('');
pidcrypt.setParams({dataOut:ciphertext, encryptOut:ciphertext});
if(!pidcrypt.isDebug() && pidcrypt.clear) pidcrypt.clearParams();
return ciphertext || '';
}
function aes_decrypt_raw_nopadding(aescbc, byteArray) {
var aes = aescbc.aes;
var pidcrypt = aescbc.pidcrypt;
var p = pidcrypt.getParams(); //get parameters for operation set by init
if(!byteArray)
byteArray = p.decryptIn;
pidcrypt.setParams({decryptIn: byteArray});
if(!p.dataIn) pidcrypt.setParams({dataIn:byteArray});
if((p.iv.length/2)<p.blockSize)
return pidcrypt.appendError('pidCrypt.AES.CBC.decrypt: Sorry, can not decrypt without complete set of parameters.\n Length of key,iv:'+p.key.length+','+p.iv.length);
var iv = pidCryptUtil.convertFromHex(p.iv);
if(byteArray.length%p.blockSize != 0)
return pidcrypt.appendError('pidCrypt.AES.CBC.decrypt: Sorry, the encrypted text has the wrong length for aes-cbc mode\n Length of ciphertext:'+byteArray.length+byteArray.length%p.blockSize);
var nBytes = Math.floor(p.nBits/8); // nr of bytes in key
var keyBytes = new Array(nBytes);
var key = pidCryptUtil.convertFromHex(p.key);
for (var i=0; i<nBytes; i++) {
keyBytes[i] = isNaN(key.charCodeAt(i)) ? 0 : key.charCodeAt(i);
}
// generate key schedule
var keySchedule = aes.expandKey(keyBytes);
// separate byteArray into blocks
var nBlocks = Math.ceil((byteArray.length) / p.blockSize);
// plaintext will get generated block-by-block into array of block-length strings
var plaintxt = new Array(nBlocks.length);
var state = pidCryptUtil.toByteArray(iv);
var ciphertextBlock = [];
var dec_state = [];
for (var b=0; b<nBlocks; b++) {
ciphertextBlock = byteArray.slice(b*p.blockSize, b*p.blockSize+p.blockSize);
dec_state = aes.decrypt(ciphertextBlock, keySchedule); // decrypt ciphertext block
plaintxt[b] = pidCryptUtil.byteArray2String(aes.xOr_Array(state, dec_state));
state = ciphertextBlock.slice(); //save old ciphertext for next round
}
// join array of blocks into single plaintext string and return it
var plaintext = plaintxt.join('');
pidcrypt.setParams({dataOut: plaintext,decryptOut: plaintext});
//remove all parameters from enviroment for more security is debug off
if(!pidcrypt.isDebug() && pidcrypt.clear) pidcrypt.clearParams();
return plaintext || '';
}
function b58_encode_check(value_bytes) {
var checksum = Crypto.SHA256(Crypto.SHA256(value_bytes, {asBytes: true}),
{asBytes: true});
value_bytes = value_bytes.concat(checksum.slice(0, 4));
return Bitcoin.Base58.encode(value_bytes);
}
function b58_decode_check(value_b58) {
var value_bytes = Bitcoin.Base58.decode(value_b58);
if (value_bytes.length < 5) {
return [];
}
var checksum = Crypto.SHA256(
Crypto.SHA256(value_bytes.slice(0, value_bytes.length - 4),
{asBytes: true}),
{asBytes: true});
if ((value_bytes[value_bytes.length - 4] != checksum[0]) ||
(value_bytes[value_bytes.length - 3] != checksum[1]) ||
(value_bytes[value_bytes.length - 2] != checksum[2]) ||
(value_bytes[value_bytes.length - 1] != checksum[3])) {
return [];
}
return value_bytes.slice(0, value_bytes.length - 4);
}
function protected_privkey_encode(privkey_b58, password) {
var privkey = b58_decode_check(privkey_b58);
if (!privkey || (privkey.length != 33) || (privkey[0] != 128))
return "Invalid private key";
password = pidCryptUtil.encodeUTF8(password) + "\0";
var pbkdfParam = {password:password, rounds:4096, bits:256};
var aes = new pidCrypt.AES.CBC();
// Use four bytes of salt instead of the PBKDF recommended 8
salt_bytes = aes.pidcrypt.getRandomBytes(4).concat([0x7f,0x7f,0x7f,0x7f]);
pbkdfParam.salt = pidCryptUtil.convertToHex(
pidCryptUtil.byteArray2String(salt_bytes));
var params = pbkdf_aes_key(aes, pbkdfParam);
aes.pidcrypt.setParams(params);
aes.aes.init();
var salt_bytes = pidCryptUtil.toByteArray(
pidCryptUtil.convertFromHex(pbkdfParam.salt));
var protected_privkey = aes_encrypt_raw_nopadding(aes, privkey.slice(1));
protected_privkey = pidCryptUtil.toByteArray(protected_privkey);
var check_subject = privkey.slice(1).concat(salt_bytes);
var plain_checksum = Crypto.SHA256(
Crypto.SHA256(check_subject, {asBytes: true}),
{asBytes: true});
var protkey = [136];
protkey = protkey.concat(protected_privkey);
protkey = protkey.concat(plain_checksum.slice(0, 8));
protkey = protkey.concat(salt_bytes.slice(0, 4));
return b58_encode_check(protkey);
}
function protected_privkey_decode(protkey_b58, password) {
var protkey = b58_decode_check(protkey_b58);
if (!protkey || (protkey.length != 45) || (protkey[0] != 136))
return "Invalid protected private key";
password = pidCryptUtil.encodeUTF8(password) + "\0";
var protected_privkey = protkey.slice(1, 33);
var expect_checksum = protkey.slice(33, 41);
var salt_bytes = protkey.slice(41, 45).concat([0x7f,0x7f,0x7f,0x7f]);
var pbkdfParam = {password:password, rounds:4096, bits:256};
pbkdfParam.salt = pidCryptUtil.convertToHex(
pidCryptUtil.byteArray2String(salt_bytes));
var aes = new pidCrypt.AES.CBC();
var params = pbkdf_aes_key(aes, pbkdfParam);
aes.pidcrypt.setParams(params);
aes.aes.init();
var privkey_str = aes_decrypt_raw_nopadding(aes, protected_privkey);
privkey = [128].concat(pidCryptUtil.toByteArray(privkey_str));
var check_subject = privkey.slice(1).concat(salt_bytes);
var plain_checksum = Crypto.SHA256(
Crypto.SHA256(check_subject, {asBytes: true}),
{asBytes: true});
var i;
for (i = 0; i < 8; i++) {
if (plain_checksum[i] != expect_checksum[i])
return "Invalid password";
}
return b58_encode_check(privkey);
}
function do_form_protect_key() {
var privkey_b58 = document.getElementById("privkey-in").value;
var password = document.getElementById("prot-password-in").value;
document.getElementById("protkey-out").innerHTML =
protected_privkey_encode(privkey_b58, password);
}
function do_form_unprotect_key() {
var privkey_b58 = document.getElementById("protkey-in").value;
var password = document.getElementById("unprot-password-in").value;
document.getElementById("privkey-out").innerHTML =
protected_privkey_decode(privkey_b58, password);
}
@mkvtvseries
Copy link

Hello, How to run on browser? Please help

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