Skip to content

Commit

Permalink
replace buffer hex string comparisons with cmp
Browse files Browse the repository at this point in the history
In order to compare buffers, fullnode had been exclusively using node's
toString('hex') function and then doing a string comparison. This method is
subject to timing attacks for any cryptography-sensitive code. We replace all
such instances with the cmp.eq function which is constant-time.

Related issue: #23
  • Loading branch information
ryanxcharles committed Jan 12, 2015
1 parent 4a2306b commit 5ffa0af
Show file tree
Hide file tree
Showing 9 changed files with 18 additions and 11 deletions.
3 changes: 2 additions & 1 deletion lib/ach.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
var AESCBC = require('./aescbc');
var Hash = require('./hash');
var cmp = require('./cmp');

var ACH = {};

Expand All @@ -29,7 +30,7 @@ ACH.decrypt = function(encbuf, cipherkeybuf) {
var hmacbuf = encbuf.slice(0, 256 / 8);
encbuf = encbuf.slice(256 / 8, encbuf.length);
var hmacbuf2 = Hash.sha256hmac(encbuf, cipherkeybuf);
if (hmacbuf.toString('hex') !== hmacbuf2.toString('hex'))
if (!cmp.eq(hmacbuf, hmacbuf2))
throw new Error('Message authentication failed - HMACs are not equivalent');
return AESCBC.decrypt(encbuf, cipherkeybuf);
};
3 changes: 2 additions & 1 deletion lib/base58check.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
var base58 = require('./base58');
var sha256sha256 = require('./hash').sha256sha256;
var cmp = require('./cmp');

