New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto: warn if counter mode used in createCipher #13821

Closed
wants to merge 2 commits into
base: master
from

Conversation

Projects
None yet
@shigeki
Contributor

shigeki commented Jun 20, 2017

crypto.createCipher() sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
crypto.createCipher() to notify users to avoid nonce reuse.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

crypto

Fixes: #13801

CC @bnoordhuis, @indutny

@shigeki

This comment has been minimized.

Contributor

shigeki commented Jun 20, 2017

@iangcarroll

This comment has been minimized.

iangcarroll commented Jun 20, 2017

Is it possible to put the documentation warning in a box like one of the alerts for stability notices? This really needs to be more prominent, and the wording should be more direct, i.e replace the entire paragraph with something like:

When using ciphers that require an initialization vector, createCipher will insecurely derive a non-random initialization vector from the key you provide. Messages with the same plaintext will always have the same ciphertext. Never use createCipher with counter modes (e.g. CTR, GCM or CCM), as reusing initialization vectors may result in no encryption at all. A warning will be emitted if you attempt to use createCipher with one of these modes.

Though if it goes in an alert box it'll obviously need to be more concise. Maybe just "Don't use this function".

@tniessen

This comment has been minimized.

Member

tniessen commented Jun 20, 2017

Maybe just "Don't use this function".

See #13801 (comment), there are justified use cases of createCipher.

@tniessen

This comment has been minimized.

Member

tniessen commented Jun 20, 2017

I think the problems and security implications of using createCipher are not limited to counter modes, but FWIW, this won't make it worse.

@iangcarroll

This comment has been minimized.

iangcarroll commented Jun 20, 2017

there are justified use cases of createCipher.

"Don't use it" was mostly a joke, but still holds true even for ECB. ;)

but FWIW, this won't make it worse.

Well, I mean, sure. I'd still say the documentation needs to be stronger here before it's merged. Especially if people come across the warning and the documentation says it's a "recommendation".

@indutny

LGTM

src/node_crypto.cc Outdated
int mode = EVP_CIPHER_CTX_mode(&ctx_);
if (encrypt && (mode == EVP_CIPH_CTR_MODE || mode == EVP_CIPH_GCM_MODE ||
mode == EVP_CIPH_CCM_MODE))

This comment has been minimized.

@indutny

indutny Jun 20, 2017

Member

Nitpicking: could you please surround if's body with braces {...}?

This comment has been minimized.

@shigeki

shigeki Jun 21, 2017

Contributor

Thanks. Fixed.

@cbarcenas

This comment has been minimized.

cbarcenas commented Jun 20, 2017

Thanks for getting the ball rolling on a fix for this, @shigeki! Some thoughts:

crypto.createCipher() sets the fixed IV derived from password and it leads to a security risk of nonce reuse when counter mode is used.

"Leads to a security risk" is a huge understatement... in common block cipher modes (e.g. CTR), IV reuse is catastrophic to confidentiality. Observing just a few ciphertexts is sufficient in many cases to derive the underlying key and/or plaintexts, compromising the encryption scheme entirely. (See here for a good explanation.)

Reiterating my concerns from #13801, I think a much better change is for createCipher to fail when called with a block mode that requires an IV. Yes, this is a API-breaking change, but it's much better than the current behavior. The current behavior is completely broken in a cryptographic sense once the same password is used for more than one encryption operation!

If Node were to adopt this fail-fast behavior, the legacy key/IV generation should be exposed in a public immediately-deprecated API (e.g. generateLegacyKey/generateLegacyIV), so existing projects that rely on the old behavior of createCipher could easily generate the same key/IV data from their preexisting passwords. Because such an API call would be deprecated, it would serve as good impetus to migrate behavior away from the broken key/IV-generation scheme and move toward proper use of these block cipher modes via createCipheriv.

What are your thoughts about this?

I must admit, I have never contributed to this project before, so I'm not sure of the feasibility of these changes and I may not have the sufficient context on this project to make the changes myself, but I'm happy to hear what veterans of this project might think about this proposal.

@bnoordhuis

This comment has been minimized.

Member

bnoordhuis commented Jun 20, 2017

I think I'm +1 on @cbarcenas's proposal. It's been proven time and time again that users simply ignore or mute warnings so I don't have much hope for this PR.

If we're going to make a hard break, are there other things that should go?

@stouset

This comment has been minimized.

stouset commented Jun 20, 2017

@cbarcenas That is an improvement over the current situation, but a better approach in my opinion is for crypto.createCipher to generate IVs for the end-user, and return them with the output of cipher.final(). Or alternatively, if you don't want to change semantics of existing functions, deprecate the existing function and replace it with a newly-named one.

Users should not, in the general case, be asked to deal with details like IV generation. Modes like CTR have different security requirements (uniqueness) than CBC (unpredictability), and users will not consistently get this right. Similarly, modes like GCM only provide an advantage when the auth tag is actually provided during decryption. Naïve searching shows that only about 80% of users actually take this step when using GCM. Including the auth tag (when relevant) in the output when using crypto.createCipher would also eliminate this entire class of weakness.

If a user does want to take things into their own hands, they can use the existing createCipheriv.

