crypto: allow passing null as IV unless required
PR-URL: https://github.com/nodejs/node/pull/18644 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
cf52ab19dc
commit
38bac4266a
@ -1286,6 +1286,11 @@ Adversaries][] for details.
|
|||||||
### crypto.createCipheriv(algorithm, key, iv[, options])
|
### crypto.createCipheriv(algorithm, key, iv[, options])
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.1.94
|
added: v0.1.94
|
||||||
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/18644
|
||||||
|
description: The `iv` parameter may now be `null` for ciphers which do not
|
||||||
|
need an initialization vector.
|
||||||
-->
|
-->
|
||||||
- `algorithm` {string}
|
- `algorithm` {string}
|
||||||
- `key` {string | Buffer | TypedArray | DataView}
|
- `key` {string | Buffer | TypedArray | DataView}
|
||||||
@ -1301,7 +1306,8 @@ available cipher algorithms.
|
|||||||
|
|
||||||
The `key` is the raw key used by the `algorithm` and `iv` is an
|
The `key` is the raw key used by the `algorithm` and `iv` is an
|
||||||
[initialization vector][]. Both arguments must be `'utf8'` encoded strings,
|
[initialization vector][]. Both arguments must be `'utf8'` encoded strings,
|
||||||
[Buffers][`Buffer`], `TypedArray`, or `DataView`s.
|
[Buffers][`Buffer`], `TypedArray`, or `DataView`s. If the cipher does not need
|
||||||
|
an initialization vector, `iv` may be `null`.
|
||||||
|
|
||||||
### crypto.createCredentials(details)
|
### crypto.createCredentials(details)
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
@ -1347,6 +1353,11 @@ to create the `Decipher` object.
|
|||||||
### crypto.createDecipheriv(algorithm, key, iv[, options])
|
### crypto.createDecipheriv(algorithm, key, iv[, options])
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.1.94
|
added: v0.1.94
|
||||||
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/18644
|
||||||
|
description: The `iv` parameter may now be `null` for ciphers which do not
|
||||||
|
need an initialization vector.
|
||||||
-->
|
-->
|
||||||
- `algorithm` {string}
|
- `algorithm` {string}
|
||||||
- `key` {string | Buffer | TypedArray | DataView}
|
- `key` {string | Buffer | TypedArray | DataView}
|
||||||
@ -1363,7 +1374,8 @@ available cipher algorithms.
|
|||||||
|
|
||||||
The `key` is the raw key used by the `algorithm` and `iv` is an
|
The `key` is the raw key used by the `algorithm` and `iv` is an
|
||||||
[initialization vector][]. Both arguments must be `'utf8'` encoded strings,
|
[initialization vector][]. Both arguments must be `'utf8'` encoded strings,
|
||||||
[Buffers][`Buffer`], `TypedArray`, or `DataView`s.
|
[Buffers][`Buffer`], `TypedArray`, or `DataView`s. If the cipher does not need
|
||||||
|
an initialization vector, `iv` may be `null`.
|
||||||
|
|
||||||
### crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])
|
### crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -182,7 +182,7 @@ function Cipheriv(cipher, key, iv, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
iv = toBuf(iv);
|
iv = toBuf(iv);
|
||||||
if (!isArrayBufferView(iv)) {
|
if (iv !== null && !isArrayBufferView(iv)) {
|
||||||
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'iv',
|
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'iv',
|
||||||
['string', 'Buffer', 'TypedArray', 'DataView']);
|
['string', 'Buffer', 'TypedArray', 'DataView']);
|
||||||
}
|
}
|
||||||
@ -253,7 +253,7 @@ function Decipheriv(cipher, key, iv, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
iv = toBuf(iv);
|
iv = toBuf(iv);
|
||||||
if (!isArrayBufferView(iv)) {
|
if (iv !== null && !isArrayBufferView(iv)) {
|
||||||
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'iv',
|
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'iv',
|
||||||
['string', 'Buffer', 'TypedArray', 'DataView']);
|
['string', 'Buffer', 'TypedArray', 'DataView']);
|
||||||
}
|
}
|
||||||
|
@ -3090,8 +3090,17 @@ void CipherBase::InitIv(const char* cipher_type,
|
|||||||
const int expected_iv_len = EVP_CIPHER_iv_length(cipher);
|
const int expected_iv_len = EVP_CIPHER_iv_length(cipher);
|
||||||
const int mode = EVP_CIPHER_mode(cipher);
|
const int mode = EVP_CIPHER_mode(cipher);
|
||||||
const bool is_gcm_mode = (EVP_CIPH_GCM_MODE == mode);
|
const bool is_gcm_mode = (EVP_CIPH_GCM_MODE == mode);
|
||||||
|
const bool has_iv = iv_len >= 0;
|
||||||
|
|
||||||
if (is_gcm_mode == false && iv_len != expected_iv_len) {
|
// Throw if no IV was passed and the cipher requires an IV
|
||||||
|
if (!has_iv && expected_iv_len != 0) {
|
||||||
|
char msg[128];
|
||||||
|
snprintf(msg, sizeof(msg), "Missing IV for cipher %s", cipher_type);
|
||||||
|
return env()->ThrowError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw if an IV was passed which does not match the cipher's fixed IV length
|
||||||
|
if (is_gcm_mode == false && has_iv && iv_len != expected_iv_len) {
|
||||||
return env()->ThrowError("Invalid IV length");
|
return env()->ThrowError("Invalid IV length");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3103,12 +3112,14 @@ void CipherBase::InitIv(const char* cipher_type,
|
|||||||
const bool encrypt = (kind_ == kCipher);
|
const bool encrypt = (kind_ == kCipher);
|
||||||
EVP_CipherInit_ex(ctx_, cipher, nullptr, nullptr, nullptr, encrypt);
|
EVP_CipherInit_ex(ctx_, cipher, nullptr, nullptr, nullptr, encrypt);
|
||||||
|
|
||||||
if (is_gcm_mode &&
|
if (is_gcm_mode) {
|
||||||
!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) {
|
CHECK(has_iv);
|
||||||
|
if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) {
|
||||||
EVP_CIPHER_CTX_free(ctx_);
|
EVP_CIPHER_CTX_free(ctx_);
|
||||||
ctx_ = nullptr;
|
ctx_ = nullptr;
|
||||||
return env()->ThrowError("Invalid IV length");
|
return env()->ThrowError("Invalid IV length");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
|
if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
|
||||||
EVP_CIPHER_CTX_free(ctx_);
|
EVP_CIPHER_CTX_free(ctx_);
|
||||||
@ -3135,8 +3146,15 @@ void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {
|
|||||||
const node::Utf8Value cipher_type(env->isolate(), args[0]);
|
const node::Utf8Value cipher_type(env->isolate(), args[0]);
|
||||||
ssize_t key_len = Buffer::Length(args[1]);
|
ssize_t key_len = Buffer::Length(args[1]);
|
||||||
const char* key_buf = Buffer::Data(args[1]);
|
const char* key_buf = Buffer::Data(args[1]);
|
||||||
ssize_t iv_len = Buffer::Length(args[2]);
|
ssize_t iv_len;
|
||||||
const char* iv_buf = Buffer::Data(args[2]);
|
const char* iv_buf;
|
||||||
|
if (args[2]->IsNull()) {
|
||||||
|
iv_buf = nullptr;
|
||||||
|
iv_len = -1;
|
||||||
|
} else {
|
||||||
|
iv_buf = Buffer::Data(args[2]);
|
||||||
|
iv_len = Buffer::Length(args[2]);
|
||||||
|
}
|
||||||
cipher->InitIv(*cipher_type, key_buf, key_len, iv_buf, iv_len);
|
cipher->InitIv(*cipher_type, key_buf, key_len, iv_buf, iv_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ function testCipher3(key, iv) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
common.expectsError(
|
common.expectsError(
|
||||||
() => crypto.createCipheriv('des-ede3-cbc', key, null),
|
() => crypto.createCipheriv('des-ede3-cbc', key, 10),
|
||||||
{
|
{
|
||||||
code: 'ERR_INVALID_ARG_TYPE',
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
type: TypeError,
|
type: TypeError,
|
||||||
@ -141,7 +141,7 @@ function testCipher3(key, iv) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
common.expectsError(
|
common.expectsError(
|
||||||
() => crypto.createDecipheriv('des-ede3-cbc', key, null),
|
() => crypto.createDecipheriv('des-ede3-cbc', key, 10),
|
||||||
{
|
{
|
||||||
code: 'ERR_INVALID_ARG_TYPE',
|
code: 'ERR_INVALID_ARG_TYPE',
|
||||||
type: TypeError,
|
type: TypeError,
|
||||||
@ -161,8 +161,9 @@ if (!common.hasFipsCrypto) {
|
|||||||
Buffer.from('A6A6A6A6A6A6A6A6', 'hex'));
|
Buffer.from('A6A6A6A6A6A6A6A6', 'hex'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero-sized IV should be accepted in ECB mode.
|
// Zero-sized IV or null should be accepted in ECB mode.
|
||||||
crypto.createCipheriv('aes-128-ecb', Buffer.alloc(16), Buffer.alloc(0));
|
crypto.createCipheriv('aes-128-ecb', Buffer.alloc(16), Buffer.alloc(0));
|
||||||
|
crypto.createCipheriv('aes-128-ecb', Buffer.alloc(16), null);
|
||||||
|
|
||||||
const errMessage = /Invalid IV length/;
|
const errMessage = /Invalid IV length/;
|
||||||
|
|
||||||
@ -186,6 +187,11 @@ for (let n = 0; n < 256; n += 1) {
|
|||||||
errMessage);
|
errMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// And so should null be.
|
||||||
|
assert.throws(() => {
|
||||||
|
crypto.createCipheriv('aes-128-cbc', Buffer.alloc(16), null);
|
||||||
|
}, /Missing IV for cipher aes-128-cbc/);
|
||||||
|
|
||||||
// Zero-sized IV should be rejected in GCM mode.
|
// Zero-sized IV should be rejected in GCM mode.
|
||||||
assert.throws(
|
assert.throws(
|
||||||
() => crypto.createCipheriv('aes-128-gcm', Buffer.alloc(16),
|
() => crypto.createCipheriv('aes-128-gcm', Buffer.alloc(16),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user