Skip to content

Commit

Permalink
Module to [secure] dump/load JSON objs to/from string.
Browse files Browse the repository at this point in the history
  • Loading branch information
virtuo committed Dec 28, 2010
1 parent d9a6c0e commit d3c66a3
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
@@ -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
81 changes: 81 additions & 0 deletions src/nodetk/serializer.js
@@ -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);
};

52 changes: 52 additions & 0 deletions src/nodetk/tests/test_serializer.js
@@ -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);
});
}],

];

1 change: 1 addition & 0 deletions vendor/node-base64
Submodule node-base64 added at 488e82

0 comments on commit d3c66a3

Please sign in to comment.