diff options
author | Tobias Nießen <tniessen@tnie.de> | 2018-09-20 19:53:44 +0200 |
---|---|---|
committer | Tobias Nießen <tniessen@tnie.de> | 2018-12-24 14:50:16 +0100 |
commit | 823d86c47ce15fba8875fcebd412593b02aab362 (patch) | |
tree | a023dac2cbda38b6e194c7324e501e4054715af5 /test/parallel/test-crypto-key-objects.js | |
parent | 5570df407aae1e329955b1093e0e5b8bde270213 (diff) | |
download | android-node-v8-823d86c47ce15fba8875fcebd412593b02aab362.tar.gz android-node-v8-823d86c47ce15fba8875fcebd412593b02aab362.tar.bz2 android-node-v8-823d86c47ce15fba8875fcebd412593b02aab362.zip |
crypto: add key object API
This commit makes multiple important changes:
1. A new key object API is introduced. The KeyObject class itself is
not exposed to users, instead, several new APIs can be used to
construct key objects: createSecretKey, createPrivateKey and
createPublicKey. The new API also allows to convert between
different key formats, and even though the API itself is not
compatible to the WebCrypto standard in any way, it makes
interoperability much simpler.
2. Key objects can be used instead of the raw key material in all
relevant crypto APIs.
3. The handling of asymmetric keys has been unified and greatly
improved. Node.js now fully supports both PEM-encoded and
DER-encoded public and private keys.
4. Conversions between buffers and strings have been moved to native
code for sensitive data such as symmetric keys due to security
considerations such as zeroing temporary buffers.
5. For compatibility with older versions of the crypto API, this
change allows to specify Buffers and strings as the "passphrase"
option when reading or writing an encoded key. Note that this
can result in unexpected behavior if the password contains a
null byte.
PR-URL: https://github.com/nodejs/node/pull/24234
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'test/parallel/test-crypto-key-objects.js')
-rw-r--r-- | test/parallel/test-crypto-key-objects.js | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/test/parallel/test-crypto-key-objects.js b/test/parallel/test-crypto-key-objects.js new file mode 100644 index 0000000000..dddbd5f270 --- /dev/null +++ b/test/parallel/test-crypto-key-objects.js @@ -0,0 +1,107 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const { + createCipheriv, + createDecipheriv, + createSecretKey, + createPublicKey, + createPrivateKey, + randomBytes, + publicEncrypt, + privateDecrypt +} = require('crypto'); + +const fixtures = require('../common/fixtures'); + +const publicPem = fixtures.readSync('test_rsa_pubkey.pem', 'ascii'); +const privatePem = fixtures.readSync('test_rsa_privkey.pem', 'ascii'); + +{ + // Attempting to create an empty key should throw. + common.expectsError(() => { + createSecretKey(Buffer.alloc(0)); + }, { + type: RangeError, + code: 'ERR_OUT_OF_RANGE', + message: 'The value of "key.byteLength" is out of range. ' + + 'It must be > 0. Received 0' + }); +} + +{ + const keybuf = randomBytes(32); + const key = createSecretKey(keybuf); + assert.strictEqual(key.type, 'secret'); + assert.strictEqual(key.symmetricKeySize, 32); + assert.strictEqual(key.asymmetricKeyType, undefined); + + const exportedKey = key.export(); + assert(keybuf.equals(exportedKey)); + + const plaintext = Buffer.from('Hello world', 'utf8'); + + const cipher = createCipheriv('aes-256-ecb', key, null); + const ciphertext = Buffer.concat([ + cipher.update(plaintext), cipher.final() + ]); + + const decipher = createDecipheriv('aes-256-ecb', key, null); + const deciphered = Buffer.concat([ + decipher.update(ciphertext), decipher.final() + ]); + + assert(plaintext.equals(deciphered)); +} + +{ + const publicKey = createPublicKey(publicPem); + assert.strictEqual(publicKey.type, 'public'); + assert.strictEqual(publicKey.asymmetricKeyType, 'rsa'); + assert.strictEqual(publicKey.symmetricKeySize, undefined); + + const privateKey = createPrivateKey(privatePem); + assert.strictEqual(privateKey.type, 'private'); + assert.strictEqual(privateKey.asymmetricKeyType, 'rsa'); + assert.strictEqual(privateKey.symmetricKeySize, undefined); + + const publicDER = publicKey.export({ + format: 'der', + type: 'pkcs1' + }); + + const privateDER = privateKey.export({ + format: 'der', + type: 'pkcs1' + }); + + assert(Buffer.isBuffer(publicDER)); + assert(Buffer.isBuffer(privateDER)); + + const plaintext = Buffer.from('Hello world', 'utf8'); + const ciphertexts = [ + publicEncrypt(publicKey, plaintext), + publicEncrypt({ key: publicKey }, plaintext), + // Test distinguishing PKCS#1 public and private keys based on the + // DER-encoded data only. + publicEncrypt({ format: 'der', type: 'pkcs1', key: publicDER }, plaintext), + publicEncrypt({ format: 'der', type: 'pkcs1', key: privateDER }, plaintext) + ]; + + const decryptionKeys = [ + privateKey, + { format: 'pem', key: privatePem }, + { format: 'der', type: 'pkcs1', key: privateDER } + ]; + + for (const ciphertext of ciphertexts) { + for (const key of decryptionKeys) { + const deciphered = privateDecrypt(key, ciphertext); + assert(plaintext.equals(deciphered)); + } + } +} |