@cbarcenas

This comment has been minimized.

cbarcenas commented Jun 20, 2017

@stouset I agree with you in principle that letting Node handle IV generation would improve usability and security. However, something to consider here is making these changes as backwards-compatible as possible, and giving projects an easy path to remediate this issue without relying these projects' developers to have cryptographic expertise.

My main concern is that including the IV in the output of cipher.final() will break decryption in projects that take ciphertext output from cipher.final() and blindly pass it into decipher.update() without preprocessing.

I guess an underlying question here is whether the crypto module is intended to provide high- or low-level cryptographic functionality.

@mscdex

This comment has been minimized.

Contributor

mscdex commented Jun 20, 2017

Also, I think having differing .final() return values depending on whether createCipher() or createCipheriv() was used would be unexpected behavior. On top of that, returning objects (plain or otherwise) from C++ land would decrease performance (although passing an object created in JS land to C++ land might be slightly faster -- at least it used to be).

@stouset

This comment has been minimized.

stouset commented Jun 21, 2017

@cbarcenas Yeah, I wouldn't mind such an API having a new name.

@mscdex The return value wouldn't change. It would just be slightly longer to accommodate the IV (and ideally tag, for authenticated encryption). This would be essentially transparent to consumers of the API.

@shigeki

This comment has been minimized.

Contributor

shigeki commented Jun 21, 2017

I agree that nonce reuse in counter mode leads catastrophic. For examples in TLS case of AES-GCM, "Nonce-Disrespecting Adversaries" shows that the MAC key of GHASH can be derived and encrypted message can be tampered by bit flipping.

I wrote a modest description in the doc because the nonce is not always reused in crypto.createCipher if it is used only once or keys are changed in every encryptions.
For example in case of plain text is known, we can do it unless it has hash collision as

const crypto = require('crypto');
const key = 'pass';
const plain = 'hello world';
const cipher = crypto.createCipher('aes-128-gcm', crypto.createHmac('sha256', key).update(plain).digest());
const encrypted = cipher.update(plain);

I also think that we cannot prohibit reused nonce even if we use crypto.createCipheriv. Some people might use a random value as nonce such that

const crypto = require('crypto');
const key = 'pass';
const plain = 'hello world';
const cipher = crypto.createCipheriv('aes-128-gcm', key, crypto.randomBytes(12));
const encrypted = cipher.update(plain);

But it has a possibility of nonce reused when it is called in extremely large number due to birthday paradox. The situation of nonce reused largely depends on how user use it and I think we cannot cover all the cases.
That is why AES-SIV RFC5297) and AES-GCM-SIV are developed. We should encourage to use them against nonce reuse. Unfortunately, they are not yet widely used. AES-GCM-SIV is under standardization and only boringSSL has just supported it recently. I think we can only let users generate IV to meet their use and security requirements for now.

@iangcarroll iangcarroll referenced this pull request Jun 27, 2017

Closed

crypto: Deprecate createCipher for createCipheriv #13941

7 of 7 tasks complete
@bnoordhuis

Needs a rebase but let's land it, it still improves on the status quo.

@@ -1196,7 +1196,8 @@ rapidly.
In line with OpenSSL's recommendation to use pbkdf2 instead of
[`EVP_BytesToKey`][] it is recommended that developers derive a key and IV on
their own using [`crypto.pbkdf2()`][] and to use [`crypto.createCipheriv()`][]
to create the `Cipher` object.
to create the `Cipher` object. A warning is emitted when counter mode (e.g. CTR,
GCM or CCM) is used in `crypto.createCipher()` in order to avoid IV reuse.

This comment has been minimized.

@bnoordhuis

bnoordhuis Aug 20, 2017

Member

Maybe make this warning a little stronger, e.g. "a predictable IV undermines the security of counter-based ciphers."

Would it be worthwhile to mention that this API predates the addition of counter-based ciphers to OpenSSL, hence why it's not an error outright?

(Really, the more I think about it, the more I feel throwing an exception is the right thing to do. If it weren't for backwards compatibility...)

This comment has been minimized.

@shigeki

shigeki Aug 21, 2017

Contributor

I changed the doc into a little stronger description as ae7dbb1 and add a reference of Nonce-Disrespecting Adversaries.

Would it be worthwhile to mention that this API predates the addition of counter-based ciphers to OpenSSL, hence why it's not an error outright?

I think it gets more complicated description in the doc. We can make throwing an error some time later after enough time.

This comment has been minimized.

@stouset

stouset Aug 21, 2017

A predictable IV does not undermine the security of counter-based ciphers. In fact, a simple incrementing counter is a recommended approach when using counter-based schemes that have IVs too small to reliably be generated uniquely at random.

This comment has been minimized.

@bnoordhuis

bnoordhuis Aug 21, 2017

Member

@stouset I think you may be misunderstanding how openssl implements them and what "IV" means in that context. The best description I could find:

https://stackoverflow.com/questions/3141860/aes-ctr-256-encryption-mode-of-operation-on-openssl/3146214#3146214

This comment has been minimized.

@stouset

stouset Aug 21, 2017

I checked the link, and I might be wrong but I don't think anything in it contradicts my response. I'll do some more research, but at the very least the wording you suggested may be confusing and need clarification if there's a particular reason it's accurate in this case. I'm in an area with poor signal but I should be able to take a better look later tonight.

This comment has been minimized.

@shigeki

shigeki Aug 22, 2017

Contributor

I think that IV should be a nonce not a random so that it must not be reused with the same secret key but it can be predictable.

This comment has been minimized.

@bnoordhuis

bnoordhuis Aug 22, 2017

Member

Yes. I think the confusion is around the fact that the IV to OpenSSL's EVP_CipherInit_ex() is the concatenation of the nonce and the counter as a single bit string.

This comment has been minimized.

@stouset

stouset Aug 22, 2017

Right, but it's fine if that's predictable as long as it's never repeated. The nonce in CTR mode can be predictable (and is often recommended to be a simple counter in appropriate contexts), and the counter is itself just an actual counter.

This comment has been minimized.

@bnoordhuis

bnoordhuis Aug 22, 2017

Member

I don't think we are in disagreement. Is your beef with the wording in this PR? Can you suggest an alternative?

shigeki added some commits Jun 20, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.
@shigeki

This comment has been minimized.

Contributor

shigeki commented Aug 21, 2017

Rebased against the latest master and CI is running on https://ci.nodejs.org/job/node-test-pull-request/9777/.

@bnoordhuis

Still LGTM.

@shigeki

This comment has been minimized.

Contributor

shigeki commented Aug 22, 2017

The previous CI had an Jenkins error. A new CI of https://ci.nodejs.org/job/node-test-commit/11951/ is all green. Landed in 9dfb2d1.

@stouset If you have any proposal, please submit a new PR.

Thanks for reviewers.

@shigeki shigeki closed this Aug 22, 2017

shigeki added a commit that referenced this pull request Aug 22, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Fixes: #13801
PR-URL: #13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

addaleax added a commit to addaleax/ayo that referenced this pull request Aug 25, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Fixes: nodejs/node#13801
PR-URL: nodejs/node#13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

addaleax added a commit to ayojs/ayo that referenced this pull request Aug 28, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Fixes: nodejs/node#13801
PR-URL: nodejs/node#13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

@bnoordhuis bnoordhuis referenced this pull request Sep 10, 2017

Closed

crypto: fix error of createCipher in wrap mode #15037

3 of 4 tasks complete
@bnoordhuis

This comment has been minimized.

Member

bnoordhuis commented Sep 10, 2017

I'm removing the semver-major label. Since it warns on insecure usage, I think it's appropriate to back-port it to the release branches.

MylesBorins added a commit that referenced this pull request Sep 10, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Fixes: #13801
PR-URL: #13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

@MylesBorins MylesBorins referenced this pull request Sep 10, 2017

Merged

v8.5.0 proposal #15308

MylesBorins added a commit that referenced this pull request Sep 11, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Fixes: #13801
PR-URL: #13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

MylesBorins added a commit that referenced this pull request Sep 11, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Fixes: #13801
PR-URL: #13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

MylesBorins added a commit that referenced this pull request Sep 12, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Fixes: #13801
PR-URL: #13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
@MylesBorins

This comment has been minimized.

Member

MylesBorins commented Sep 20, 2017

Should this be backported to v6.x-staging? If yes please follow the guide and raise a backport PR, if no let me know or add the dont-land-on label.

bnoordhuis added a commit to bnoordhuis/io.js that referenced this pull request Oct 29, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Fixes: nodejs#13801
PR-URL: nodejs#13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

bnoordhuis added a commit to bnoordhuis/io.js that referenced this pull request Oct 29, 2017

test: add regression test for counter mode warning
The previous commit is a back-port of pull request nodejs#13821 to v6.x.
Its regression test does not apply to the v6.x branch (depends on
semver-major pull request nodejs#9405) so this commit adds a new test.

Refs: nodejs#13821
Refs: nodejs#9405
@bnoordhuis

This comment has been minimized.

Member

bnoordhuis commented Oct 29, 2017

v6.x: #16583

MylesBorins added a commit that referenced this pull request Nov 14, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Backport-PR-URL: #16583
Fixes: #13801
PR-URL: #13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

@MylesBorins MylesBorins referenced this pull request Nov 21, 2017

Merged

v6.12.1 proposal #17180

MylesBorins added a commit that referenced this pull request Nov 21, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Backport-PR-URL: #16583
Fixes: #13801
PR-URL: #13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

MylesBorins added a commit that referenced this pull request Nov 28, 2017

crypto: warn if counter mode used in createCipher
`crypto.createCipher()` sets the fixed IV derived from password and it
leads to a security risk of nonce reuse when counter mode is used.
A warning is emitted when CTR, GCM or CCM is used in
`crypto.createCipher()` to notify users to avoid nonce reuse.

Backport-PR-URL: #16583
Fixes: #13801
PR-URL: #13821
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>

@ChALkeR ChALkeR added the security label Jan 27, 2018

@tniessen tniessen referenced this pull request Aug 2, 2018

Closed

crypto: move createCipher to runtime deprecation #22089

4 of 4 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment