Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit cd50e93

Browse filesBrowse files
tniessendanielleadams
authored andcommitted
doc: warn about using strings as inputs in crypto
PR-URL: #37248 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Filip Skokan <panva.ip@gmail.com>
1 parent 5a4288e commit cd50e93
Copy full SHA for cd50e93

File tree

Expand file treeCollapse file tree

1 file changed

+67
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

1 file changed

+67
-0
lines changed
Open diff view settings
Collapse file

‎doc/api/crypto.md‎

Copy file name to clipboardExpand all lines: doc/api/crypto.md
+67Lines changed: 67 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,9 @@ of the ciphertext in bytes. See [CCM mode][].
537537

538538
The `decipher.setAAD()` method must be called before [`decipher.update()`][].
539539

540+
When passing a string as the `buffer`, please consider
541+
[caveats when using strings as inputs to cryptographic APIs][].
542+
540543
### `decipher.setAuthTag(buffer[, encoding])`
541544
<!-- YAML
542545
added: v1.0.0
@@ -569,6 +572,9 @@ The `decipher.setAuthTag()` method must be called before [`decipher.update()`][]
569572
for `CCM` mode or before [`decipher.final()`][] for `GCM` and `OCB` modes.
570573
`decipher.setAuthTag()` can only be called once.
571574

575+
When passing a string as the authentication tag, please consider
576+
[caveats when using strings as inputs to cryptographic APIs][].
577+
572578
### `decipher.setAutoPadding([autoPadding])`
573579
<!-- YAML
574580
added: v0.7.1
@@ -2161,6 +2167,9 @@ The `key` is the raw key used by the `algorithm` and `iv` is an
21612167
a [`KeyObject`][] of type `secret`. If the cipher does not need
21622168
an initialization vector, `iv` may be `null`.
21632169

2170+
When passing strings for `key` or `iv`, please consider
2171+
[caveats when using strings as inputs to cryptographic APIs][].
2172+
21642173
Initialization vectors should be unpredictable and unique; ideally, they will be
21652174
cryptographically random. They do not have to be secret: IVs are typically just
21662175
added to ciphertext messages unencrypted. It may sound contradictory that
@@ -2257,6 +2266,9 @@ The `key` is the raw key used by the `algorithm` and `iv` is an
22572266
a [`KeyObject`][] of type `secret`. If the cipher does not need
22582267
an initialization vector, `iv` may be `null`.
22592268

2269+
When passing strings for `key` or `iv`, please consider
2270+
[caveats when using strings as inputs to cryptographic APIs][].
2271+
22602272
Initialization vectors should be unpredictable and unique; ideally, they will be
22612273
cryptographically random. They do not have to be secret: IVs are typically just
22622274
added to ciphertext messages unencrypted. It may sound contradictory that
@@ -3097,6 +3109,9 @@ but will take a longer amount of time to complete.
30973109
The `salt` should be as unique as possible. It is recommended that a salt is
30983110
random and at least 16 bytes long. See [NIST SP 800-132][] for details.
30993111

3112+
When passing strings for `password` or `salt`, please consider
3113+
[caveats when using strings as inputs to cryptographic APIs][].
3114+
31003115
```js
31013116
const crypto = require('crypto');
31023117
crypto.pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, derivedKey) => {
@@ -3168,6 +3183,9 @@ but will take a longer amount of time to complete.
31683183
The `salt` should be as unique as possible. It is recommended that a salt is
31693184
random and at least 16 bytes long. See [NIST SP 800-132][] for details.
31703185

3186+
When passing strings for `password` or `salt`, please consider
3187+
[caveats when using strings as inputs to cryptographic APIs][].
3188+
31713189
```js
31723190
const crypto = require('crypto');
31733191
const key = crypto.pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512');
@@ -3656,6 +3674,9 @@ memory-wise in order to make brute-force attacks unrewarding.
36563674
The `salt` should be as unique as possible. It is recommended that a salt is
36573675
random and at least 16 bytes long. See [NIST SP 800-132][] for details.
36583676

3677+
When passing strings for `password` or `salt`, please consider
3678+
[caveats when using strings as inputs to cryptographic APIs][].
3679+
36593680
The `callback` function is called with two arguments: `err` and `derivedKey`.
36603681
`err` is an exception object when key derivation fails, otherwise `err` is
36613682
`null`. `derivedKey` is passed to the callback as a [`Buffer`][].
@@ -3714,6 +3735,9 @@ memory-wise in order to make brute-force attacks unrewarding.
37143735
The `salt` should be as unique as possible. It is recommended that a salt is
37153736
random and at least 16 bytes long. See [NIST SP 800-132][] for details.
37163737

