Browse Source

fix string/buffer sjcl issue

...by using sjcl.mode.cbc.encrypt/decrypt rather than sjcl.encrypt/decrypt. The
difference is that the sjcl.encrypt/decrypt functions are really convenience
methods designed to encrypt and decrypt strings, but don't play nice with
binary data, as revealed in the tests in this commit and the previous commit.
Basically, if you use them to encrypt and decrypt binary data as a string, it
will return the wrong result or an error.

The solution is to use the block cipher directly, in this case sjcl.mode.cbc.
This also has the advantage of fewer format conversions - no converting to
base64 and JSON strings. This makes things faster. Also, it is actually correct
unlike the previous method.
patch-2
Ryan X. Charles 11 years ago
parent
commit
65ab3a663a
  1. 38
      lib/browser/ECIES.js
  2. 42
      test/test.ECIES.js

38
lib/browser/ECIES.js

@ -9,18 +9,10 @@ ECIES.symmetricEncrypt = function(key, iv, message) {
var smessage = sjcl.codec.hex.toBits(message.toString('hex'));
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]();
var params = {
iv: siv,
ks: 256,
ts: 128,
iter: 1000,
mode: 'cbc'
};
var encrypted = sjcl.encrypt(skey, smessage, params);
var enchex = sjcl.codec.hex.fromBits(sjcl.codec.base64.toBits(JSON.parse(encrypted).ct));
var encbuf = new Buffer(enchex, 'hex');
var cipher = new sjcl.cipher.aes(skey);
var encrypted = sjcl.mode.cbc.encrypt(cipher, smessage, siv);
var encbuf = new Buffer(sjcl.codec.hex.fromBits(encrypted), 'hex');
var r = Buffer.concat([iv, encbuf]);
return r;
@ -31,25 +23,13 @@ ECIES.symmetricDecrypt = function(key, encrypted) {
var iv = encrypted.slice(0, 16);
var todecrypt = encrypted.slice(16, encrypted.length);
var siv = sjcl.codec.base64.fromBits(sjcl.codec.hex.toBits(iv.toString('hex')));
var sct = sjcl.codec.base64.fromBits(sjcl.codec.hex.toBits(todecrypt.toString('hex')));
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]();
var obj = {
iv: siv,
v: 1,
iter: 1000,
ks: 256,
ts: 128,
mode: 'cbc',
adata: '',
cipher: 'aes',
ct: sct
};
var str = JSON.stringify(obj);
var decrypted = sjcl.decrypt(skey, str);
var decbuf = new Buffer(decrypted);
var encbits = sjcl.codec.hex.toBits(todecrypt.toString('hex'));
var ivbits = sjcl.codec.hex.toBits(iv.toString('hex'));
var cipher = new sjcl.cipher.aes(skey);
var decrypted = sjcl.mode.cbc.decrypt(cipher, encbits, ivbits);
var decbuf = new Buffer(sjcl.codec.hex.fromBits(decrypted), 'hex');
return decbuf;
};

42
test/test.ECIES.js

@ -75,6 +75,48 @@ describe('ECIES', function() {
decrypted.toString().should.equal('this is my message');
});
it('should encrypt and decrypt 0x80 correctly, the first bad byte', function() {
var privhex = 'e0224327f5e4a9daea6c7b996cb013775f90821d15d7d0d25db517c7cd0c1a8e';
var key = new bitcore.Key();
key.private = new Buffer(privhex, 'hex');
key.regenerateSync();
var data = new Buffer([0x80]);
var encrypted = bitcore.ECIES.encrypt(key.public, data);
var decrypted = bitcore.ECIES.decrypt(key.private, encrypted);
decrypted.toString('hex').should.equal('80');
decrypted.toString('hex').should.not.equal('c280');
});
it('should encrypt and decrypt this known problematic encrypted message', function() {
var privhex = 'e0224327f5e4a9daea6c7b996cb013775f90821d15d7d0d25db517c7cd0c1a8e';
var key = new bitcore.Key();
key.private = new Buffer(privhex, 'hex');
key.regenerateSync();
var data = new Buffer('010053bdae9b000000017b2274797065223a2268656c6c6f222c22636f70617965724964223a22303237323735366234366561386564313763376166613934303861306161333535616266326432623263353134373637343766353135326332623535653163656230227d', 'hex');
var data = new Buffer('53bdae00', 'hex');
var encrypted = bitcore.ECIES.encrypt(key.public, data);
var decrypted = bitcore.ECIES.decrypt(key.private, encrypted);
decrypted.toString('hex').should.not.equal('53c2bdc2ae00');
decrypted.toString('hex').should.equal('53bdae00');
});
it('should encrypt and decrypt this known problematic encrypted message', function() {
var privhex = 'e0224327f5e4a9daea6c7b996cb013775f90821d15d7d0d25db517c7cd0c1a8e';
var key = new bitcore.Key();
key.private = new Buffer(privhex, 'hex');
key.regenerateSync();
var data = new Buffer('010053bdae9b000000017b2274797065223a2268656c6c6f222c22636f70617965724964223a22303237323735366234366561386564313763376166613934303861306161333535616266326432623263353134373637343766353135326332623535653163656230227d', 'hex');
var encrypted = bitcore.ECIES.encrypt(key.public, data);
var decrypted = bitcore.ECIES.decrypt(key.private, encrypted);
decrypted.toString('hex').should.equal('010053bdae9b000000017b2274797065223a2268656c6c6f222c22636f70617965724964223a22303237323735366234366561386564313763376166613934303861306161333535616266326432623263353134373637343766353135326332623535653163656230227d');
});
it('should decrypt this known problematic encrypted message', function() {
var privhex = 'e0224327f5e4a9daea6c7b996cb013775f90821d15d7d0d25db517c7cd0c1a8e';
var key = new bitcore.Key();

Loading…
Cancel
Save