Skip to content

Commit f7cdeba

Browse files
yhwangtniessen
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]> 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 cd8ed1c commit f7cdeba

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

src/node_crypto.cc

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3023,14 +3023,28 @@ CipherBase::UpdateResult CipherBase::Update(const char* data,
30233023
auth_tag_set_ = true;
30243024
}
30253025

3026-
*out_len = len + EVP_CIPHER_CTX_block_size(ctx_);
3027-
*out = Malloc<unsigned char>(static_cast<size_t>(*out_len));
3026+
*out_len = 0;
3027+
int buff_len = len + EVP_CIPHER_CTX_block_size(ctx_);
3028+
// For key wrapping algorithms, get output size by calling
3029+
// EVP_CipherUpdate() with null output.
3030+
if (mode == EVP_CIPH_WRAP_MODE &&
3031+
EVP_CipherUpdate(ctx_,
3032+
nullptr,
3033+
&buff_len,
3034+
reinterpret_cast<const unsigned char*>(data),
3035+
len) != 1) {
3036+
return kErrorState;
3037+
}
3038+
3039+
*out = Malloc<unsigned char>(buff_len);
30283040
int r = EVP_CipherUpdate(ctx_,
30293041
*out,
30303042
out_len,
30313043
reinterpret_cast<const unsigned char*>(data),
30323044
len);
30333045

3046+
CHECK_LE(*out_len, buff_len);
3047+
30343048
// When in CCM mode, EVP_CipherUpdate will fail if the authentication tag is
30353049
// invalid. In that case, remember the error and throw in final().
30363050
if (!r && kind_ == kDecipher && mode == EVP_CIPH_CCM_MODE) {
Lines changed: 25 additions & 0 deletions
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)