Skip to content

Commit d1bbf33

Browse files
committed
doc,test: clarify ChaCha20-Poly1305 usage
1 parent b481bee commit d1bbf33

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

doc/api/crypto.md

Lines changed: 18 additions & 9 deletions
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
@@ -2963,7 +2968,8 @@ Creates and returns a `Cipher` object that uses the given `algorithm` and
29632968
`password`.
29642969

29652970
The `options` argument controls stream behavior and is optional except when a
2966-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
2971+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
2972+
In that case, the
29672973
`authTagLength` option is required and specifies the length of the
29682974
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
29692975
option is not required but can be used to set the length of the authentication
@@ -3033,7 +3039,8 @@ Creates and returns a `Cipher` object, with the given `algorithm`, `key` and
30333039
initialization vector (`iv`).
30343040

30353041
The `options` argument controls stream behavior and is optional except when a
3036-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
3042+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
3043+
In that case, the
30373044
`authTagLength` option is required and specifies the length of the
30383045
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
30393046
option is not required but can be used to set the length of the authentication
@@ -3081,7 +3088,8 @@ Creates and returns a `Decipher` object that uses the given `algorithm` and
30813088
`password` (key).
30823089

30833090
The `options` argument controls stream behavior and is optional except when a
3084-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
3091+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
3092+
In that case, the
30853093
`authTagLength` option is required and specifies the length of the
30863094
authentication tag in bytes, see [CCM mode][].
30873095

@@ -3133,7 +3141,8 @@ Creates and returns a `Decipher` object that uses the given `algorithm`, `key`
31333141
and initialization vector (`iv`).
31343142

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

test/parallel/test-crypto-authenticated.js

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

0 commit comments

Comments
 (0)