GeezerVison is showing github.com — crypto: always accept private keys as public keys · nodejs/node@eaaaa0d
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/crypto.md +16Lines changed: 16 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1379,6 +1379,9 @@ This can be called many times with new data as it is streamed. | 1379 | 1379 | <!-- YAML | 1380 | 1380 | added: v0.1.92 | 1381 | 1381 | changes: | | 1382 | + - version: REPLACEME | | 1383 | + pr-url: https://github.com/nodejs/node/pull/25217 | | 1384 | + description: The key can now be a private key. | 1382 | 1385 | - version: v8.0.0 | 1383 | 1386 | pr-url: https://github.com/nodejs/node/pull/11705 | 1384 | 1387 | description: Support for RSASSA-PSS and additional options was added. | @@ -1419,6 +1422,9 @@ The `verify` object can not be used again after `verify.verify()` has been | 1419 | 1422 | called. Multiple calls to `verify.verify()` will result in an error being | 1420 | 1423 | thrown. | 1421 | 1424 |
| | 1425 | +Because public keys can be derived from private keys, a private key may | | 1426 | +be passed instead of a public key. | | 1427 | + | 1422 | 1428 | ## `crypto` module methods and properties | 1423 | 1429 |
| 1424 | 1430 | ### crypto.constants | @@ -1829,6 +1835,10 @@ must be an object with the properties described above. | 1829 | 1835 | ### crypto.createPublicKey(key) | 1830 | 1836 | <!-- YAML | 1831 | 1837 | added: v11.6.0 | | 1838 | +changes: | | 1839 | + - version: REPLACEME | | 1840 | + pr-url: https://github.com/nodejs/node/pull/25217 | | 1841 | + description: The `key` argument can now be a private key. | 1832 | 1842 | --> | 1833 | 1843 | * `key` {Object | string | Buffer} | 1834 | 1844 | - `key`: {string | Buffer} | @@ -1843,6 +1853,12 @@ must be an object with the properties described above. | 1843 | 1853 |
| 1844 | 1854 | If the format is `'pem'`, the `'key'` may also be an X.509 certificate. | 1845 | 1855 |
| | 1856 | +Because public keys can be derived from private keys, a private key may be | | 1857 | +passed instead of a public key. In that case, this function behaves as if | | 1858 | +[`crypto.createPrivateKey()`][] had been called, except that the type of the | | 1859 | +returned `KeyObject` will be `public` and that the private key cannot be | | 1860 | +extracted from the returned `KeyObject`. | | 1861 | + | 1846 | 1862 | ### crypto.createSecretKey(key) | 1847 | 1863 | <!-- YAML | 1848 | 1864 | added: v11.6.0 | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/crypto/keys.js +1-6Lines changed: 1 addition & 6 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -261,10 +261,6 @@ function prepareAsymmetricKey(key, isPublic, allowKeyObject = true) { | 261 | 261 | } | 262 | 262 | } | 263 | 263 |
| 264 | | -function preparePublicKey(key, allowKeyObject) { | 265 | | - return prepareAsymmetricKey(key, true, allowKeyObject); | 266 | | -} | 267 | | - | 268 | 264 | function preparePrivateKey(key, allowKeyObject) { | 269 | 265 | return prepareAsymmetricKey(key, false, allowKeyObject); | 270 | 266 | } | @@ -300,7 +296,7 @@ function createSecretKey(key) { | 300 | 296 | } | 301 | 297 |
| 302 | 298 | function createPublicKey(key) { | 303 | | - const { format, type, data } = preparePublicKey(key, false); | | 299 | + const { format, type, data } = preparePublicOrPrivateKey(key, false); | 304 | 300 | const handle = new KeyObjectHandle(kKeyTypePublic); | 305 | 301 | handle.init(data, format, type); | 306 | 302 | return new PublicKeyObject(handle); | @@ -326,7 +322,6 @@ module.exports = { | 326 | 322 | // These are designed for internal use only and should not be exposed. | 327 | 323 | parsePublicKeyEncoding, | 328 | 324 | parsePrivateKeyEncoding, | 329 | | - preparePublicKey, | 330 | 325 | preparePrivateKey, | 331 | 326 | preparePublicOrPrivateKey, | 332 | 327 | prepareSecretKey, | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/crypto/sig.js +5-4Lines changed: 5 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -19,7 +19,7 @@ const { | 19 | 19 | } = require('internal/crypto/util'); | 20 | 20 | const { | 21 | 21 | preparePrivateKey, | 22 | | - preparePublicKey | | 22 | + preparePublicOrPrivateKey | 23 | 23 | } = require('internal/crypto/keys'); | 24 | 24 | const { Writable } = require('stream'); | 25 | 25 | const { inherits } = require('util'); | @@ -111,8 +111,9 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { | 111 | 111 | const { | 112 | 112 | data, | 113 | 113 | format, | 114 | | - type | 115 | | - } = preparePublicKey(options, true); | | 114 | + type, | | 115 | + passphrase | | 116 | + } = preparePublicOrPrivateKey(options, true); | 116 | 117 |
| 117 | 118 | sigEncoding = sigEncoding || getDefaultEncoding(); | 118 | 119 |
| @@ -124,7 +125,7 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { | 124 | 125 | signature = validateArrayBufferView(toBuf(signature, sigEncoding), | 125 | 126 | 'signature'); | 126 | 127 |
| 127 | | - return this[kHandle].verify(data, format, type, signature, | | 128 | + return this[kHandle].verify(data, format, type, passphrase, signature, | 128 | 129 | rsaPadding, pssSaltLength); | 129 | 130 | }; | 130 | 131 |
| |
Collapse file Copy file name to clipboardExpand all lines: src/node_crypto.cc +2-26Lines changed: 2 additions & 26 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -2995,30 +2995,6 @@ static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs( | 2995 | 2995 | return result; | 2996 | 2996 | } | 2997 | 2997 |
| 2998 | | -static ManagedEVPPKey GetPublicKeyFromJs( | 2999 | | - const FunctionCallbackInfo<Value>& args, | 3000 | | - unsigned int* offset, | 3001 | | - bool allow_key_object) { | 3002 | | - if (args[*offset]->IsString() || Buffer::HasInstance(args[*offset])) { | 3003 | | - Environment* env = Environment::GetCurrent(args); | 3004 | | - ByteSource key = ByteSource::FromStringOrBuffer(env, args[(*offset)++]); | 3005 | | - PublicKeyEncodingConfig config = | 3006 | | - GetPublicKeyEncodingFromJs(args, offset, kKeyContextInput); | 3007 | | - EVPKeyPointer pkey; | 3008 | | - ParsePublicKey(&pkey, config, key.get(), key.size()); | 3009 | | - if (!pkey) | 3010 | | - ThrowCryptoError(env, ERR_get_error(), "Failed to read public key"); | 3011 | | - return ManagedEVPPKey(pkey.release()); | 3012 | | - } else { | 3013 | | - CHECK(args[*offset]->IsObject() && allow_key_object); | 3014 | | - KeyObject* key; | 3015 | | - ASSIGN_OR_RETURN_UNWRAP(&key, args[*offset].As<Object>(), ManagedEVPPKey()); | 3016 | | - CHECK_EQ(key->GetKeyType(), kKeyTypePublic); | 3017 | | - (*offset) += 3; | 3018 | | - return key->GetAsymmetricKey(); | 3019 | | - } | 3020 | | -} | 3021 | | - | 3022 | 2998 | static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs( | 3023 | 2999 | const FunctionCallbackInfo<Value>& args, | 3024 | 3000 | unsigned int* offset, | @@ -3380,7 +3356,7 @@ void KeyObject::Init(const FunctionCallbackInfo<Value>& args) { | 3380 | 3356 | CHECK_EQ(args.Length(), 3); | 3381 | 3357 |
| 3382 | 3358 | offset = 0; | 3383 | | - pkey = GetPublicKeyFromJs(args, &offset, false); | | 3359 | + pkey = GetPublicOrPrivateKeyFromJs(args, &offset, false); | 3384 | 3360 | if (!pkey) | 3385 | 3361 | return; | 3386 | 3362 | key->InitPublic(pkey); | @@ -4662,7 +4638,7 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) { | 4662 | 4638 | ASSIGN_OR_RETURN_UNWRAP(&verify, args.Holder()); | 4663 | 4639 |
| 4664 | 4640 | unsigned int offset = 0; | 4665 | | - ManagedEVPPKey pkey = GetPublicKeyFromJs(args, &offset, true); | | 4641 | + ManagedEVPPKey pkey = GetPublicOrPrivateKeyFromJs(args, &offset, true); | 4666 | 4642 |
| 4667 | 4643 | char* hbuf = Buffer::Data(args[offset]); | 4668 | 4644 | ssize_t hlen = Buffer::Length(args[offset]); | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-crypto-keygen.js +10-6Lines changed: 10 additions & 6 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -31,19 +31,23 @@ function assertApproximateSize(key, expectedSize) { | 31 | 31 | function testEncryptDecrypt(publicKey, privateKey) { | 32 | 32 | const message = 'Hello Node.js world!'; | 33 | 33 | const plaintext = Buffer.from(message, 'utf8'); | 34 | | - const ciphertext = publicEncrypt(publicKey, plaintext); | 35 | | - const received = privateDecrypt(privateKey, ciphertext); | 36 | | - assert.strictEqual(received.toString('utf8'), message); | | 34 | + for (const key of [publicKey, privateKey]) { | | 35 | + const ciphertext = publicEncrypt(key, plaintext); | | 36 | + const received = privateDecrypt(privateKey, ciphertext); | | 37 | + assert.strictEqual(received.toString('utf8'), message); | | 38 | + } | 37 | 39 | } | 38 | 40 |
| 39 | 41 | // Tests that a key pair can be used for signing / verification. | 40 | 42 | function testSignVerify(publicKey, privateKey) { | 41 | 43 | const message = 'Hello Node.js world!'; | 42 | 44 | const signature = createSign('SHA256').update(message) | 43 | 45 | .sign(privateKey, 'hex'); | 44 | | - const okay = createVerify('SHA256').update(message) | 45 | | - .verify(publicKey, signature, 'hex'); | 46 | | - assert(okay); | | 46 | + for (const key of [publicKey, privateKey]) { | | 47 | + const okay = createVerify('SHA256').update(message) | | 48 | + .verify(key, signature, 'hex'); | | 49 | + assert(okay); | | 50 | + } | 47 | 51 | } | 48 | 52 |
| 49 | 53 | // Constructs a regular expression for a PEM-encoded key with the given label. | |
|