Skip to content

Commit f604c04

Browse files
yhwangMylesBorins
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 17dbf6c commit f604c04

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
@@ -2987,14 +2987,28 @@ CipherBase::UpdateResult CipherBase::Update(const char* data,
29872987
auth_tag_set_ = true;
29882988
}
29892989

2990-
*out_len = len + EVP_CIPHER_CTX_block_size(ctx_);
2991-
*out = Malloc<unsigned char>(static_cast<size_t>(*out_len));
2990+
*out_len = 0;
2991+
int buff_len = len + EVP_CIPHER_CTX_block_size(ctx_);
2992+
// For key wrapping algorithms, get output size by calling
2993+
// EVP_CipherUpdate() with null output.
2994+
if (mode == EVP_CIPH_WRAP_MODE &&
2995+
EVP_CipherUpdate(ctx_,
2996+
nullptr,
2997+
&buff_len,
2998+
reinterpret_cast<const unsigned char*>(data),
2999+
len) != 1) {
3000+
return kErrorState;
3001+
}
3002+
3003+
*out = Malloc<unsigned char>(buff_len);
29923004
int r = EVP_CipherUpdate(ctx_,
29933005
*out,
29943006
out_len,
29953007
reinterpret_cast<const unsigned char*>(data),
29963008
len);
29973009

3010+
CHECK_LE(*out_len, buff_len);
3011+
29983012
// When in CCM mode, EVP_CipherUpdate will fail if the authentication tag is
29993013
// invalid. In that case, remember the error and throw in final().
30003014
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)