Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

OpenSSL EVP API Fix (ECB mode failing) #1997

Closed
wants to merge 8 commits into from
55 changes: 33 additions & 22 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ int Connection::SelectNextProtoCallback_(SSL *s,
}

return SSL_TLSEXT_ERR_OK;
}
}
#endif

#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
Expand Down Expand Up @@ -1827,15 +1827,19 @@ class Cipher : public ObjectWrap {
}

unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH];
int key_len = EVP_BytesToKey(cipher, EVP_md5(), NULL, (unsigned char*) key_buf, key_buf_len, 1, key, iv);
int key_len = EVP_BytesToKey(cipher, EVP_md5(), NULL,
(unsigned char*) key_buf, key_buf_len, 1, key, iv);

EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit(&ctx,cipher,(unsigned char *)key,(unsigned char *)iv, true);
if (!EVP_CIPHER_CTX_set_key_length(&ctx,key_len)) {
EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true);
if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
EVP_CIPHER_CTX_cleanup(&ctx);
return false;
}
EVP_CipherInit_ex(&ctx, NULL, NULL,
(unsigned char *)key,
(unsigned char *)iv, true);
initialised_ = true;
return true;
}
Expand All @@ -1851,17 +1855,23 @@ class Cipher : public ObjectWrap {
fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
return false;
}
if (EVP_CIPHER_iv_length(cipher)!=iv_len) {
/* OpenSSL versions up to 0.9.8l failed to return the correct
iv_length (0) for ECB ciphers */
if (EVP_CIPHER_iv_length(cipher) != iv_len &&
!(EVP_CIPHER_mode(cipher) == EVP_CIPH_ECB_MODE && iv_len == 0)) {
fprintf(stderr, "node-crypto : Invalid IV length %d\n", iv_len);
return false;
}
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit(&ctx,cipher,(unsigned char *)key,(unsigned char *)iv, true);
if (!EVP_CIPHER_CTX_set_key_length(&ctx,key_len)) {
EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true);
if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
EVP_CIPHER_CTX_cleanup(&ctx);
return false;
}
EVP_CipherInit_ex(&ctx, NULL, NULL,
(unsigned char *)key,
(unsigned char *)iv, true);
initialised_ = true;
return true;
}
Expand All @@ -1879,7 +1889,7 @@ class Cipher : public ObjectWrap {
int CipherFinal(unsigned char** out, int *out_len) {
if (!initialised_) return 0;
*out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)];
EVP_CipherFinal(&ctx,*out,out_len);
EVP_CipherFinal_ex(&ctx,*out,out_len);
EVP_CIPHER_CTX_cleanup(&ctx);
initialised_ = false;
return 1;
Expand Down Expand Up @@ -2198,16 +2208,15 @@ class Decipher : public ObjectWrap {
iv);

EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit(&ctx,
cipher_,
(unsigned char*)(key),
(unsigned char *)(iv),
false);
if (!EVP_CIPHER_CTX_set_key_length(&ctx,key_len)) {
EVP_CipherInit_ex(&ctx, cipher_, NULL, NULL, NULL, false);
if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
EVP_CIPHER_CTX_cleanup(&ctx);
return false;
}
EVP_CipherInit_ex(&ctx, NULL, NULL,
(unsigned char *)key,
(unsigned char *)iv, false);
initialised_ = true;
return true;
}
Expand All @@ -2223,21 +2232,23 @@ class Decipher : public ObjectWrap {
fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
return false;
}
if (EVP_CIPHER_iv_length(cipher_) != iv_len) {
/* OpenSSL versions up to 0.9.8l failed to return the correct
iv_length (0) for ECB ciphers */
if (EVP_CIPHER_iv_length(cipher_) != iv_len &&
!(EVP_CIPHER_mode(cipher_) == EVP_CIPH_ECB_MODE && iv_len == 0)) {
fprintf(stderr, "node-crypto : Invalid IV length %d\n", iv_len);
return false;
}
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit(&ctx,
cipher_,
(unsigned char*)(key),
(unsigned char *)(iv),
false);
if (!EVP_CIPHER_CTX_set_key_length(&ctx,key_len)) {
EVP_CipherInit_ex(&ctx, cipher_, NULL, NULL, NULL, false);
if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
EVP_CIPHER_CTX_cleanup(&ctx);
return false;
}
EVP_CipherInit_ex(&ctx, NULL, NULL,
(unsigned char *)key,
(unsigned char *)iv, false);
initialised_ = true;
return true;
}
Expand All @@ -2258,7 +2269,7 @@ class Decipher : public ObjectWrap {
if (tolerate_padding) {
local_EVP_DecryptFinal_ex(&ctx,*out,out_len);
} else {
EVP_CipherFinal(&ctx,*out,out_len);
EVP_CipherFinal_ex(&ctx,*out,out_len);
}
EVP_CIPHER_CTX_cleanup(&ctx);
initialised_ = false;
Expand Down
52 changes: 52 additions & 0 deletions test/simple/test-crypto-ecb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.




var common = require('../common');
var assert = require('assert');

try {
var crypto = require('crypto');
} catch (e) {
console.log('Not compiled with OPENSSL support.');
process.exit();
}

// Testing whether EVP_CipherInit_ex is functioning correctly.
// Reference: bug#1997

(function()
{
var encrypt = crypto.createCipheriv('BF-ECB', 'SomeRandomBlahz0c5GZVnR', '');
var hex = encrypt.update('Hello World!', 'ascii', 'hex');
hex += encrypt.final('hex');
assert.equal(hex.toUpperCase(), '6D385F424AAB0CFBF0BB86E07FFB7D71');
}());

(function()
{
var decrypt = crypto.createDecipheriv('BF-ECB', 'SomeRandomBlahz0c5GZVnR', '');
var msg = decrypt.update('6D385F424AAB0CFBF0BB86E07FFB7D71', 'hex', 'ascii');
msg += decrypt.final('ascii');
assert.equal(msg, 'Hello World!');
}());