Skip to content

Commit 34d6708

Browse files
yhwangaddaleax
authored andcommitted
crypto: allocate more memory for cipher.update()
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 <[email protected]> Backport-PR-URL: #20706 PR-URL: #20370 Fixes: #19655 Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 2b2ccae commit 34d6708

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

src/node_crypto.cc

+16-2
Original file line numberDiff line numberDiff line change
@@ -3032,14 +3032,28 @@ CipherBase::UpdateResult CipherBase::Update(const char* data,
30323032
auth_tag_set_ = true;
30333033
}
30343034

3035-
*out_len = len + EVP_CIPHER_CTX_block_size(ctx_);
3036-
*out = Malloc<unsigned char>(static_cast<size_t>(*out_len));
3035+
*out_len = 0;
3036+
int buff_len = len + EVP_CIPHER_CTX_block_size(ctx_);
3037+
// For key wrapping algorithms, get output size by calling
3038+
// EVP_CipherUpdate() with null output.
3039+
if (mode == EVP_CIPH_WRAP_MODE &&
3040+
EVP_CipherUpdate(ctx_,
3041+
nullptr,
3042+
&buff_len,
3043+
reinterpret_cast<const unsigned char*>(data),
3044+
len) != 1) {
3045+
return kErrorState;
3046+
}
3047+
3048+
*out = Malloc<unsigned char>(buff_len);
30373049
int r = EVP_CipherUpdate(ctx_,
30383050
*out,
30393051
out_len,
30403052
reinterpret_cast<const unsigned char*>(data),
30413053
len);
30423054

3055+
CHECK_LE(*out_len, buff_len);
3056+
30433057
// When in CCM mode, EVP_CipherUpdate will fail if the authentication tag is
30443058
// invalid. In that case, remember the error and throw in final().
30453059
if (!r && kind_ == kDecipher && mode == EVP_CIPH_CCM_MODE) {
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
6+
const assert = require('assert');
7+
const crypto = require('crypto');
8+
9+
// Test case for des-ede3 wrap/unwrap. des3-wrap needs extra 2x blocksize
10+
// then plaintext to store ciphertext.
11+
const test = {
12+
key: Buffer.from('3c08e25be22352910671cfe4ba3652b1220a8a7769b490ba', 'hex'),
13+
iv: Buffer.alloc(0),
14+
plaintext: '32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBG' +
15+
'WWELweCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZU' +
16+
'JjAfaFg**'
17+
};
18+
19+
const cipher = crypto.createCipheriv('des3-wrap', test.key, test.iv);
20+
const ciphertext = cipher.update(test.plaintext, 'utf8');
21+
22+
const decipher = crypto.createDecipheriv('des3-wrap', test.key, test.iv);
23+
const msg = decipher.update(ciphertext, 'buffer', 'utf8');
24+
25+
assert.strictEqual(msg, test.plaintext);

0 commit comments

Comments
 (0)