diff options
Diffstat (limited to 'test/simple/test-crypto.js')
-rw-r--r-- | test/simple/test-crypto.js | 312 |
1 files changed, 256 insertions, 56 deletions
diff --git a/test/simple/test-crypto.js b/test/simple/test-crypto.js index 535af760f..291ac504b 100644 --- a/test/simple/test-crypto.js +++ b/test/simple/test-crypto.js @@ -32,6 +32,8 @@ try { process.exit(); } +crypto.DEFAULT_ENCODING = 'buffer'; + var fs = require('fs'); var path = require('path'); @@ -79,6 +81,62 @@ var h1 = crypto.createHmac('sha1', 'Node') .digest('hex'); assert.equal(h1, '19fd6e1ba73d9ed2224dd5094a71babe85d9a892', 'test HMAC'); +// Test HMAC (Wikipedia Test Cases) +var wikipedia = [ + { + key: 'key', data: 'The quick brown fox jumps over the lazy dog', + hmac: { // HMACs lifted from Wikipedia. + md5: '80070713463e7749b90c2dc24911e275', + sha1: 'de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9', + sha256: + 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc' + + '2d1a3cd8' + } + }, + { + key: 'key', data: '', + hmac: { // Intermediate test to help debugging. + md5: '63530468a04e386459855da0063b6596', + sha1: 'f42bb0eeb018ebbd4597ae7213711ec60760843f', + sha256: + '5d5d139563c95b5967b9bd9a8c9b233a9dedb45072794cd232dc1b74' + + '832607d0' + } + }, + { + key: '', data: 'The quick brown fox jumps over the lazy dog', + hmac: { // Intermediate test to help debugging. + md5: 'ad262969c53bc16032f160081c4a07a0', + sha1: '2ba7f707ad5f187c412de3106583c3111d668de8', + sha256: + 'fb011e6154a19b9a4c767373c305275a5a69e8b68b0b4c9200c383dc' + + 'ed19a416' + } + }, + { + key: '', data: '', + hmac: { // HMACs lifted from Wikipedia. + md5: '74e6f7298a9c2d168935f58c001bad88', + sha1: 'fbdb1d1b18aa6c08324b7d64b71fb76370690e1d', + sha256: + 'b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c71214' + + '4292c5ad' + } + }, +] + +for (var i = 0, l = wikipedia.length; i < l; i++) { + for (var hash in wikipedia[i]['hmac']) { + var result = crypto.createHmac(hash, wikipedia[i]['key']) + .update(wikipedia[i]['data']) + .digest('hex'); + assert.equal(wikipedia[i]['hmac'][hash], + result, + 'Test HMAC-' + hash + ': Test case ' + (i + 1) + ' wikipedia'); + } +} + + // Test HMAC-SHA-* (rfc 4231 Test Cases) var rfc4231 = [ { @@ -228,15 +286,20 @@ var rfc4231 = [ for (var i = 0, l = rfc4231.length; i < l; i++) { for (var hash in rfc4231[i]['hmac']) { + var str = crypto.createHmac(hash, rfc4231[i].key); + str.end(rfc4231[i].data); + var strRes = str.read().toString('hex'); var result = crypto.createHmac(hash, rfc4231[i]['key']) .update(rfc4231[i]['data']) .digest('hex'); if (rfc4231[i]['truncate']) { result = result.substr(0, 32); // first 128 bits == 32 hex chars + strRes = strRes.substr(0, 32); } assert.equal(rfc4231[i]['hmac'][hash], result, 'Test HMAC-' + hash + ': Test case ' + (i + 1) + ' rfc 4231'); + assert.equal(strRes, result, 'Should get same result from stream'); } } @@ -369,18 +432,42 @@ var a0 = crypto.createHash('sha1').update('Test123').digest('hex'); var a1 = crypto.createHash('md5').update('Test123').digest('binary'); var a2 = crypto.createHash('sha256').update('Test123').digest('base64'); var a3 = crypto.createHash('sha512').update('Test123').digest(); // binary +var a4 = crypto.createHash('sha1').update('Test123').digest('buffer'); + +// stream interface +var a5 = crypto.createHash('sha512'); +a5.end('Test123'); +a5 = a5.read(); + +var a6 = crypto.createHash('sha512'); +a6.write('Te'); +a6.write('st'); +a6.write('123'); +a6.end(); +a6 = a6.read(); assert.equal(a0, '8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 'Test SHA1'); 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( + '\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\'', + 'binary'), + 'Test SHA512 as assumed buffer'); +assert.deepEqual(a4, + new Buffer('8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 'hex'), + 'Test SHA1'); + +// stream interface should produce the same result. +assert.deepEqual(a5, a3, 'stream interface is consistent'); +assert.deepEqual(a6, a3, 'stream interface is consistent'); // Test multiple updates to same hash var h1 = crypto.createHash('sha1').update('Test123').digest('hex'); @@ -409,6 +496,11 @@ assert.throws(function() { var s1 = crypto.createSign('RSA-SHA1') .update('Test123') .sign(keyPem, 'base64'); +var s1stream = crypto.createSign('RSA-SHA1'); +s1stream.end('Test123'); +s1stream = s1stream.sign(keyPem, 'base64'); +assert.equal(s1, s1stream, 'Stream produces same output'); + var verified = crypto.createVerify('RSA-SHA1') .update('Test') .update('123') @@ -417,13 +509,41 @@ assert.strictEqual(verified, true, 'sign and verify (base 64)'); var s2 = crypto.createSign('RSA-SHA256') .update('Test123') - .sign(keyPem); // binary + .sign(keyPem, 'binary'); +var s2stream = crypto.createSign('RSA-SHA256'); +s2stream.end('Test123'); +s2stream = s2stream.sign(keyPem, 'binary'); +assert.equal(s2, s2stream, 'Stream produces same output'); + var verified = crypto.createVerify('RSA-SHA256') .update('Test') .update('123') - .verify(certPem, s2); // binary + .verify(certPem, s2, 'binary'); assert.strictEqual(verified, true, 'sign and verify (binary)'); +var verStream = crypto.createVerify('RSA-SHA256'); +verStream.write('Tes'); +verStream.write('t12'); +verStream.end('3'); +verified = verStream.verify(certPem, s2, 'binary'); +assert.strictEqual(verified, true, 'sign and verify (stream)'); + +var s3 = crypto.createSign('RSA-SHA1') + .update('Test123') + .sign(keyPem, 'buffer'); +var verified = crypto.createVerify('RSA-SHA1') + .update('Test') + .update('123') + .verify(certPem, s3); +assert.strictEqual(verified, true, 'sign and verify (buffer)'); + +var verStream = crypto.createVerify('RSA-SHA1'); +verStream.write('Tes'); +verStream.write('t12'); +verStream.end('3'); +verified = verStream.verify(certPem, s3); +assert.strictEqual(verified, true, 'sign and verify (stream)'); + function testCipher1(key) { // Test encryption and decryption @@ -441,6 +561,20 @@ function testCipher1(key) { txt += decipher.final('utf8'); assert.equal(txt, plaintext, 'encryption and decryption'); + + // streaming cipher interface + // NB: In real life, it's not guaranteed that you can get all of it + // in a single read() like this. But in this case, we know it's + // quite small, so there's no harm. + var cStream = crypto.createCipher('aes192', key); + cStream.end(plaintext); + ciph = cStream.read(); + + var dStream = crypto.createDecipher('aes192', key); + dStream.end(ciph); + txt = dStream.read().toString('utf8'); + + assert.equal(txt, plaintext, 'encryption and decryption with streams'); } @@ -481,6 +615,38 @@ function testCipher3(key, iv) { txt += decipher.final('utf8'); assert.equal(txt, plaintext, 'encryption and decryption with key and iv'); + + // streaming cipher interface + // NB: In real life, it's not guaranteed that you can get all of it + // in a single read() like this. But in this case, we know it's + // quite small, so there's no harm. + var cStream = crypto.createCipheriv('des-ede3-cbc', key, iv); + cStream.end(plaintext); + ciph = cStream.read(); + + var dStream = crypto.createDecipheriv('des-ede3-cbc', key, iv); + dStream.end(ciph); + txt = dStream.read().toString('utf8'); + + assert.equal(txt, plaintext, 'streaming cipher iv'); +} + + +function testCipher4(key, iv) { + // Test encyrption and decryption with explicit key and iv + var plaintext = + '32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' + + 'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' + + 'jAfaFg**'; + var cipher = crypto.createCipheriv('des-ede3-cbc', key, iv); + var ciph = cipher.update(plaintext, 'utf8', 'buffer'); + ciph = Buffer.concat([ciph, cipher.final('buffer')]); + + var decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv); + var txt = decipher.update(ciph, 'buffer', 'utf8'); + txt += decipher.final('utf8'); + + assert.equal(txt, plaintext, 'encryption and decryption with key and iv'); } @@ -495,36 +661,38 @@ testCipher3('0123456789abcd0123456789', new Buffer('12345678')); testCipher3(new Buffer('0123456789abcd0123456789'), '12345678'); testCipher3(new Buffer('0123456789abcd0123456789'), new Buffer('12345678')); +testCipher4(new Buffer('0123456789abcd0123456789'), new Buffer('12345678')); + // update() should only take buffers / strings assert.throws(function() { crypto.createHash('sha1').update({foo: 'bar'}); -}, /string or buffer/); +}, /buffer/); // Test Diffie-Hellman with two parties sharing a secret, // using various encodings as we go along var dh1 = crypto.createDiffieHellman(256); -var p1 = dh1.getPrime('base64'); +var p1 = dh1.getPrime('buffer'); var dh2 = crypto.createDiffieHellman(p1, 'base64'); var key1 = dh1.generateKeys(); var key2 = dh2.generateKeys('hex'); var secret1 = dh1.computeSecret(key2, 'hex', 'base64'); -var secret2 = dh2.computeSecret(key1, 'binary', 'base64'); +var secret2 = dh2.computeSecret(key1, 'binary', 'buffer'); -assert.equal(secret1, secret2); +assert.equal(secret1, secret2.toString('base64')); // Create "another dh1" using generated keys from dh1, // and compute secret again -var dh3 = crypto.createDiffieHellman(p1, 'base64'); +var dh3 = crypto.createDiffieHellman(p1, 'buffer'); var privkey1 = dh1.getPrivateKey(); dh3.setPublicKey(key1); dh3.setPrivateKey(privkey1); -assert.equal(dh1.getPrime(), dh3.getPrime()); -assert.equal(dh1.getGenerator(), dh3.getGenerator()); -assert.equal(dh1.getPublicKey(), dh3.getPublicKey()); -assert.equal(dh1.getPrivateKey(), dh3.getPrivateKey()); +assert.deepEqual(dh1.getPrime(), dh3.getPrime()); +assert.deepEqual(dh1.getGenerator(), dh3.getGenerator()); +assert.deepEqual(dh1.getPublicKey(), dh3.getPublicKey()); +assert.deepEqual(dh1.getPrivateKey(), dh3.getPrivateKey()); var secret3 = dh3.computeSecret(key2, 'hex', 'base64'); @@ -534,6 +702,16 @@ assert.throws(function() { dh3.computeSecret(''); }, /key is too small/i); +// Create a shared using a DH group. +var alice = crypto.createDiffieHellmanGroup('modp5'); +var bob = crypto.createDiffieHellmanGroup('modp5'); +alice.generateKeys(); +bob.generateKeys(); +var aSecret = alice.computeSecret(bob.getPublicKey()).toString('hex'); +var bSecret = bob.computeSecret(alice.getPublicKey()).toString('hex'); +assert.equal(aSecret, bSecret); + + // https://github.com/joyent/node/issues/2338 assert.throws(function() { var p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' + @@ -622,46 +800,68 @@ assert.strictEqual(rsaVerify.verify(rsaPubPem, rsaSignature, 'hex'), true); // // Test PBKDF2 with RFC 6070 test vectors (except #4) // -crypto.pbkdf2('password', 'salt', 1, 20, function(err, result) { - assert.equal(result, - '\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24' + - '\xaf\x60\x12\x06\x2f\xe0\x37\xa6', - 'pbkdf1 test vector 1'); -}); +function testPBKDF2(password, salt, iterations, keylen, expected) { + var actual = crypto.pbkdf2Sync(password, salt, iterations, keylen); + assert.equal(actual.toString('binary'), expected); -crypto.pbkdf2('password', 'salt', 2, 20, function(err, result) { - assert.equal(result, - '\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a' + - '\xce\x1d\x41\xf0\xd8\xde\x89\x57', - 'pbkdf1 test vector 2'); -}); + crypto.pbkdf2(password, salt, iterations, keylen, function(err, actual) { + assert.equal(actual.toString('binary'), expected); + }); +} -crypto.pbkdf2('password', 'salt', 4096, 20, function(err, result) { - assert.equal(result, - '\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26' + - '\xf7\x21\xd0\x65\xa4\x29\xc1', - 'pbkdf1 test vector 3'); -}); -crypto.pbkdf2( - 'passwordPASSWORDpassword', - 'saltSALTsaltSALTsaltSALTsaltSALTsalt', - 4096, - 25, function(err, result) { - assert.equal(result, - '\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62' + - '\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38', - 'pbkdf1 test vector 5'); - }); - -crypto.pbkdf2('pass\0word', 'sa\0lt', 4096, 16, function(err, result) { - assert.equal(result, - '\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34' + - '\x25\xe0\xc3', - 'pbkdf1 test vector 6'); -}); +testPBKDF2('password', 'salt', 1, 20, + '\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24' + + '\xaf\x60\x12\x06\x2f\xe0\x37\xa6'); -// Error path should not leak memory (check with valgrind). -assert.throws(function() { - crypto.pbkdf2('password', 'salt', 1, 20, null); -}); +testPBKDF2('password', 'salt', 2, 20, + '\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a' + + '\xce\x1d\x41\xf0\xd8\xde\x89\x57'); + +testPBKDF2('password', 'salt', 4096, 20, + '\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26' + + '\xf7\x21\xd0\x65\xa4\x29\xc1'); + +testPBKDF2('passwordPASSWORDpassword', + 'saltSALTsaltSALTsaltSALTsaltSALTsalt', + 4096, + 25, + '\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62' + + '\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38'); + +testPBKDF2('pass\0word', 'sa\0lt', 4096, 16, + '\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34' + + '\x25\xe0\xc3'); + +function assertSorted(list) { + for (var i = 0, k = list.length - 1; i < k; ++i) { + var a = list[i + 0]; + var b = list[i + 1]; + assert(a <= b); + } +} + +// Assume that we have at least AES256-SHA. +assert.notEqual(0, crypto.getCiphers()); +assert.notEqual(-1, crypto.getCiphers().indexOf('AES256-SHA')); +assertSorted(crypto.getCiphers()); + +// Assert that we have sha and sha1 but not SHA and SHA1. +assert.notEqual(0, crypto.getHashes()); +assert.notEqual(-1, crypto.getHashes().indexOf('sha1')); +assert.notEqual(-1, crypto.getHashes().indexOf('sha')); +assert.equal(-1, crypto.getHashes().indexOf('SHA1')); +assert.equal(-1, crypto.getHashes().indexOf('SHA')); +assertSorted(crypto.getHashes()); + +(function() { + var c = crypto.createDecipher('aes-128-ecb', ''); + assert.throws(function() { c.final('utf8') }, /invalid public key/); +})(); + +// Base64 padding regression test, see #4837. +(function() { + var c = crypto.createCipher('aes-256-cbc', 'secret'); + var s = c.update('test', 'utf8', 'base64') + c.final('base64'); + assert.equal(s, '375oxUQCIocvxmC5At+rvA=='); +})(); |