Skip to content

Commit 5602c08

Browse files
tniessenjuanarbol
authored andcommitted
doc,test: clarify ChaCha20-Poly1305 usage
PR-URL: #42323 Reviewed-By: James M Snell <[email protected]>
1 parent 0a2123d commit 5602c08

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

doc/api/crypto.md

+18-9
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,8 @@ added: v1.0.0
546546
-->
547547

548548
* Returns: {Buffer} When using an authenticated encryption mode (`GCM`, `CCM`,
549-
and `OCB` are currently supported), the `cipher.getAuthTag()` method returns a
549+
`OCB`, and `chacha20-poly1305` are currently supported), the
550+
`cipher.getAuthTag()` method returns a
550551
[`Buffer`][] containing the _authentication tag_ that has been computed from
551552
the given data.
552553

@@ -568,7 +569,8 @@ added: v1.0.0
568569
* `encoding` {string} The string encoding to use when `buffer` is a string.
569570
* Returns: {Cipher} for method chaining.
570571

571-
When using an authenticated encryption mode (`GCM`, `CCM`, and `OCB` are
572+
When using an authenticated encryption mode (`GCM`, `CCM`, `OCB`, and
573+
`chacha20-poly1305` are
572574
currently supported), the `cipher.setAAD()` method sets the value used for the
573575
_additional authenticated data_ (AAD) input parameter.
574576

@@ -865,7 +867,8 @@ changes:
865867
* `encoding` {string} String encoding to use when `buffer` is a string.
866868
* Returns: {Decipher} for method chaining.
867869

868-
When using an authenticated encryption mode (`GCM`, `CCM`, and `OCB` are
870+
When using an authenticated encryption mode (`GCM`, `CCM`, `OCB`, and
871+
`chacha20-poly1305` are
869872
currently supported), the `decipher.setAAD()` method sets the value used for the
870873
_additional authenticated data_ (AAD) input parameter.
871874

@@ -899,7 +902,8 @@ changes:
899902
* `encoding` {string} String encoding to use when `buffer` is a string.
900903
* Returns: {Decipher} for method chaining.
901904

902-
When using an authenticated encryption mode (`GCM`, `CCM`, and `OCB` are
905+
When using an authenticated encryption mode (`GCM`, `CCM`, `OCB`, and
906+
`chacha20-poly1305` are
903907
currently supported), the `decipher.setAuthTag()` method is used to pass in the
904908
received _authentication tag_. If no tag is provided, or if the cipher text
905909
has been tampered with, [`decipher.final()`][] will throw, indicating that the
@@ -908,7 +912,8 @@ is invalid according to [NIST SP 800-38D][] or does not match the value of the
908912
`authTagLength` option, `decipher.setAuthTag()` will throw an error.
909913

910914
The `decipher.setAuthTag()` method must be called before [`decipher.update()`][]
911-
for `CCM` mode or before [`decipher.final()`][] for `GCM` and `OCB` modes.
915+
for `CCM` mode or before [`decipher.final()`][] for `GCM` and `OCB` modes and
916+
`chacha20-poly1305`.
912917
`decipher.setAuthTag()` can only be called once.
913918

914919
When passing a string as the authentication tag, please consider
@@ -2945,7 +2950,8 @@ Creates and returns a `Cipher` object that uses the given `algorithm` and
29452950
`password`.
29462951

29472952
The `options` argument controls stream behavior and is optional except when a
2948-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
2953+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
2954+
In that case, the
29492955
`authTagLength` option is required and specifies the length of the
29502956
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
29512957
option is not required but can be used to set the length of the authentication
@@ -3016,7 +3022,8 @@ Creates and returns a `Cipher` object, with the given `algorithm`, `key` and
30163022
initialization vector (`iv`).
30173023

30183024
The `options` argument controls stream behavior and is optional except when a
3019-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
3025+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
3026+
In that case, the
30203027
`authTagLength` option is required and specifies the length of the
30213028
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
30223029
option is not required but can be used to set the length of the authentication
@@ -3064,7 +3071,8 @@ Creates and returns a `Decipher` object that uses the given `algorithm` and
30643071
`password` (key).
30653072

30663073
The `options` argument controls stream behavior and is optional except when a
3067-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
3074+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
3075+
In that case, the
30683076
`authTagLength` option is required and specifies the length of the
30693077
authentication tag in bytes, see [CCM mode][].
30703078

@@ -3117,7 +3125,8 @@ Creates and returns a `Decipher` object that uses the given `algorithm`, `key`
31173125
and initialization vector (`iv`).
31183126

31193127
The `options` argument controls stream behavior and is optional except when a
3120-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
3128+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
3129+
In that case, the
31213130
`authTagLength` option is required and specifies the length of the
31223131
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
31233132
option is not required but can be used to restrict accepted authentication tags

test/parallel/test-crypto-authenticated.js

+44
Original file line numberDiff line numberDiff line change
@@ -701,3 +701,47 @@ for (const test of TEST_CASES) {
701701
});
702702
}
703703
}
704+
705+
// ChaCha20-Poly1305 should respect the authTagLength option and should not
706+
// require the authentication tag before calls to update() during decryption.
707+
{
708+
const key = Buffer.alloc(32);
709+
const iv = Buffer.alloc(12);
710+
711+
for (let authTagLength = 1; authTagLength <= 16; authTagLength++) {
712+
const cipher =
713+
crypto.createCipheriv('chacha20-poly1305', key, iv, { authTagLength });
714+
const ciphertext = Buffer.concat([cipher.update('foo'), cipher.final()]);
715+
const authTag = cipher.getAuthTag();
716+
assert.strictEqual(authTag.length, authTagLength);
717+
718+
// The decipher operation should reject all authentication tags other than
719+
// that of the expected length.
720+
for (let other = 1; other <= 16; other++) {
721+
const decipher = crypto.createDecipheriv('chacha20-poly1305', key, iv, {
722+
authTagLength: other
723+
});
724+
// ChaCha20 is a stream cipher so we do not need to call final() to obtain
725+
// the full plaintext.
726+
const plaintext = decipher.update(ciphertext);
727+
assert.strictEqual(plaintext.toString(), 'foo');
728+
if (other === authTagLength) {
729+
// The authentication tag length is as expected and the tag itself is
730+
// correct, so this should work.
731+
decipher.setAuthTag(authTag);
732+
decipher.final();
733+
} else {
734+
// The authentication tag that we are going to pass to setAuthTag is
735+
// either too short or too long. If other < authTagLength, the
736+
// authentication tag is still correct, but it should still be rejected
737+
// because its security assurance is lower than expected.
738+
assert.throws(() => {
739+
decipher.setAuthTag(authTag);
740+
}, {
741+
code: 'ERR_CRYPTO_INVALID_AUTH_TAG',
742+
message: `Invalid authentication tag length: ${authTagLength}`
743+
});
744+
}
745+
}
746+
}
747+
}

0 commit comments

Comments
 (0)