Browse Source

crypto: fix error of createCipher in wrap mode

EVP_CIPHER_CTX_FLAG_WRAP_ALLOW flag needs to be set in using wrap mode
ciphers. In `crypto.createCipher()`, AES key wrap mode does not use a
default IV defined in RFC3394 but a generated IV with
`EVP_BytesToKey()` to be consistent API behaviors with other ciphers.

The built-in AES wrap mode in OpenSSL is not supported in FIPS mode as
http://openssl.6102.n7.nabble.com/AES-Key-Wrap-in-FIPS-Mode-td50238.html
so its tests in FIPS mode are skipped.

Fixes: https://github.com/nodejs/node/issues/15009
PR-URL: https://github.com/nodejs/node/pull/15037
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: James M Snell <jasnell@gmail.com>
canary-base
Shigeki Ohtsu 8 years ago
parent
commit
4218f1974d
  1. 10
      src/node_crypto.cc
  2. 21
      test/parallel/test-crypto-binary-default.js
  3. 24
      test/parallel/test-crypto-cipheriv-decipheriv.js

10
src/node_crypto.cc

@ -3349,6 +3349,9 @@ void CipherBase::Init(const char* cipher_type,
cipher_type); cipher_type);
} }
if (mode == EVP_CIPH_WRAP_MODE)
EVP_CIPHER_CTX_set_flags(&ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) { if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) {
EVP_CIPHER_CTX_cleanup(&ctx_); EVP_CIPHER_CTX_cleanup(&ctx_);
return env()->ThrowError("Invalid key length"); return env()->ThrowError("Invalid key length");
@ -3396,13 +3399,18 @@ 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 bool is_gcm_mode = (EVP_CIPH_GCM_MODE == EVP_CIPHER_mode(cipher)); const int mode = EVP_CIPHER_mode(cipher);
const bool is_gcm_mode = (EVP_CIPH_GCM_MODE == mode);
if (is_gcm_mode == false && iv_len != expected_iv_len) { if (is_gcm_mode == false && iv_len != expected_iv_len) {
return env()->ThrowError("Invalid IV length"); return env()->ThrowError("Invalid IV length");
} }
EVP_CIPHER_CTX_init(&ctx_); EVP_CIPHER_CTX_init(&ctx_);
if (mode == EVP_CIPH_WRAP_MODE)
EVP_CIPHER_CTX_set_flags(&ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
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);

21
test/parallel/test-crypto-binary-default.js

@ -530,12 +530,33 @@ function testCipher4(key, iv) {
'encryption and decryption with key and iv'); 'encryption and decryption with key and iv');
} }
function testCipher5(key, iv) {
// Test encryption and decryption with explicit key with aes128-wrap
const plaintext =
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
'jAfaFg**';
const cipher = crypto.createCipher('id-aes128-wrap', key);
let ciph = cipher.update(plaintext, 'utf8', 'buffer');
ciph = Buffer.concat([ciph, cipher.final('buffer')]);
const decipher = crypto.createDecipher('id-aes128-wrap', key);
let txt = decipher.update(ciph, 'buffer', 'utf8');
txt += decipher.final('utf8');
assert.strictEqual(txt, plaintext,
'encryption and decryption with key');
}
if (!common.hasFipsCrypto) { if (!common.hasFipsCrypto) {
testCipher1('MySecretKey123'); testCipher1('MySecretKey123');
testCipher1(Buffer.from('MySecretKey123')); testCipher1(Buffer.from('MySecretKey123'));
testCipher2('0123456789abcdef'); testCipher2('0123456789abcdef');
testCipher2(Buffer.from('0123456789abcdef')); testCipher2(Buffer.from('0123456789abcdef'));
testCipher5(Buffer.from('0123456789abcd0123456789'));
} }
testCipher3('0123456789abcd0123456789', '12345678'); testCipher3('0123456789abcd0123456789', '12345678');

24
test/parallel/test-crypto-cipheriv-decipheriv.js

@ -55,12 +55,36 @@ function testCipher2(key, iv) {
assert.strictEqual(txt, plaintext, 'encryption/decryption with key and iv'); assert.strictEqual(txt, plaintext, 'encryption/decryption with key and iv');
} }
function testCipher3(key, iv) {
// Test encryption and decryption with explicit key and iv.
// AES Key Wrap test vector comes from RFC3394
const plaintext = Buffer.from('00112233445566778899AABBCCDDEEFF', 'hex');
const cipher = crypto.createCipheriv('id-aes128-wrap', key, iv);
let ciph = cipher.update(plaintext, 'utf8', 'buffer');
ciph = Buffer.concat([ciph, cipher.final('buffer')]);
const ciph2 = Buffer.from('1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5',
'hex');
assert(ciph.equals(ciph2));
const decipher = crypto.createDecipheriv('id-aes128-wrap', key, iv);
let deciph = decipher.update(ciph, 'buffer');
deciph = Buffer.concat([deciph, decipher.final()]);
assert(deciph.equals(plaintext), 'encryption/decryption with key and iv');
}
testCipher1('0123456789abcd0123456789', '12345678'); testCipher1('0123456789abcd0123456789', '12345678');
testCipher1('0123456789abcd0123456789', Buffer.from('12345678')); testCipher1('0123456789abcd0123456789', Buffer.from('12345678'));
testCipher1(Buffer.from('0123456789abcd0123456789'), '12345678'); testCipher1(Buffer.from('0123456789abcd0123456789'), '12345678');
testCipher1(Buffer.from('0123456789abcd0123456789'), Buffer.from('12345678')); testCipher1(Buffer.from('0123456789abcd0123456789'), Buffer.from('12345678'));
testCipher2(Buffer.from('0123456789abcd0123456789'), Buffer.from('12345678')); testCipher2(Buffer.from('0123456789abcd0123456789'), Buffer.from('12345678'));
if (!common.hasFipsCrypto) {
testCipher3(Buffer.from('000102030405060708090A0B0C0D0E0F', 'hex'),
Buffer.from('A6A6A6A6A6A6A6A6', 'hex'));
}
// Zero-sized IV should be accepted in ECB mode. // Zero-sized IV 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));

Loading…
Cancel
Save