3738+
When passing strings for `password` or `salt`, please consider
3739+
[caveats when using strings as inputs to cryptographic APIs][].
3740+
37173741
An exception is thrown when key derivation fails, otherwise the derived key is
37183742
returned as a [`Buffer`][].
37193743

@@ -3923,6 +3947,47 @@ See the [Web Crypto API documentation][] for details.
39233947

39243948
## Notes
39253949

3950+
### Using strings as inputs to cryptographic APIs
3951+
3952+
For historical reasons, many cryptographic APIs provided by Node.js accept
3953+
strings as inputs where the underlying cryptographic algorithm works on byte
3954+
sequences. These instances include plaintexts, ciphertexts, symmetric keys,
3955+
initialization vectors, passphrases, salts, authentication tags,
3956+
and additional authenticated data.
3957+
3958+
When passing strings to cryptographic APIs, consider the following factors.
3959+
3960+
* Not all byte sequences are valid UTF-8 strings. Therefore, when a byte
3961+
sequence of length `n` is derived from a string, its entropy is generally
3962+
lower than the entropy of a random or pseudo-random `n` byte sequence.
3963+
For example, no UTF-8 string will result in the byte sequence `c0 af`. Secret
3964+
keys should almost exclusively be random or pseudo-random byte sequences.
3965+
* Similarly, when converting random or pseudo-random byte sequences to UTF-8
3966+
strings, subsequences that do not represent valid code points may be replaced
3967+
by the Unicode replacement character (`U+FFFD`). The byte representation of
3968+
the resulting Unicode string may, therefore, not be equal to the byte sequence
3969+
that the string was created from.
3970+
3971+
```js
3972+
const original = [0xc0, 0xaf];
3973+
const bytesAsString = Buffer.from(original).toString('utf8');
3974+
const stringAsBytes = Buffer.from(bytesAsString, 'utf8');
3975+
console.log(stringAsBytes);
3976+
// Prints '<Buffer ef bf bd ef bf bd>'.
3977+
```
3978+
3979+
The outputs of ciphers, hash functions, signature algorithms, and key
3980+
derivation functions are pseudo-random byte sequences and should not be
3981+
used as Unicode strings.
3982+
* When strings are obtained from user input, some Unicode characters can be
3983+
represented in multiple equivalent ways that result in different byte
3984+
sequences. For example, when passing a user passphrase to a key derivation
3985+
function, such as PBKDF2 or scrypt, the result of the key derivation function
3986+
depends on whether the string uses composed or decomposed characters. Node.js
3987+
does not normalize character representations. Developers should consider using
3988+
[`String.prototype.normalize()`][] on user inputs before passing them to
3989+
cryptographic APIs.
3990+
39263991
### Legacy streams API (prior to Node.js 0.10)
39273992

39283993
The Crypto module was added to Node.js before there was the concept of a
@@ -4384,6 +4449,7 @@ See the [list of SSL OP Flags][] for details.
43844449
[AEAD algorithms]: https://en.wikipedia.org/wiki/Authenticated_encryption
43854450
[CCM mode]: #crypto_ccm_mode
43864451
[Caveats]: #crypto_support_for_weak_or_compromised_algorithms
4452+
[caveats when using strings as inputs to cryptographic APIs]: #crypto_using_strings_as_inputs_to_cryptographic_apis
43874453
[Crypto constants]: #crypto_crypto_constants_1
43884454
[HTML 5.2]: https://www.w3.org/TR/html52/changes.html#features-removed
43894455
[HTML5's `keygen` element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen
@@ -4406,6 +4472,7 @@ See the [list of SSL OP Flags][] for details.
44064472
[`EVP_BytesToKey`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_BytesToKey.html
44074473
[`KeyObject`]: #crypto_class_keyobject
44084474
[`Sign`]: #crypto_class_sign
4475+
[`String.prototype.normalize()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
44094476
[`UV_THREADPOOL_SIZE`]: cli.md#cli_uv_threadpool_size_size
44104477
[`Verify`]: #crypto_class_verify
44114478
[`cipher.final()`]: #crypto_cipher_final_outputencoding

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.