-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
18b65a8
commit d57ed6f
Showing
9 changed files
with
648 additions
and
1 deletion.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.idea/ | ||
node_modules/ |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
JSCryptor | ||
========= | ||
|
||
Javascript implementation of RNCryptor | ||
*Javascript implementation of RNCryptor* | ||
|
||
This implementation try to be compatible with Rob Napier's Objective-C implementation of RNCryptor, but currently it only supports decrypt of cbc mode through version 3. | ||
This code is based in the [PHP implementation of RNCryptor](https://github.com/RNCryptor/RNCryptor-php). Any pull request is welcomed. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
var RNCryptor = require('./index'); | ||
|
||
// Example taken from https://github.com/RNCryptor/RNCryptor-php/blob/master/examples/decrypt.php | ||
|
||
var password = 'myPassword'; | ||
var b64string = "AwHsr+ZD87myaoHm51kZX96u4hhaTuLkEsHwpCRpDywMO1Moz35wdS6OuDgq+SIAK6BOSVKQFSbX/GiFSKhWNy1q94JidKc8hs581JwVJBrEEoxDaMwYE+a+sZeirThbfpup9WZQgp3XuZsGuZPGvy6CvHWt08vsxFAn9tiHW9EFVtdSK7kAGzpnx53OUSt451Jpy6lXl1TKek8m64RT4XPr"; | ||
|
||
console.log(RNCryptor.Decrypt(b64string, password)); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
(function() { | ||
var RNCryptor = require('./lib/RNCryptor'); | ||
|
||
module.exports = RNCryptor; | ||
})(); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
(function() { | ||
var crypto = require('crypto'); | ||
var pbkdf2 = require('./pbkdf2_sha1'); | ||
var base64_decode = require('./base64_decode'); | ||
|
||
var MCrypt = require('mcrypt').MCrypt; | ||
|
||
var RNCryptor = {}; | ||
|
||
var _settings = {}; | ||
|
||
var _configureSettings = function(version) { | ||
var settings = { | ||
algorithm: 'rijndael-128', | ||
salt_length: 8, | ||
iv_length: 16, | ||
hmac: { | ||
length: 32 | ||
} | ||
}; | ||
|
||
switch(version) { | ||
case 3: | ||
settings.mode = 'cbc'; | ||
settings.options = 1; | ||
settings.hmac.includes_header = true; | ||
settings.hmac.algorithm = 'sha256'; | ||
settings.hmac.includes_padding = false; | ||
settings.truncatesMultibytePasswords = false; | ||
break; | ||
default: | ||
throw "Unsupported schema version " + version | ||
} | ||
|
||
_settings = settings; | ||
}; | ||
|
||
var _unpackEncryptedBase64Data = function(b64str) { | ||
var binary_data = base64_decode(b64str); | ||
|
||
var components = { | ||
headers: _parseHeaders(binary_data), | ||
hmac: binary_data.substr(-_settings.hmac.length) | ||
}; | ||
|
||
var header_length = components.headers.length; | ||
var cipher_text_length = binary_data.length - header_length - components.hmac.length; | ||
|
||
components.cipher_text = binary_data.substr(header_length, cipher_text_length); | ||
|
||
return components; | ||
}; | ||
|
||
var _parseHeaders = function(bin_data) { | ||
var offset = 0; | ||
|
||
var version_char = bin_data[0]; | ||
offset += version_char.length; | ||
|
||
_configureSettings(version_char.charCodeAt()); | ||
|
||
var options_char = bin_data[1]; | ||
offset += options_char.length; | ||
|
||
var encryption_salt = bin_data.substr(offset, _settings.salt_length); | ||
offset += encryption_salt.length; | ||
|
||
var hmac_salt = bin_data.substr(offset, _settings.salt_length); | ||
offset += hmac_salt.length; | ||
|
||
var iv = bin_data.substr(offset, _settings.iv_length); | ||
offset += iv.length; | ||
|
||
return { | ||
version: version_char, | ||
options: options_char, | ||
encryption_salt: encryption_salt, | ||
hmac_salt: hmac_salt, | ||
iv: iv, | ||
length: offset | ||
}; | ||
}; | ||
|
||
var _hmac_is_valid = function(components, password) { | ||
var hmac_key = _generate_key(components.headers.hmac_salt, password); | ||
return components.hmac == _generate_hmac(components, hmac_key); | ||
}; | ||
|
||
var _generate_key = function (salt, password) { | ||
return pbkdf2(password, salt, 10000, 32); | ||
}; | ||
|
||
var _generate_hmac = function(components, hmac_key) { | ||
var hmac_message = ''; | ||
|
||
if (_settings.hmac.includes_header) { | ||
hmac_message += components.headers.version; | ||
hmac_message += components.headers.options; | ||
hmac_message += components.headers.encryption_salt != null ? components.headers.encryption_salt : ''; | ||
hmac_message += components.headers.hmac_salt != null ? components.headers.hmac_salt : ''; | ||
hmac_message += components.headers.iv; | ||
} | ||
|
||
hmac_message += components.cipher_text; | ||
|
||
return _hmac_sha256(hmac_key, hmac_message); | ||
}; | ||
|
||
var _hmac_sha256 = function(password, salt) { | ||
var hmac = crypto.createHmac(_settings.hmac.algorithm, password); | ||
hmac.setEncoding('binary'); | ||
hmac.write(salt); | ||
hmac.end(); | ||
|
||
return hmac.read(); | ||
}; | ||
|
||
var _strip_pkcs7_padding = function(plain_text) { | ||
var pad_length = plain_text.charCodeAt(plain_text.length - 1); | ||
return plain_text.substr(0, plain_text.length - pad_length); | ||
}; | ||
|
||
RNCryptor.Decrypt = function(b64str, password) { | ||
var components = _unpackEncryptedBase64Data(b64str); | ||
|
||
if (!_hmac_is_valid(components, password)) { | ||
return; | ||
} | ||
|
||
var key = _generate_key(components.headers.encryption_salt, password); | ||
var decrypter = new MCrypt(_settings.algorithm, _settings.mode); | ||
decrypter.open(key, components.headers.iv); | ||
|
||
var padded_plain_text = decrypter.decrypt(new Buffer(components.cipher_text, 'binary')).toString(); | ||
return _strip_pkcs7_padding(padded_plain_text); | ||
}; | ||
|
||
module.exports = RNCryptor; | ||
})(); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
function base64_decode(data) { | ||
// discuss at: http://phpjs.org/functions/base64_decode/ | ||
// original by: Tyler Akins (http://rumkin.com) | ||
// improved by: Thunder.m | ||
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) | ||
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) | ||
// input by: Aman Gupta | ||
// input by: Brett Zamir (http://brett-zamir.me) | ||
// bugfixed by: Onno Marsman | ||
// bugfixed by: Pellentesque Malesuada | ||
// bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) | ||
// example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA=='); | ||
// returns 1: 'Kevin van Zonneveld' | ||
// example 2: base64_decode('YQ==='); | ||
// returns 2: 'a' | ||
// example 3: base64_decode('4pyTIMOgIGxhIG1vZGU='); | ||
// returns 3: '✓ à la mode' | ||
|
||
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; | ||
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, | ||
ac = 0, | ||
dec = '', | ||
tmp_arr = []; | ||
|
||
if (!data) { | ||
return data; | ||
} | ||
|
||
data += ''; | ||
|
||
do { | ||
// unpack four hexets into three octets using index points in b64 | ||
h1 = b64.indexOf(data.charAt(i++)); | ||
h2 = b64.indexOf(data.charAt(i++)); | ||
h3 = b64.indexOf(data.charAt(i++)); | ||
h4 = b64.indexOf(data.charAt(i++)); | ||
|
||
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; | ||
|
||
o1 = bits >> 16 & 0xff; | ||
o2 = bits >> 8 & 0xff; | ||
o3 = bits & 0xff; | ||
|
||
if (h3 == 64) { | ||
tmp_arr[ac++] = String.fromCharCode(o1); | ||
} else if (h4 == 64) { | ||
tmp_arr[ac++] = String.fromCharCode(o1, o2); | ||
} else { | ||
tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); | ||
} | ||
} while (i < data.length); | ||
|
||
dec = tmp_arr.join(''); | ||
|
||
return dec.replace(/\0+$/, ''); | ||
} | ||
|
||
module.exports = base64_decode; | ||
|
Oops, something went wrong.