Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Module to [secure] dump/load JSON objs to/from string.
- Loading branch information
Showing
4 changed files
with
137 additions
and
0 deletions.
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 |
---|---|---|
@@ -1,3 +1,6 @@ | ||
[submodule "vendor/yabble"] | ||
path = vendor/yabble | ||
url = git://github.com/virtuo/yabble.git | ||
[submodule "vendor/node-base64"] | ||
path = vendor/node-base64 | ||
url = git://github.com/tdebarochez/node-base64.js.git |
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,81 @@ | ||
|
||
require.paths.unshift(__dirname + '/../../vendor/node-base64') | ||
|
||
var crypto = require('crypto') | ||
|
||
, base64 = require('base64') | ||
|
||
, random_str = require('nodetk/random_str') | ||
; | ||
|
||
|
||
exports.dump_str = function(obj) { | ||
/* Returns dump of the given JSON obj as a str. | ||
* There is no encryption, and it might not be safe. | ||
* Might throw an error. | ||
* | ||
* Arguments: | ||
* - obj: JSON obj. | ||
* | ||
*/ | ||
return base64.encode(JSON.stringify(obj)); | ||
}; | ||
|
||
|
||
exports.load_str = function(str) { | ||
/* Returns obj loaded from given string. | ||
* Might throw an error. | ||
* | ||
* Arguments: | ||
* - str: string representation of obj to load. | ||
* | ||
*/ | ||
return JSON.parse(base64.decode(str)); | ||
}; | ||
|
||
|
||
var sign_str = function(str, key) { | ||
/* Return base64 signed sha1 hash of str using key */ | ||
var hmac = crypto.createHmac('sha1', key); | ||
hmac.update(str); | ||
return hmac.digest('base64'); | ||
}; | ||
|
||
|
||
var CYPHER = 'aes256'; | ||
var CODE_ENCODING = "hex"; | ||
var DATA_ENCODING = "utf8"; | ||
|
||
exports.dump_secure_str = function(obj, encrypt_key, validate_key) { | ||
/* Return str representing the given obj. It is signed and encrypted using the | ||
* given keys. | ||
*/ | ||
// TODO XXX: check the validity of the process | ||
// Do we need some timestamp to invalidate too old data? | ||
var nonce_check = random_str.randomString(48); // 8 chars | ||
var nonce_crypt = random_str.randomString(48); // 8 chars | ||
var cypher = crypto.createCipher(CYPHER, encrypt_key + nonce_crypt); | ||
var data = JSON.stringify(obj); | ||
var res = cypher.update(nonce_check, DATA_ENCODING, CODE_ENCODING); | ||
res += cypher.update(data, DATA_ENCODING, CODE_ENCODING); | ||
res += cypher.final(CODE_ENCODING); | ||
var digest = sign_str(data, validate_key + nonce_check); | ||
return digest + nonce_crypt + res; | ||
}; | ||
|
||
exports.load_secure_str = function(str, encrypt_key, validate_key) { | ||
/* Given a string resulting from dump_secure_str, load corresponding JSON. | ||
*/ | ||
var expected_digest = str.substring(0, 28); | ||
var nonce_crypt = str.substring(28, 36); | ||
var encrypted_data = str.substring(36, str.length); | ||
var decypher = crypto.createDecipher(CYPHER, encrypt_key + nonce_crypt); | ||
var data = decypher.update(encrypted_data, CODE_ENCODING, DATA_ENCODING); | ||
data += decypher.final(DATA_ENCODING); | ||
var nonce_check = data.substring(0, 8); | ||
data = data.substring(8, data.length); | ||
var digest = sign_str(data, validate_key + nonce_check); | ||
if(digest != expected_digest) throw new Error("Bad digest"); | ||
return JSON.parse(data); | ||
}; | ||
|
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,52 @@ | ||
var assert = require('nodetk/testing/custom_assert'); | ||
var serializer = require('nodetk/serializer'); | ||
|
||
|
||
var VALS = [ | ||
-4 | ||
, 0 | ||
, 42 | ||
, null | ||
, true | ||
, false | ||
, [] | ||
, ["a",2] | ||
, {} | ||
, '' | ||
, 12554322 | ||
, "short str" | ||
, "Some long string that would take a lot of place !!!!" | ||
, {name: "Pierre"} | ||
, {name: "Cécile"} | ||
, {nested: {structure: ['some', 'öi']}} | ||
]; | ||
|
||
|
||
exports.tests = [ | ||
|
||
['dump_str & laod_str', VALS.length * 2, function() { | ||
VALS.forEach(function(val) { | ||
var dump = serializer.dump_str(val); | ||
var original = serializer.load_str(dump); | ||
assert.deepEqual(original, val); | ||
// Algorithm determinist: | ||
var dump2 = serializer.dump_str(val); | ||
assert.equal(dump, dump2); | ||
}); | ||
}], | ||
|
||
['dump_secure_str', VALS.length * 2, function() { | ||
var encrypt_key = 'somesecretkey'; | ||
var validate_key = 'anothersecretstring'; | ||
VALS.forEach(function(val) { | ||
var res = serializer.dump_secure_str(val, encrypt_key, validate_key); | ||
var original = serializer.load_secure_str(res, encrypt_key, validate_key); | ||
assert.deepEqual(original, val); | ||
// The result string must vary between different calls: | ||
var res2 = serializer.dump_secure_str(val, encrypt_key, validate_key); | ||
assert.notEqual(res, res2); | ||
}); | ||
}], | ||
|
||
]; | ||
|
Submodule node-base64
added at
488e82