Skip to content

Commit

Permalink
crypto: allow passing null as IV unless required
Browse files Browse the repository at this point in the history
  • Loading branch information
tniessen committed Feb 7, 2018
1 parent bff5d5b commit 30efdad
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 8 deletions.
4 changes: 2 additions & 2 deletions lib/internal/crypto/cipher.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ function Cipheriv(cipher, key, iv, options) {
}

iv = toBuf(iv);
if (!isArrayBufferView(iv)) {
if (iv !== null && !isArrayBufferView(iv)) {
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'iv',
['string', 'Buffer', 'TypedArray', 'DataView']);
}
Expand Down Expand Up @@ -253,7 +253,7 @@ function Decipheriv(cipher, key, iv, options) {
}

iv = toBuf(iv);
if (!isArrayBufferView(iv)) {
if (iv !== null && !isArrayBufferView(iv)) {
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'iv',
['string', 'Buffer', 'TypedArray', 'DataView']);
}
Expand Down
22 changes: 19 additions & 3 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3090,8 +3090,17 @@ void CipherBase::InitIv(const char* cipher_type,
const int expected_iv_len = EVP_CIPHER_iv_length(cipher);
const int mode = EVP_CIPHER_mode(cipher);
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");
}

Expand Down Expand Up @@ -3135,8 +3144,15 @@ void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {
const node::Utf8Value cipher_type(env->isolate(), args[0]);
ssize_t key_len = Buffer::Length(args[1]);
const char* key_buf = Buffer::Data(args[1]);
ssize_t iv_len = Buffer::Length(args[2]);
const char* iv_buf = Buffer::Data(args[2]);
ssize_t iv_len;
const char* iv_buf;
if (args[2]->IsNullOrUndefined()) {
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);
}

Expand Down
12 changes: 9 additions & 3 deletions test/parallel/test-crypto-cipheriv-decipheriv.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function testCipher3(key, iv) {
});

common.expectsError(
() => crypto.createCipheriv('des-ede3-cbc', key, null),
() => crypto.createCipheriv('des-ede3-cbc', key, 10),
{
code: 'ERR_INVALID_ARG_TYPE',
type: TypeError,
Expand Down Expand Up @@ -141,7 +141,7 @@ function testCipher3(key, iv) {
});

common.expectsError(
() => crypto.createDecipheriv('des-ede3-cbc', key, null),
() => crypto.createDecipheriv('des-ede3-cbc', key, 10),
{
code: 'ERR_INVALID_ARG_TYPE',
type: TypeError,
Expand All @@ -161,8 +161,9 @@ if (!common.hasFipsCrypto) {
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), null);

const errMessage = /Invalid IV length/;

Expand All @@ -186,6 +187,11 @@ for (let n = 0; n < 256; n += 1) {
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.
assert.throws(
() => crypto.createCipheriv('aes-128-gcm', Buffer.alloc(16),
Expand Down

0 comments on commit 30efdad

Please sign in to comment.