From c87b524c5f40f52a63d8b6f01e0d4df842c63f96 Mon Sep 17 00:00:00 2001 From: isaacs Date: Tue, 23 Oct 2012 10:35:15 -0700 Subject: [PATCH] crypto: Clean up buffer handling and DH methods --- lib/crypto.js | 248 ++++++++++++++++++++++----------------------- src/node_crypto.cc | 8 +- 2 files changed, 122 insertions(+), 134 deletions(-) diff --git a/lib/crypto.js b/lib/crypto.js index 85b88af0b2..7efa6243f9 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -37,6 +37,20 @@ try { var crypto = false; } +// This is here because many functions accepted binary strings without +// any explicit encoding in older versions of node, and we don't want +// to break them unnecessarily. +function toBuf(str, encoding) { + encoding = encoding || 'binary'; + if (typeof str === 'string') { + if (encoding === 'buffer') + encoding = 'binary'; + str = new Buffer(str, encoding); + } + return str; +} + + var assert = require('assert'); var StringDecoder = require('string_decoder').StringDecoder; @@ -117,11 +131,11 @@ exports.createCredentials = function(options, context) { if (options.pfx) { var pfx = options.pfx; var passphrase = options.passphrase; - // legacy - if (typeof pfx === 'string') - pfx = new Buffer(pfx, 'binary'); - if (passphrase && typeof passphrase === 'string') - passphrase = new Buffer(passphrase, 'binary'); + + pfx = toBuf(pfx); + if (passphrase) + passphrase = toBuf(passphrase); + if (passphrase) { c.context.loadPKCS12(pfx, passphrase); } else { @@ -140,19 +154,18 @@ function Hash(algorithm) { this._binding = new binding.Hash(algorithm); } + Hash.prototype.update = function(data, encoding) { encoding = encoding || exports.DEFAULT_ENCODING; - if (encoding === 'buffer') - encoding = null; - if (typeof data === 'string') - data = new Buffer(data, encoding); + data = toBuf(data, encoding); this._binding.update(data); return this; }; + Hash.prototype.digest = function(outputEncoding) { outputEncoding = outputEncoding || exports.DEFAULT_ENCODING; - var result = this._binding.digest('buffer'); + var result = this._binding.digest(); if (outputEncoding && outputEncoding !== 'buffer') result = result.toString(outputEncoding); return result; @@ -165,12 +178,10 @@ function Hmac(hmac, key) { if (!(this instanceof Hmac)) return new Hmac(hmac, key); this._binding = new binding.Hmac(); - // legacy - if (typeof key === 'string') - key = new Buffer(key, 'binary'); - this._binding.init(hmac, key); + this._binding.init(hmac, toBuf(key)); } + Hmac.prototype.update = Hash.prototype.update; Hmac.prototype.digest = Hash.prototype.digest; @@ -188,21 +199,17 @@ function Cipher(cipher, password) { return new Cipher(cipher, password); this._binding = new binding.Cipher; - // legacy. - if (typeof password === 'string') - password = new Buffer(password, 'binary'); - - this._binding.init(cipher, password); + this._binding.init(cipher, toBuf(password)); this._decoder = null; } + Cipher.prototype.update = function(data, inputEncoding, outputEncoding) { inputEncoding = inputEncoding || exports.DEFAULT_ENCODING; outputEncoding = outputEncoding || exports.DEFAULT_ENCODING; - if (inputEncoding && inputEncoding !== 'buffer') - data = new Buffer(data, inputEncoding); + data = toBuf(data, inputEncoding); - var ret = this._binding.update(data, 'buffer', 'buffer'); + var ret = this._binding.update(data); if (outputEncoding && outputEncoding !== 'buffer') { this._decoder = getDecoder(this._decoder, outputEncoding); @@ -212,9 +219,10 @@ Cipher.prototype.update = function(data, inputEncoding, outputEncoding) { return ret; }; + Cipher.prototype.final = function(outputEncoding) { outputEncoding = outputEncoding || exports.DEFAULT_ENCODING; - var ret = this._binding.final('buffer'); + var ret = this._binding.final(); if (outputEncoding && outputEncoding !== 'buffer') { this._decoder = getDecoder(this._decoder, outputEncoding); @@ -224,6 +232,7 @@ Cipher.prototype.final = function(outputEncoding) { return ret; }; + Cipher.prototype.setAutoPadding = function(ap) { this._binding.setAutoPadding(ap); return this; @@ -235,61 +244,54 @@ exports.createCipheriv = exports.Cipheriv = Cipheriv; function Cipheriv(cipher, key, iv) { if (!(this instanceof Cipheriv)) return new Cipheriv(cipher, key, iv); - // legacy - if (typeof key === 'string') - key = new Buffer(key, 'binary'); - if (typeof iv === 'string') - iv = new Buffer(iv, 'binary'); this._binding = new binding.Cipher(); - this._binding.initiv(cipher, key, iv); + this._binding.initiv(cipher, toBuf(key), toBuf(iv)); this._decoder = null; } + Cipheriv.prototype.update = Cipher.prototype.update; Cipheriv.prototype.final = Cipher.prototype.final; Cipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding; + exports.createDecipher = exports.Decipher = Decipher; function Decipher(cipher, password) { if (!(this instanceof Decipher)) return new Decipher(cipher, password); - // legacy. - if (typeof password === 'string') - password = new Buffer(password, 'binary'); - this._binding = new binding.Decipher; - this._binding.init(cipher, password); + this._binding.init(cipher, toBuf(password)); this._decoder = null; } + Decipher.prototype.update = Cipher.prototype.update; Decipher.prototype.final = Cipher.prototype.final; Decipher.prototype.finaltol = Cipher.prototype.final; Decipher.prototype.setAutoPadding = Cipher.prototype.setAutoPadding; + exports.createDecipheriv = exports.Decipheriv = Decipheriv; function Decipheriv(cipher, key, iv) { if (!(this instanceof Decipheriv)) return new Decipheriv(cipher, key, iv); - // legacy - if (typeof key === 'string') - key = new Buffer(key, 'binary'); - if (typeof iv === 'string') - iv = new Buffer(iv, 'binary'); + this._binding = new binding.Decipher; - this._binding.initiv(cipher, key, iv); + this._binding.initiv(cipher, toBuf(key), toBuf(iv)); this._decoder = null; } + Decipheriv.prototype.update = Cipher.prototype.update; Decipheriv.prototype.final = Cipher.prototype.final; Decipheriv.prototype.finaltol = Cipher.prototype.final; Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding; + exports.createSign = exports.Sign = Sign; function Sign(algorithm) { if (!(this instanceof Sign)) @@ -298,21 +300,22 @@ function Sign(algorithm) { this._binding.init(algorithm); } + Sign.prototype.update = Hash.prototype.update; -Sign.prototype.sign = function(key, encoding) { - // legacy. - if (typeof key === 'string') - key = new Buffer(key, 'binary'); +Sign.prototype.sign = function(key, encoding) { encoding = encoding || exports.DEFAULT_ENCODING; - var ret = this._binding.sign(key, 'buffer'); + var ret = this._binding.sign(toBuf(key)); + if (encoding && encoding !== 'buffer') ret = ret.toString(encoding); + return ret; }; + exports.createVerify = exports.Verify = Verify; function Verify(algorithm) { if (!(this instanceof Verify)) @@ -322,22 +325,17 @@ function Verify(algorithm) { this._binding.init(algorithm); } + Verify.prototype.update = Hash.prototype.update; -Verify.prototype.verify = function(object, signature, sigEncoding) { - // legacy. - if (typeof object === 'string') - object = new Buffer(object, 'binary'); +Verify.prototype.verify = function(object, signature, sigEncoding) { sigEncoding = sigEncoding || exports.DEFAULT_ENCODING; - if (sigEncoding === 'buffer') - sigEncoding = null; - if (sigEncoding || typeof signature === 'string') - signature = new Buffer(signature, sigEncoding); - - return this._binding.verify(object, signature, 'buffer'); + return this._binding.verify(toBuf(object), toBuf(signature, sigEncoding)); }; + + exports.createDiffieHellman = exports.DiffieHellman = DiffieHellman; function DiffieHellman(sizeOrKey, encoding) { @@ -348,124 +346,120 @@ function DiffieHellman(sizeOrKey, encoding) { this._binding = new binding.DiffieHellman(); else { encoding = encoding || exports.DEFAULT_ENCODING; - if (encoding === 'buffer') - encoding = null; - if (typeof sizeOrKey === 'string') - sizeOrKey = new Buffer(sizeOrKey, encoding); - this._binding = new binding.DiffieHellman(sizeOrKey, 'buffer'); + sizeOrKey = toBuf(sizeOrKey, encoding); + this._binding = new binding.DiffieHellman(sizeOrKey); } } -DiffieHellman.prototype.generateKeys = function(encoding) { - var keys = this._binding.generateKeys('buffer'); + +exports.DiffieHellmanGroup = + exports.createDiffieHellmanGroup = + exports.getDiffieHellman = DiffieHellmanGroup; + +function DiffieHellmanGroup(name) { + if (!(this instanceof DiffieHellmanGroup)) + return new DiffieHellmanGroup(name); + this._binding = new binding.DiffieHellmanGroup(name); +} + + +DiffieHellmanGroup.prototype.generateKeys = + DiffieHellman.prototype.generateKeys = + dhGenerateKeys; + +function dhGenerateKeys(encoding) { + var keys = this._binding.generateKeys(); encoding = encoding || exports.DEFAULT_ENCODING; if (encoding && encoding !== 'buffer') keys = keys.toString(encoding); return keys; -}; +} + + +DiffieHellmanGroup.prototype.computeSecret = + DiffieHellman.prototype.computeSecret = + dhComputeSecret; -DiffieHellman.prototype.computeSecret = function(key, inEnc, outEnc) { +function dhComputeSecret(key, inEnc, outEnc) { inEnc = inEnc || exports.DEFAULT_ENCODING; outEnc = outEnc || exports.DEFAULT_ENCODING; - if (inEnc === 'buffer') - inEnc = null; - if (outEnc === 'buffer') - outEnc = null; - if (inEnc || typeof key === 'string') - key = new Buffer(key, inEnc); - var ret = this._binding.computeSecret(key, 'buffer', 'buffer'); - if (outEnc) + var ret = this._binding.computeSecret(toBuf(key, inEnc)); + if (outEnc && outEnc !== 'buffer') ret = ret.toString(outEnc); return ret; -}; +} + -DiffieHellman.prototype.getPrime = function(encoding) { - var prime = this._binding.getPrime('buffer'); +DiffieHellmanGroup.prototype.getPrime = + DiffieHellman.prototype.getPrime = + dhGetPrime; + +function dhGetPrime(encoding) { + var prime = this._binding.getPrime(); encoding = encoding || exports.DEFAULT_ENCODING; if (encoding && encoding !== 'buffer') prime = prime.toString(encoding); return prime; -}; +} + -DiffieHellman.prototype.getGenerator = function(encoding) { - var generator = this._binding.getGenerator('buffer'); +DiffieHellmanGroup.prototype.getGenerator = + DiffieHellman.prototype.getGenerator = + dhGetGenerator; + +function dhGetGenerator(encoding) { + var generator = this._binding.getGenerator(); encoding = encoding || exports.DEFAULT_ENCODING; if (encoding && encoding !== 'buffer') generator = generator.toString(encoding); return generator; -}; +} + + +DiffieHellmanGroup.prototype.getPublicKey = + DiffieHellman.prototype.getPublicKey = + dhGetPublicKey; -DiffieHellman.prototype.getPublicKey = function(encoding) { - var key = this._binding.getPublicKey('buffer'); +function dhGetPublicKey(encoding) { + var key = this._binding.getPublicKey(); encoding = encoding || exports.DEFAULT_ENCODING; if (encoding && encoding !== 'buffer') key = key.toString(encoding); return key; -}; +} + -DiffieHellman.prototype.getPrivateKey = function(encoding) { - var key = this._binding.getPrivateKey('buffer'); +DiffieHellmanGroup.prototype.getPrivateKey = + DiffieHellman.prototype.getPrivateKey = + dhGetPrivateKey; + +function dhGetPrivateKey(encoding) { + var key = this._binding.getPrivateKey(); encoding = encoding || exports.DEFAULT_ENCODING; if (encoding && encoding !== 'buffer') key = key.toString(encoding); return key; -}; +} + DiffieHellman.prototype.setPublicKey = function(key, encoding) { encoding = encoding || exports.DEFAULT_ENCODING; - if (encoding === 'buffer') - encoding = null; - if (encoding || typeof key === 'string') - key = new Buffer(key, encoding); - this._binding.setPublicKey(key, 'buffer'); + this._binding.setPublicKey(toBuf(key, encoding)); return this; }; + DiffieHellman.prototype.setPrivateKey = function(key, encoding) { encoding = encoding || exports.DEFAULT_ENCODING; - if (encoding === 'buffer') - encoding = null; - if (encoding || typeof key === 'string') - key = new Buffer(key, encoding); - this._binding.setPrivateKey(key, 'buffer'); + this._binding.setPrivateKey(toBuf(key, encoding)); return this; }; -exports.DiffieHellmanGroup = - exports.createDiffieHellmanGroup = - exports.getDiffieHellman = DiffieHellmanGroup; - -function DiffieHellmanGroup(name) { - if (!(this instanceof DiffieHellmanGroup)) - return new DiffieHellmanGroup(name); - this._binding = new binding.DiffieHellmanGroup(name); -} - -DiffieHellmanGroup.prototype.generateKeys = - DiffieHellman.prototype.generateKeys; - -DiffieHellmanGroup.prototype.computeSecret = - DiffieHellman.prototype.computeSecret; - -DiffieHellmanGroup.prototype.getPrime = - DiffieHellman.prototype.getPrime; - -DiffieHellmanGroup.prototype.getGenerator = - DiffieHellman.prototype.getGenerator; - -DiffieHellmanGroup.prototype.getPublicKey = - DiffieHellman.prototype.getPublicKey; - -DiffieHellmanGroup.prototype.getPrivateKey = - DiffieHellman.prototype.getPrivateKey; - exports.pbkdf2 = function(password, salt, iterations, keylen, callback) { - if (typeof password === 'string') - password = new Buffer(password, 'binary'); - if (typeof salt === 'string') - salt = new Buffer(salt, 'binary'); + password = toBuf(password); + salt = toBuf(salt); if (exports.DEFAULT_ENCODING === 'buffer') return binding.PBKDF2(password, salt, iterations, keylen, callback); diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 2012b7df15..37a3e95c66 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3602,13 +3602,7 @@ class DiffieHellman : public ObjectWrap { Local outString; - if (args.Length() > 2 && args[2]->IsString()) { - outString = EncodeWithEncoding(args[2], data, dataSize); - } else if (args.Length() > 1 && args[1]->IsString()) { - outString = EncodeWithEncoding(args[1], data, dataSize); - } else { - outString = Encode(data, dataSize, BUFFER); - } + outString = Encode(data, dataSize, BUFFER); delete[] data; return scope.Close(outString);