var Base58Check = function Base58Check(obj) {
if (!(this instanceof Base58Check))
Expand Down Expand Up @@ -44,7 +45,7 @@ Base58Check.decode = function(s) {
var hash = sha256sha256(data);
var hash4 = hash.slice(0, 4);

if (csum.toString('hex') !== hash4.toString('hex'))
if (!cmp.eq(csum, hash4))
throw new Error("Checksum mismatch");

return data;
Expand Down
3 changes: 2 additions & 1 deletion lib/bsm.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var BW = require('./bw');
var Hash = require('./hash');
var Address = require('./address');
var Sig = require('./sig');
var cmp = require('./cmp');

var BSM = function BSM(obj) {
if (!(this instanceof BSM))
Expand Down Expand Up @@ -94,7 +95,7 @@ BSM.prototype.verify = function() {

var address = Address().fromPubkey(ecdsa.keypair.pubkey, undefined, this.sig.compressed);
//TODO: what if livenet/testnet mismatch?
if (address.hashbuf.toString('hex') === this.address.hashbuf.toString('hex'))
if (cmp.eq(address.hashbuf, this.address.hashbuf))
this.verified = true;
else
this.verified = false;
Expand Down
3 changes: 2 additions & 1 deletion lib/cbc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29
*/
var Random = require('./random');
var cmp = require('./cmp');

var CBC = {};

Expand Down Expand Up @@ -119,7 +120,7 @@ CBC.pkcs7unpad = function(paddedbuf, blocksize) {
var padbuf = paddedbuf.slice(paddedbuf.length - padlength, paddedbuf.length);
var padbuf2 = new Buffer(padlength);
padbuf2.fill(padlength);
if (padbuf.toString('hex') !== padbuf2.toString('hex'))
if (!cmp.eq(padbuf, padbuf2))
throw new Error('invalid padding');
return paddedbuf.slice(0, paddedbuf.length - padlength);
};
Expand Down
3 changes: 2 additions & 1 deletion lib/expmt/ecies.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var Point = require('../point');
var Hash = require('../hash');
var Pubkey = require('../pubkey');
var Privkey = require('../privkey');
var cmp = require('../cmp');

// http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme
var ECIES = function ECIES() {
Expand Down Expand Up @@ -46,7 +47,7 @@ ECIES.decrypt = function(encbuf, toprivkey) {
var c = encbuf.slice(33, encbuf.length - 32);
var d = encbuf.slice(encbuf.length - 32, encbuf.length);
var d2 = Hash.sha256hmac(c, kM);
if (d.toString('hex') !== d2.toString('hex'))
if (!cmp.eq(d, d2))
throw new Error('Invalid checksum');
var messagebuf = AESCBC.decrypt(c, kE);
return messagebuf;
Expand Down
3 changes: 2 additions & 1 deletion lib/expmt/stealth/key.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var Pubkey = require('../../pubkey');
var Point = require('../../point');
var Hash = require('../../hash');
var KDF = require('../../kdf');
var cmp = require('../../cmp');

var SKey = function SKey(payloadKeypair, scanKeypair) {
if (!(this instanceof SKey))
Expand Down Expand Up @@ -79,7 +80,7 @@ SKey.prototype.isForMe = function(senderPubkey, myPossiblePubkeyhashbuf) {
var pubkeybuf = pubkey.toDER(true);
var pubkeyhash = Hash.sha256ripemd160(pubkeybuf);

if (pubkeyhash.toString('hex') === myPossiblePubkeyhashbuf.toString('hex'))
if (cmp.eq(pubkeyhash, myPossiblePubkeyhashbuf))
return true;
else
return false;
Expand Down
3 changes: 2 additions & 1 deletion lib/expmt/stealth/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var ECIES = require('../ecies');
var Keypair = require('../../keypair');
var Address = require('../../address');
var Pubkey = require('../../pubkey');
var cmp = require('../../cmp');

var SMessage = function SMessage(obj) {
if (!(this instanceof SMessage))
Expand Down Expand Up @@ -75,7 +76,7 @@ SMessage.prototype.decrypt = function() {
SMessage.prototype.isForMe = function() {
var receivePubkey = this.toSKey.getReceivePubkey(this.fromKeypair.pubkey);
var receiveAddress = Address().fromPubkey(receivePubkey);
if (receiveAddress.toString('hex') === this.receiveAddress.toString('hex'))
if (cmp.eq(receiveAddress.hashbuf, this.receiveAddress.hashbuf))
return true;
else
return false;
Expand Down
3 changes: 2 additions & 1 deletion lib/interp.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var BR = require('./br');
var BW = require('./bw');
var Sig = require('./sig');
var Pubkey = require('./pubkey');
var cmp = require('./cmp');

var Interp = function Interp(obj) {
if (!(this instanceof Interp))
Expand Down Expand Up @@ -684,7 +685,7 @@ Interp.prototype.step = function() {
}
var buf1 = this.stack[this.stack.length - 2];
var buf2 = this.stack[this.stack.length - 1];
var fEqual = buf1.toString('hex') === buf2.toString('hex');
var fEqual = cmp.eq(buf1, buf2);
// Opcode.OP_NOTEQUAL is disabled because it would be too easy to say
// something like n != 1 and have some wiseguy pass in 1 with extra
// zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)
Expand Down
5 changes: 2 additions & 3 deletions lib/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var BR = require('./br');
var BW = require('./bw');
var BN = require('./bn');
var Opcode = require('./opcode');
var cmp = require('./cmp');

var Script = function Script(buf) {
if (!(this instanceof Script))
Expand Down Expand Up @@ -372,12 +373,10 @@ Script.prototype.isScripthashIn = function() {
*/
Script.prototype.findAndDelete = function(script) {
var buf = script.toBuffer();
var hex = buf.toString('hex');
for (var i = 0; i < this.chunks.length; i++) {
var script2 = Script({chunks: [this.chunks[i]]});
var buf2 = script2.toBuffer();
var hex2 = buf2.toString('hex');
if (hex === hex2)
if (cmp.eq(buf, buf2))
this.chunks.splice(i, 1);
}
return this;
Expand Down

0 comments on commit 5ffa0af

Please sign in to comment.