-
-
Save mkvtvseries/cdf817b5a882eadda6b4012131c0c63b to your computer and use it in GitHub Desktop.
Sam7 js encryption
This file contains 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
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); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment