From 8848f7c8d229e48d4e436461d05a5b2e4d29efc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Tue, 6 Sep 2022 07:40:54 +0000 Subject: [PATCH] doc: emphasize that createCipher is never secure The current documentation clearly states that createCipher() and createDecipher() should not be used with ciphers in counter mode, but (1) this is an understatement, and (2) these functions are (semantically) insecure for ciphers in any other supported block cipher mode as well. Semantic security requires IND-CPA, but a deterministic cipher with fixed key and IV, such as those generated by these functions, does not fulfill IND-CPA. Are there justified use cases for createCipher() and createDecipher()? Yes and no. The only case in which these functions can be used in a semantically secure manner arises only when the password argument is not actually a password but rather a random or pseudo-random sequence that is unpredictable and that is never reused (e.g., securely derived from a password with a proper salt). Insofar, it is possible to use these APIs without immediately creating a vulnerability. However, - any application that manages to fulfill this requirement should also be able to fulfill the similar requirements of crypto.createCipheriv() and those of crypto.createDecipheriv(), which give much more control over key and initialization vector, and - the MD5-based key derivation step generally does not help and might even reduce the overall security due to its many weaknesses. Refs: https://github.com/nodejs/node/pull/13821 Refs: https://github.com/nodejs/node/pull/19343 Refs: https://github.com/nodejs/node/pull/22089 --- doc/api/crypto.md | 8 ++++++++ doc/api/deprecations.md | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/api/crypto.md b/doc/api/crypto.md index dc581cbd82b6bb..66fb2f207bd6ab 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -3013,6 +3013,10 @@ The `password` is used to derive the cipher key and initialization vector (IV). The value must be either a `'latin1'` encoded string, a [`Buffer`][], a `TypedArray`, or a `DataView`. +This function is semantically insecure for all +supported ciphers and fatally flawed for ciphers in counter mode (such as CTR, +GCM, or CCM). + The implementation of `crypto.createCipher()` derives keys using the OpenSSL function [`EVP_BytesToKey`][] with the digest algorithm set to MD5, one iteration, and no salt. The lack of salt allows dictionary attacks as the same @@ -3136,6 +3140,10 @@ cipher in CCM or OCB mode (e.g. `'aes-128-ccm'`) is used. In that case, the authentication tag in bytes, see [CCM mode][]. For `chacha20-poly1305`, the `authTagLength` option defaults to 16 bytes. +This function is semantically insecure for all +supported ciphers and fatally flawed for ciphers in counter mode (such as CTR, +GCM, or CCM). + The implementation of `crypto.createDecipher()` derives keys using the OpenSSL function [`EVP_BytesToKey`][] with the digest algorithm set to MD5, one iteration, and no salt. The lack of salt allows dictionary attacks as the same diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 7cfe0c01ee0f6e..d3f3eac9cef122 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -2114,10 +2114,10 @@ changes: Type: Runtime -Using [`crypto.createCipher()`][] and [`crypto.createDecipher()`][] should be +Using [`crypto.createCipher()`][] and [`crypto.createDecipher()`][] must be avoided as they use a weak key derivation function (MD5 with no salt) and static initialization vectors. It is recommended to derive a key using -[`crypto.pbkdf2()`][] or [`crypto.scrypt()`][] and to use +[`crypto.pbkdf2()`][] or [`crypto.scrypt()`][] with random salts and to use [`crypto.createCipheriv()`][] and [`crypto.createDecipheriv()`][] to obtain the [`Cipher`][] and [`Decipher`][] objects respectively.