Skip to content

Commit f9b9974

Browse files
committed
crypto: support authTagLength in GCM encryption
The authTagLength option can now be used to produce GCM authentication tags with a specific length. PR-URL: #20235 Refs: #20039 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Yihong Wang <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent 6606a26 commit f9b9974

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

doc/api/crypto.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,11 @@ This property is deprecated. Please use `crypto.setFips()` and
13211321
<!-- YAML
13221322
added: v0.1.94
13231323
deprecated: v10.0.0
1324+
changes:
1325+
- version: REPLACEME
1326+
pr-url: https://github.com/nodejs/node/pull/20235
1327+
description: The `authTagLength` option can now be used to produce shorter
1328+
authentication tags in GCM mode and defaults to 16 bytes.
13241329
-->
13251330

13261331
> Stability: 0 - Deprecated: Use [`crypto.createCipheriv()`][] instead.
@@ -1336,7 +1341,9 @@ Creates and returns a `Cipher` object that uses the given `algorithm` and
13361341
The `options` argument controls stream behavior and is optional except when a
13371342
cipher in CCM mode is used (e.g. `'aes-128-ccm'`). In that case, the
13381343
`authTagLength` option is required and specifies the length of the
1339-
authentication tag in bytes, see [CCM mode][].
1344+
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
1345+
option is not required but can be used to set the length of the authentication
1346+
tag that will be returned by `getAuthTag()` and defaults to 16 bytes.
13401347

13411348
The `algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On
13421349
recent OpenSSL releases, `openssl list-cipher-algorithms` will display the
@@ -1366,6 +1373,10 @@ Adversaries][] for details.
13661373
<!-- YAML
13671374
added: v0.1.94
13681375
changes:
1376+
- version: REPLACEME
1377+
pr-url: https://github.com/nodejs/node/pull/20235
1378+
description: The `authTagLength` option can now be used to produce shorter
1379+
authentication tags in GCM mode and defaults to 16 bytes.
13691380
- version: v9.9.0
13701381
pr-url: https://github.com/nodejs/node/pull/18644
13711382
description: The `iv` parameter may now be `null` for ciphers which do not
@@ -1383,7 +1394,9 @@ initialization vector (`iv`).
13831394
The `options` argument controls stream behavior and is optional except when a
13841395
cipher in CCM mode is used (e.g. `'aes-128-ccm'`). In that case, the
13851396
`authTagLength` option is required and specifies the length of the
1386-
authentication tag in bytes, see [CCM mode][].
1397+
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
1398+
option is not required but can be used to set the length of the authentication
1399+
tag that will be returned by `getAuthTag()` and defaults to 16 bytes.
13871400

13881401
The `algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On
13891402
recent OpenSSL releases, `openssl list-cipher-algorithms` will display the

src/node_crypto.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3106,9 +3106,10 @@ bool CipherBase::Final(unsigned char** out, int *out_len) {
31063106
ok = EVP_CipherFinal_ex(ctx_, *out, out_len) == 1;
31073107

31083108
if (ok && kind_ == kCipher && IsAuthenticatedMode()) {
3109-
// For GCM, the tag length is static (16 bytes), while the CCM tag length
3110-
// must be specified in advance.
3111-
if (mode == EVP_CIPH_GCM_MODE)
3109+
// In GCM mode, the authentication tag length can be specified in advance,
3110+
// but defaults to 16 bytes when encrypting. In CCM mode, it must always
3111+
// be given by the user.
3112+
if (mode == EVP_CIPH_GCM_MODE && auth_tag_len_ == kNoAuthTagLength)
31123113
auth_tag_len_ = sizeof(auth_tag_);
31133114
// TOOD(tniessen) Use EVP_CTRL_AEAP_GET_TAG in OpenSSL 1.1.0
31143115
static_assert(EVP_CTRL_CCM_GET_TAG == EVP_CTRL_GCM_GET_TAG,

test/parallel/test-crypto-authenticated.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,18 @@ for (const test of TEST_CASES) {
727727
message: `Invalid GCM authentication tag length: ${length}`
728728
});
729729

730+
common.expectsError(() => {
731+
crypto.createCipheriv('aes-256-gcm',
732+
'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8',
733+
'qkuZpJWCewa6Szih',
734+
{
735+
authTagLength: length
736+
});
737+
}, {
738+
type: Error,
739+
message: `Invalid GCM authentication tag length: ${length}`
740+
});
741+
730742
common.expectsError(() => {
731743
crypto.createDecipheriv('aes-256-gcm',
732744
'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8',
@@ -741,6 +753,23 @@ for (const test of TEST_CASES) {
741753
}
742754
}
743755

756+
// Test that GCM can produce shorter authentication tags than 16 bytes.
757+
{
758+
const fullTag = '1debb47b2c91ba2cea16fad021703070';
759+
for (const [authTagLength, e] of [[undefined, 16], [12, 12], [4, 4]]) {
760+
const cipher = crypto.createCipheriv('aes-256-gcm',
761+
'FxLKsqdmv0E9xrQhp0b1ZgI0K7JFZJM8',
762+
'qkuZpJWCewa6Szih', {
763+
authTagLength
764+
});
765+
cipher.setAAD(Buffer.from('abcd'));
766+
cipher.update('01234567', 'hex');
767+
cipher.final();
768+
const tag = cipher.getAuthTag();
769+
assert.strictEqual(tag.toString('hex'), fullTag.substr(0, 2 * e));
770+
}
771+
}
772+
744773
// Test that users can manually restrict the GCM tag length to a single value.
745774
{
746775
const decipher = crypto.createDecipheriv('aes-256-gcm',

0 commit comments

Comments
 (0)