From 34d67085d5c1d090e056ce62a5c4b0440f4a2b06 Mon Sep 17 00:00:00 2001 From: Yihong Wang Date: Thu, 26 Apr 2018 16:15:12 -0700 Subject: [PATCH] crypto: allocate more memory for cipher.update() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For key wrapping algorithms, calling EVP_CipherUpdate() with null output could obtain the size for the ciphertext. Then use the returned size to allocate output buffer. Also add a test case to verify des3-wrap. Signed-off-by: Yihong Wang Backport-PR-URL: https://github.com/nodejs/node/pull/20706 PR-URL: https://github.com/nodejs/node/pull/20370 Fixes: https://github.com/nodejs/node/issues/19655 Reviewed-By: Tobias Nießen Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell --- src/node_crypto.cc | 18 ++++++++++++++++-- test/parallel/test-crypto-des3-wrap.js | 25 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-crypto-des3-wrap.js diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 3fc753e2dae1da..bcdb1deb583272 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3032,14 +3032,28 @@ CipherBase::UpdateResult CipherBase::Update(const char* data, auth_tag_set_ = true; } - *out_len = len + EVP_CIPHER_CTX_block_size(ctx_); - *out = Malloc(static_cast(*out_len)); + *out_len = 0; + int buff_len = len + EVP_CIPHER_CTX_block_size(ctx_); + // For key wrapping algorithms, get output size by calling + // EVP_CipherUpdate() with null output. + if (mode == EVP_CIPH_WRAP_MODE && + EVP_CipherUpdate(ctx_, + nullptr, + &buff_len, + reinterpret_cast(data), + len) != 1) { + return kErrorState; + } + + *out = Malloc(buff_len); int r = EVP_CipherUpdate(ctx_, *out, out_len, reinterpret_cast(data), len); + CHECK_LE(*out_len, buff_len); + // When in CCM mode, EVP_CipherUpdate will fail if the authentication tag is // invalid. In that case, remember the error and throw in final(). if (!r && kind_ == kDecipher && mode == EVP_CIPH_CCM_MODE) { diff --git a/test/parallel/test-crypto-des3-wrap.js b/test/parallel/test-crypto-des3-wrap.js new file mode 100644 index 00000000000000..75c8cd574fd662 --- /dev/null +++ b/test/parallel/test-crypto-des3-wrap.js @@ -0,0 +1,25 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const crypto = require('crypto'); + +// Test case for des-ede3 wrap/unwrap. des3-wrap needs extra 2x blocksize +// then plaintext to store ciphertext. +const test = { + key: Buffer.from('3c08e25be22352910671cfe4ba3652b1220a8a7769b490ba', 'hex'), + iv: Buffer.alloc(0), + plaintext: '32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBG' + + 'WWELweCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZU' + + 'JjAfaFg**' +}; + +const cipher = crypto.createCipheriv('des3-wrap', test.key, test.iv); +const ciphertext = cipher.update(test.plaintext, 'utf8'); + +const decipher = crypto.createDecipheriv('des3-wrap', test.key, test.iv); +const msg = decipher.update(ciphertext, 'buffer', 'utf8'); + +assert.strictEqual(msg, test.plaintext);