Browse files

wip

  • Loading branch information...
1 parent ea344c0 commit a5937710cf087d4666ef3a8e10fc45a453a26eaf @isaacs committed Oct 9, 2012
Showing with 290 additions and 33 deletions.
  1. +3 −3 doc/api/crypto.markdown
  2. +5 −1 lib/buffer.js
  3. +272 −23 lib/crypto.js
  4. +4 −0 src/node_crypto.cc
  5. +5 −6 test/simple/test-crypto.js
  6. +1 −0 test/simple/test-fs-sir-writes-alot.js
View
6 doc/api/crypto.markdown
@@ -1,6 +1,6 @@
# Crypto
- Stability: 3 - Stable
+ Stability: 2 - Unstable (Reworking to standard stream API)
Use `require('crypto')` to access this module.
@@ -196,13 +196,13 @@ You can disable auto padding if the data has been encrypted without standard blo
`decipher.final` from checking and removing it. Can only work if the input data's length is a multiple of the
ciphers block size. You must call this before streaming data to `decipher.update`.
-## crypto.createSign(algorithm)
+## crypto.createSign(algorithm, privateKey)
Creates and returns a signing object, with the given algorithm.
On recent OpenSSL releases, `openssl list-public-key-algorithms` will display
the available signing algorithms. Examples are `'RSA-SHA256'`.
-## Class: Signer
+## Class: Sign
Class for generating signatures.
View
6 lib/buffer.js
@@ -104,14 +104,18 @@ SlowBuffer.prototype.hexWrite = function(string, offset, length) {
// must be an even number of digits
var strLen = string.length;
if (strLen % 2) {
+ console.error('invalid hex=%j', string);
throw new Error('Invalid hex string');
}
if (length > strLen / 2) {
length = strLen / 2;
}
for (var i = 0; i < length; i++) {
var byte = parseInt(string.substr(i * 2, 2), 16);
- if (isNaN(byte)) throw new Error('Invalid hex string');
+ if (isNaN(byte)) {
+ console.error('invalid hex=%j', string);
+ throw new Error('Invalid hex string');
+ }
this[offset + i] = byte;
}
SlowBuffer._charsWritten = i * 2;
View
295 lib/crypto.js
@@ -23,23 +23,18 @@
try {
var binding = process.binding('crypto');
var SecureContext = binding.SecureContext;
- var Hmac = binding.Hmac;
- var Hash = binding.Hash;
- var Cipher = binding.Cipher;
- var Decipher = binding.Decipher;
- var Sign = binding.Sign;
- var Verify = binding.Verify;
var DiffieHellman = binding.DiffieHellman;
var DiffieHellmanGroup = binding.DiffieHellmanGroup;
var PBKDF2 = binding.PBKDF2;
var randomBytes = binding.randomBytes;
var pseudoRandomBytes = binding.pseudoRandomBytes;
var crypto = true;
} catch (e) {
-
var crypto = false;
}
+var util = require('util');
+var Transform = require('_stream_transform');
function Credentials(secureProtocol, flags, context) {
if (!(this instanceof Credentials)) {
@@ -127,50 +122,304 @@ exports.createCredentials = function(options, context) {
};
+// Base class for Hmac and Hash
+util.inherits(Digest, Transform);
+
+function Digest(options) {
+ Transform.call(this, options);
+ this._writableState.decodeStrings = false;
+}
+
+Digest.prototype._transform = function(chunk, output, cb) {
+ var enc = chunk[1];
+ chunk = chunk[0];
+ if (!Buffer.isBuffer(chunk) && !enc)
+ enc = 'utf8';
+ this.update(chunk, enc);
+ cb();
+};
+
+Digest.prototype._flush = function(output, cb) {
+ var enc = this._readableState.encoding || 'buffer';
+ output(this.digest(enc));
+ cb();
+};
+
+
+// legacy, non-stream api.
+Digest.prototype.update = function(chunk, encoding) {
+ encoding = encoding || 'buffer';
+ return this._binding.update(chunk, encoding);
+};
+
+Digest.prototype.digest = function(encoding) {
+ encoding = encoding || this._readableState.encoding || 'buffer';
+ return this._binding.digest(encoding);
+};
+
+
exports.Hash = Hash;
-exports.createHash = function(hash) {
- return new Hash(hash);
+util.inherits(Hash, Digest);
+
+function Hash(hash, options) {
+ if (!(this instanceof Hash))
+ return new Hash(hash, options);
+
+ this._binding = new binding.Hash(hash);
+ Digest.call(this, options);
+}
+
+exports.createHash = function(hash, options) {
+ return new Hash(hash, options);
};
exports.Hmac = Hmac;
+util.inherits(Hmac, Digest);
+
+function Hmac(hmac, key, options) {
+ if (!(this instanceof Hmac))
+ return new Hmac(hmac, key, options);
+
+ this._binding = new binding.Hmac();
+ this.init(hmac, key);
+ Digest.call(this, options);
+}
+
+Hmac.prototype.init = function(hmac, key) {
+ this._binding.init(hmac, key);
+ return this;
+};
+
exports.createHmac = function(hmac, key) {
- return (new Hmac).init(hmac, key);
+ return new Hmac(hmac, key);
};
-exports.Cipher = Cipher;
-exports.createCipher = function(cipher, password) {
- return (new Cipher).init(cipher, password);
+
+util.inherits(CipherStream, Transform);
+function CipherStream(options) {
+ Transform.call(this, options);
+ this._writableState.decodeStrings = false;
+}
+
+CipherStream.prototype._transform = function(chunk, output, cb) {
+ var inEnc = chunk[1] || 'buffer';
+ chunk = chunk[0];
+ var outEnc = this._readableState.encoding || 'buffer';
+ var ret = this.update(chunk, inEnc, outEnc);
+ if (ret && ret.length)
+ output(ret);
+ cb();
+};
+
+CipherStream.prototype._flush = function(output, cb) {
+ var encoding = this._readableState.encoding || 'buffer';
+ var final = this.final(encoding);
+ if (final && final.length)
+ output(final);
+ cb();
+};
+
+CipherStream.prototype.update = function(data, inenc, outenc) {
+ return this._binding.update(data, inenc, outenc);
};
+CipherStream.prototype.final = function(outenc) {
+ return this._binding.final(outenc);
+};
+
+CipherStream.prototype.init = function(cipher, password) {
+ this._binding.init(cipher, password);
+ return this;
+};
-exports.createCipheriv = function(cipher, key, iv) {
- return (new Cipher).initiv(cipher, key, iv);
+CipherStream.prototype.initiv = function(cipher, key, iv) {
+ this._binding.initiv(cipher, key, iv);
+ return this;
+};
+
+
+util.inherits(Cipher, CipherStream);
+
+function Cipher(cipher, password, options) {
+ if (!(this instanceof Cipher))
+ return new Cipher(cipher, password, options);
+
+ this._binding = new binding.Cipher();
+ this._binding.init(cipher, password);
+ CipherStream.call(this, options);
+}
+
+Cipher.prototype.setAutoPadding = function(ap) {
+ return this._binding.setAutoPadding(ap);
+};
+
+exports.Cipher = Cipher;
+exports.createCipher = function(cipher, password, options) {
+ return new Cipher(cipher, password, options);
};
exports.Decipher = Decipher;
-exports.createDecipher = function(cipher, password) {
- return (new Decipher).init(cipher, password);
+exports.createDecipher = function(cipher, password, options) {
+ return new Decipher(cipher, password, options);
+};
+
+util.inherits(Decipher, CipherStream);
+function Decipher(cipher, password, options) {
+ if (!(this instanceof Decipher))
+ return new Decipher(cipher, password, options);
+
+ this._binding = new binding.Decipher();
+ this._binding.init(cipher, password);
+ CipherStream.call(this, options);
+}
+
+Decipher.prototype.setAutoPadding = Cipher.prototype.setAutoPadding;
+
+
+exports.Cipheriv = Cipheriv;
+util.inherits(Cipheriv, CipherStream);
+
+exports.createCipheriv = function(cipher, key, iv, options) {
+ return new Cipheriv(cipher, key, iv, options);
};
+function Cipheriv(cipher, key, iv, options) {
+ if (!(this instanceof Cipheriv))
+ return new Cipheriv(cipher, key, iv, options);
+
+ this._binding = new binding.Cipher;
+ this._binding.initiv(cipher, key, iv);
+ CipherStream.call(this, options);
+}
+
-exports.createDecipheriv = function(cipher, key, iv) {
- return (new Decipher).initiv(cipher, key, iv);
+exports.Decipheriv = Decipheriv;
+exports.createDecipheriv = function(cipher, key, iv, options) {
+ return new Decipheriv(cipher, key, iv, options);
};
+util.inherits(Decipheriv, CipherStream);
+
+function Decipheriv(cipher, key, iv, options) {
+ if (!(this instanceof Decipheriv))
+ return new Decipheriv(cipher, key, iv, options);
+
+ this._binding = new binding.Decipher;
+ this._binding.initiv(cipher, key, iv);
+ CipherStream.call(this, options);
+}
+
+
exports.Sign = Sign;
-exports.createSign = function(algorithm) {
- return (new Sign).init(algorithm);
+exports.createSign = function(algorithm, key, options) {
+ return new Sign(algorithm, key, options);
+};
+
+util.inherits(Sign, Transform);
+
+function Sign(algorithm, key, options) {
+ if (!(this instanceof Sign))
+ return new Sign(algorithm, key, options);
+
+ if (typeof key === 'object') {
+ options = key;
+ key = options.key;
+ }
+ this.key = key;
+ this._binding = new binding.Sign;
+ this._binding.init(algorithm);
+ Transform.call(this, options);
+ this._writableState.decodeStrings = false;
+}
+
+Sign.prototype._transform = function(chunk, output, cb) {
+ var enc = chunk[1] || 'buffer';
+ chunk = chunk[0];
+ this._binding.update(chunk);
+ cb();
+};
+
+Sign.prototype._flush = function(output, cb) {
+ var ret = this._binding.sign(this.key, 'buffer');
+ if (ret && ret.length)
+ output(ret);
+ cb();
+};
+
+// legacy
+Sign.prototype.update = function(chunk) {
+ return this._binding.update(chunk);
};
+Sign.prototype.sign = function(key, encoding) {
+ return this._binding.sign(key, encoding);
+};
+
+
+
exports.Verify = Verify;
-exports.createVerify = function(algorithm) {
- return (new Verify).init(algorithm);
+exports.createVerify = function(algo, key, sig, sigEnc, options) {
+ return new Verify(algo, key, sig, sigEnc, options);
};
+util.inherits(Verify, Transform);
+
+function Verify(algorithm, key, signature, sigEncoding, options) {
+ if (!(this instanceof Verify))
+ return new Verify(algorithm, key, signature, sigEncoding, options);
+
+ if (typeof key === 'object') {
+ options = key;
+ key = options.key;
+ signature = options.signature;
+ sigEncoding = options.signatureEncoding;
+ } else if (typeof signature === 'object') {
+ options = signature;
+ signature = options.signature;
+ sigEncoding = options.signatureEncoding;
+ } else if (typeof sigEncoding === 'object') {
+ options = sigEncoding;
+ sigEncoding = options.signatureEncoding;
+ }
+
+ this.key = key;
+ this.signature = signature;
+ this.signatureEncoding = sigEncoding;
+
+ this._binding = new binding.Verify(algorithm);
+ this._binding.init(algorithm);
+
+ Transform.call(this, options);
+}
+
+Verify.prototype._transform = function(chunk, output, cb) {
+ this._binding.update(chunk);
+ cb();
+};
+
+Verify.prototype._flush = function(output, cb) {
+ var key = this.key;
+ var sig = this.signature;
+ var sigEnc = this.signatureEncoding;
+ var ret = this._binding.verify(key, sig, sigEnc);
+ output(ret);
+ cb();
+};
+
+Verify.prototype.update = function(chunk, encoding) {
+ return this._binding.update(chunk, encoding);
+};
+
+Verify.prototype.verify = function(key, sig, enc) {
+ return this._binding.verify(key, sig, enc);
+};
+
+
+
exports.DiffieHellman = DiffieHellman;
exports.createDiffieHellman = function(size_or_key, enc) {
if (!size_or_key) {
View
4 src/node_crypto.cc
@@ -2632,15 +2632,19 @@ class Decipher : public ObjectWrap {
int r;
if (!initialised_) {
+ fprintf(stderr, "DecipherFinal not initialized\n");
*out_len = 0;
*out = NULL;
return 0;
}
+ fprintf(stderr, "DecipherFinal len=%d out=%s", *out_len, *out);
*out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)];
r = EVP_CipherFinal_ex(&ctx,*out,out_len);
EVP_CIPHER_CTX_cleanup(&ctx);
initialised_ = false;
+ if (!r)
+ fprintf(stderr, "DecipherFinal actual fail\n");
return r;
}
View
11 test/simple/test-crypto.js
@@ -376,12 +376,11 @@ assert.equal(a1, 'h\u00ea\u00cb\u0097\u00d8o\fF!\u00fa+\u000e\u0017\u00ca' +
'\u00bd\u008c', 'Test MD5 as binary');
assert.equal(a2, '2bX1jws4GYKTlxhloUB09Z66PoJZW+y+hq5R8dnx9l4=',
'Test SHA256 as base64');
-assert.equal(a3, '\u00c1(4\u00f1\u0003\u001fd\u0097!O\'\u00d4C/&Qz\u00d4' +
- '\u0094\u0015l\u00b8\u008dQ+\u00db\u001d\u00c4\u00b5}\u00b2' +
- '\u00d6\u0092\u00a3\u00df\u00a2i\u00a1\u009b\n\n*\u000f' +
- '\u00d7\u00d6\u00a2\u00a8\u0085\u00e3<\u0083\u009c\u0093' +
- '\u00c2\u0006\u00da0\u00a1\u00879(G\u00ed\'',
- 'Test SHA512 as assumed binary');
+assert.deepEqual(a3, new Buffer('c12834f1031f6497214f27d4432f26517ad494' +
+ '156cb88d512bdb1dc4b57db2d692a3dfa269a1' +
+ '9b0a0a2a0fd7d6a2a885e33c839c93c206da30' +
+ 'a187392847ed27', 'hex'),
+ 'Test SHA512 as assumed buffer');
assert.deepEqual(a4,
new Buffer('8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 'hex'),
'Test SHA1');
View
1 test/simple/test-fs-sir-writes-alot.js
@@ -67,5 +67,6 @@ process.on('exit', function() {
// that we get (N * line.length). Let's just make sure we've checked a
// few...
assert.ok(bytesChecked > 1000);
+ console.log('ok');
});

0 comments on commit a593771

Please sign in to comment.