Skip to content

Commit 805a3e5

Browse files
tniessentargos
authored andcommitted
doc,test: clarify ChaCha20-Poly1305 usage
PR-URL: #42323 Reviewed-By: James M Snell <[email protected]>
1 parent bbfcf8f commit 805a3e5

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
@@ -2949,7 +2954,8 @@ Creates and returns a `Cipher` object that uses the given `algorithm` and
29492954
`password`.
29502955

29512956
The `options` argument controls stream behavior and is optional except when a
2952-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
2957+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
2958+
In that case, the
29532959
`authTagLength` option is required and specifies the length of the
29542960
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
29552961
option is not required but can be used to set the length of the authentication
@@ -3020,7 +3026,8 @@ Creates and returns a `Cipher` object, with the given `algorithm`, `key` and
30203026
initialization vector (`iv`).
30213027

30223028
The `options` argument controls stream behavior and is optional except when a
3023-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
3029+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
3030+
In that case, the
30243031
`authTagLength` option is required and specifies the length of the
30253032
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
30263033
option is not required but can be used to set the length of the authentication
@@ -3068,7 +3075,8 @@ Creates and returns a `Decipher` object that uses the given `algorithm` and
30683075
`password` (key).
30693076

30703077
The `options` argument controls stream behavior and is optional except when a
3071-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
3078+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
3079+
In that case, the
30723080
`authTagLength` option is required and specifies the length of the
30733081
authentication tag in bytes, see [CCM mode][].
30743082

@@ -3121,7 +3129,8 @@ Creates and returns a `Decipher` object that uses the given `algorithm`, `key`
31213129
and initialization vector (`iv`).
31223130

31233131
The `options` argument controls stream behavior and is optional except when a
3124-
cipher in CCM or OCB mode is used (e.g. `'aes-128-ccm'`). In that case, the
3132+
cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) or `chacha20-poly1305` is used.
3133+
In that case, the
31253134
`authTagLength` option is required and specifies the length of the
31263135
authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength`
31273136
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)