If your implication is that 18F has the same reputation as past Web-related efforts in the federal government, you may need to look into 18F more closely.
It's only 3 years old and was specifically intended to fix all of those stereotypes and make the government software production efforts more similar to those in Silicon Valley.
Scrypt isn't badly designd. It's also difficult to misuse.
This is like saying "bcrypt is badly designed."
Note that you are specifically attacking scrypt with the title -- "login.gov encryption" can be substituted with "scrypt."
If you were to say it's illegal for them to be using scrypt since scrypt is not an approved KDF, that would carry more weight.
Cryptographic flaws
1. scrypt is used as password-based KDF, which violates NIST 140-2
This isn't a cryptographic flaw! The phrase "cryptographic flaw" means something.
5. hash(E) is stored right next to the ciphertext from (4). Who thought that storing a hash of the encryption key right next to PII ciphertext encrypted with that key was a good idea?
Storing the hash of an encryption key is fine, as long as the hash function is strong.
It's frustrating that a government website is making solid cryptographic choices and then being lampooned like this. It would be far more productive to make scrypt an approved NIST KDF.
Password vulns are a tiny, tiny fraction of modern security vulnerabilities. If it's important, get it pentested. I guarantee no pentest from a reputable firm would flag scrypt as a vulnerability.
I don't think "NIST" approved is that compelling of an argument.
If the author wishes to identify known vulnerabilities, that would be interesting.
FIPS has some various issues that actually increase vulnerability and not decrease it. Eg, FIPS approved OpenSSL was always an anchor that caused more problems than it solved.
A design that technically violates a law, but is not actually dangerous - suppose the law constrains designs in a way that requires them to be less effective or safe - is not necessarily a poor design, unless "complies with law" is a higher priority design objective than "functions safely as intended".
Not to be too flippant, but "complies with law" sort of seems like a requirement for non-government services too. But I may be reading this too broadly?
The OP seems to misunderstand the function of NIST, as well. NIST does not "approve" other agencies' software systems. NIST is a standards-setting organization only. They create and publish standards, but do not enforce them.
This is a rather sensational title for an article that amounts to "Login.gov does not use FIPS 140-2-compliant cryptography". Its main argument (aside from point 5) appears to be that scrypt is used in multiple locations, without passing judgement on scrypt itself.
Given that this is a US government-run system, this is still a compliance problem, but that's a different issue.
This is mostly complaining about a lack of FIPS 140 compliance. While that might be a regulatory issue for a .gov site, technically-speaking FIPS compliance is a hinderance to building a sound system, not an aid.
Putting that aside, there might be some valid points in here: using Hash(IKM + nonce) to generate a key is probably not ideal, depending on what Hash is. That's generally a job for HKDF. The post also mentions a "non-approved KDF" elsewhere, but doesn't say what it is.
On the other hand, storing Hash(key) isn't immediately an issue unless something else in the scheme depends on Hash(key) being secret, but the post implies without justification that it's some sort of obvious error.
So there might well be some issues here, but this post doesn't provide sufficient detail to condemn login.gov out of hand.
This is a butchered version of my standard write-up for customers who have customers who ask about FIPS.
FIPS is really an unsuitable way to evaluate the security of large or complex systems. The major
cloud vendors who claim to be FIPS compliant do so by describing one key part of their system as
FIPS compliant (e.g. their VPN technology, for Azure, and SSL termination for AWS), and then
proudly displaying a compliance badge on their website.
It is more or less impossible to make a modern cloud system completely FIPS compliant, and it is a waste of
time to try. Organizations asking for FIPS compliance seem perfectly happy as long as one or two
key parts are compliant.
Usually, the simplest FIPS compliance goal is to target the transfer of <key data> over the Internet. That will satisfy most customers.
Actually it is a bit worse than that, because your customers will need to do some work on their side, and based on a realistic profile of customers who enquire about FIPs compliance, they are extremely unlikely to undertake that effort. So the key thing is to be "FIPS ready". More on this shortly.
DEFINITIONS
FIPS - This is actually a broad range of standards. In the context of security, most people mean
FIPS 140-2 - "Security Requirements for Cryptographic Modules".
* FIPS Certified: If you create cryptographic modules, you can have them certified as compliant by an accredited lab. This costs a lot of money. There is an official list of all FIPS certified cryptographic modules.
* FIPS "Level" - There are 4 levels. Software can really only ever be level 1. Levels 2+ start talking about features only possible in hardware, such as tamper evident seals.
* FIPS Compliant - If your product uses only FIPS certified cryptographic modules and FIPS approved algorithms for all cryptographic operations, it is FIPS compliant.
* FIPS Ready - This is a "made-up term", but it sounds good. It's a way to express "Our software can be compliant, but you need to do some things which we can't do for you".
FIPS ON THE CLIENT
Windows is only compliant if it is operating in "FIPS mode". Obviously, you can't turn that on for your customers, they need to do it themselves. See: Enabling FIPS compliant algorithms in Windows.
Note that enabling FIPS mode will often break a lot of things (e.g. TLS connections to some web
sites, inter-operation between different versions of Windows and so on). Also, it will actually tend to
weaken security. This is because the FIPs approved algorithm list is several years old which means
that the system is forced to use ciphers which are weaker than modern defaults. Furthermore,
FIPS-certified code can't, if you read carefully, be patched without re-certification.
FIPS MODE, IN GENERAL
Most vendors meet the requirements of FIPS by providing a specific, certified "mode" in which the
system is compliant.
Why? Well, when a software cryptographic module is FIPS certified, the certification just applies to
that exact version. If a single byte changes in that software module, it isn't certified any more.
Naturally, vendors want to keep improving their software. So they keep the old, certified code
around and only activate it in FIPS mode. Also, in FIPS mode, the software must perform time-consuming self-tests every boot (ok, that is not that bad).
It is really an untenable situation for software. Here's a great write-up of the software certification process from a member of the Oracle Solaris team: Is FIPS 140-2 Actively harmful to software?.
Side note - please don’t use a code block for lists like that. It is unreadable on any screen narrower than the length of the lines, and there are no line wraps.
> The post also mentions a "non-approved KDF" elsewhere, but doesn't say what it is.
Reading the source code, it appears to be a continuation of the theme of complaints against scrypt.
Z1, Z2 = scrypt(S, password) # split 256-bit output into two halves
Honestly what's wrong here is not that the assertions are debatable, but the way it goes on the attack, calling people who apparently knew what they were doing "rookies" and such.
You mean to say that the outdated requirements of FIPS-140-2 aren't the best practices for designing a crypto system? That the lack of TMTO attack resistance in PBKDF2 makes it a sub-optimal choice for storing passwords? Surely not! NIST would never recommend anything but the strongest cryptography!
Hey, at least their transport security gets an A+ from SSL Labs. Honestly, I still find a lot of government sites, particularly state governments that get F's because they are still using SSL and 56 bit ciphers.
Now I may be misunderstanding their implementation, but it seems to me actually worse than "this isn't FIPS 140". I take no issue with their use of scrypt at all. The complaints in this Gist actually seem to miss the mark to me.
The problem isn't scrypt, or storing a hash. The real problem is storing d which, seems to me, defeats the purpose of using an HSM in the first place!
Again, with the disclaimer that I'm not 100% certain that's what they're doing, it's just what the documentation says, and what it seems like is happening from reading the Ruby code. I don't develop in Ruby, but while the language is fairly easy to read, with all their variables named 'encryption_code', 'encryption_key', 'encrypted_key', 'encrypted_code', etc. it's easy to get lost.
EDIT: Can someone please co-validate my analysis please? Or please tell me what I got wrong! From what I can see, the design is obviously broken. I don't consider myself qualified to find flaws in other people's crypto so, when I find obvious flaws in what should be well designed crypto I get a little freaked out.
EDIT: OK, I think I see what's wrong with this analysis: https://github.com/18F/identity-idp/blob/master/spec/service....
They do include Z1 in the data they pass to KMS decrypt. This is because they have XORed the ciphertext with Z1 - so now in order to recover the initial ciphertext back (i.e. the cipher text you can decrypt with KMS to get R back), you need to XOR with Z1 again.
So even if you get D from the database, you can't decrypt it unless you have Z1, and if you were trying to brute-force it, you would need to call KMS for every attempt with the Z1 for this attempt.
Original comment:
I am not any kind of crypto expert. But I agree with you.
I think they should be XORing with "AssignedSecret" (not "EncryptedAssignedSecret"). Then in order to compare password hashes you would need to decrypt the "EncryptedAssignedSecret" using KMS. (using the terminology in the description of the algorithm here: https://github.com/18F/identity-idp/blob/master/docs/encrypt...) (EDIT: you actually cover this approach in the GH issue, and point out a problem with it).
I think there is another approach like what the OP proposed where they should be using some portion of the scrypt hash (either Z1 or Z2 or just the whole thing) as part of the encryption context passed to KMS. But this seems a little more complicated to me. (EDIT: You also mention this as a possible solution in the GH issue).
Where you get the key and the key's cipher text back from KMS and store that, and then you have to use KMS to decrypt whatever you encrypted with the key.
Yes, you need to know the password to decrypt. That's the basis of their very interesting PII protection scheme!
My point is you can brute-force the password without the HSM. And their docs specifically say this should not be possible. Isn't the whole point of the HSM to prevent that?
'hash' is derived from 'z2' and 'd' - and they give you 'd'. Password will produce 'z2'. So that's the brute-force attack.
To say it another way, the 'z1' path is secured. But there is the 'z2' path and it's wide open.
I've left a comment on your github issue, but the tl;dr is that the encryption document doesn't seem to reflect the code. The comment in the ruby test case suggests that the actual step is 'E = hash( Z2 + R )' instead of 'E = hash( Z2 + D )' where 'R' is the user's randomly generated 'AssignedKey' and 'D' is the masked HSM ciphertext 'KMS(R) ^ Z2'.
Perhaps somewhere during implementation someone realized the document doesn't make sense as written.
What an immature analysis with click-bait title, I was expecting something big to read and it turns out he was just not happy about the site doesn't comply to NIST, and using scrypt is a flaw? Seriously?
The construction seems bad, but FIPS isn't anywhere close to being as good as NACL, and scrypt isn't the enemy. Bad constructions, lack of nuance and faith in certifications are the enemies.
Also note: scrypt ends with a PBKDF2 round, so if PBKDF2 is acceptable then scrypt may not actually be a problem. Legally speaking you might be able to ignore the use of the SMIX (including Salsa20) and the HMAC entirely as long as the final PBKDF2 uses a FIPS 140-2 acceptable hash function.
"OMG, you're totally right - if only the OP knew that scrypt ends with pbkdf2.."
Um, no. But thanks for playing. For those who wish to argue that everything that precedes PBKDF2 in scrypt should be considered as "key extraction", you should read NIST SP800-56c, also referenced by FIPS-140-2 Annex-D (tldr: scrypt does not fly). Welcome to USG infosec compliance.
40 comments
[ 3.8 ms ] story [ 89.6 ms ] threadIt's only 3 years old and was specifically intended to fix all of those stereotypes and make the government software production efforts more similar to those in Silicon Valley.
This is like saying "bcrypt is badly designed."
Note that you are specifically attacking scrypt with the title -- "login.gov encryption" can be substituted with "scrypt."
If you were to say it's illegal for them to be using scrypt since scrypt is not an approved KDF, that would carry more weight.
Cryptographic flaws
1. scrypt is used as password-based KDF, which violates NIST 140-2
This isn't a cryptographic flaw! The phrase "cryptographic flaw" means something.
5. hash(E) is stored right next to the ciphertext from (4). Who thought that storing a hash of the encryption key right next to PII ciphertext encrypted with that key was a good idea?
Storing the hash of an encryption key is fine, as long as the hash function is strong.
It's frustrating that a government website is making solid cryptographic choices and then being lampooned like this. It would be far more productive to make scrypt an approved NIST KDF.
When it's something as important as this, the proper choice is to use something that's been analyzed, and attacked for numerous years.
[0]: https://coinmarketcap.com/currencies/litecoin/
If the author wishes to identify known vulnerabilities, that would be interesting.
FIPS has some various issues that actually increase vulnerability and not decrease it. Eg, FIPS approved OpenSSL was always an anchor that caused more problems than it solved.
Given that this is a US government-run system, this is still a compliance problem, but that's a different issue.
Putting that aside, there might be some valid points in here: using Hash(IKM + nonce) to generate a key is probably not ideal, depending on what Hash is. That's generally a job for HKDF. The post also mentions a "non-approved KDF" elsewhere, but doesn't say what it is.
On the other hand, storing Hash(key) isn't immediately an issue unless something else in the scheme depends on Hash(key) being secret, but the post implies without justification that it's some sort of obvious error.
So there might well be some issues here, but this post doesn't provide sufficient detail to condemn login.gov out of hand.
This is a butchered version of my standard write-up for customers who have customers who ask about FIPS.
FIPS is really an unsuitable way to evaluate the security of large or complex systems. The major cloud vendors who claim to be FIPS compliant do so by describing one key part of their system as FIPS compliant (e.g. their VPN technology, for Azure, and SSL termination for AWS), and then proudly displaying a compliance badge on their website. It is more or less impossible to make a modern cloud system completely FIPS compliant, and it is a waste of time to try. Organizations asking for FIPS compliance seem perfectly happy as long as one or two key parts are compliant.
Usually, the simplest FIPS compliance goal is to target the transfer of <key data> over the Internet. That will satisfy most customers.
Actually it is a bit worse than that, because your customers will need to do some work on their side, and based on a realistic profile of customers who enquire about FIPs compliance, they are extremely unlikely to undertake that effort. So the key thing is to be "FIPS ready". More on this shortly.
DEFINITIONS
FIPS - This is actually a broad range of standards. In the context of security, most people mean FIPS 140-2 - "Security Requirements for Cryptographic Modules".
* FIPS Certified: If you create cryptographic modules, you can have them certified as compliant by an accredited lab. This costs a lot of money. There is an official list of all FIPS certified cryptographic modules.
* FIPS "Level" - There are 4 levels. Software can really only ever be level 1. Levels 2+ start talking about features only possible in hardware, such as tamper evident seals.
* FIPS Compliant - If your product uses only FIPS certified cryptographic modules and FIPS approved algorithms for all cryptographic operations, it is FIPS compliant.
* FIPS Ready - This is a "made-up term", but it sounds good. It's a way to express "Our software can be compliant, but you need to do some things which we can't do for you".
FIPS ON THE CLIENT
Windows is only compliant if it is operating in "FIPS mode". Obviously, you can't turn that on for your customers, they need to do it themselves. See: Enabling FIPS compliant algorithms in Windows. Note that enabling FIPS mode will often break a lot of things (e.g. TLS connections to some web sites, inter-operation between different versions of Windows and so on). Also, it will actually tend to weaken security. This is because the FIPs approved algorithm list is several years old which means that the system is forced to use ciphers which are weaker than modern defaults. Furthermore, FIPS-certified code can't, if you read carefully, be patched without re-certification.
FIPS MODE, IN GENERAL
Most vendors meet the requirements of FIPS by providing a specific, certified "mode" in which the system is compliant. Why? Well, when a software cryptographic module is FIPS certified, the certification just applies to that exact version. If a single byte changes in that software module, it isn't certified any more. Naturally, vendors want to keep improving their software. So they keep the old, certified code around and only activate it in FIPS mode. Also, in FIPS mode, the software must perform time-consuming self-tests every boot (ok, that is not that bad).
It is really an untenable situation for software. Here's a great write-up of the software certification process from a member of the Oracle Solaris team: Is FIPS 140-2 Actively harmful to software?.
https://blogs.oracle.com/darren/is-fips-140-2-actively-harmf...
The engineer (an architect on the Solaris crypto team) writes:
So should I run Solaris 11 with FIPS 140-2 mode enabled ? - My personal opinion is that unless you have a very hard requirement to do so I ...
Reading the source code, it appears to be a continuation of the theme of complaints against scrypt.
Honestly what's wrong here is not that the assertions are debatable, but the way it goes on the attack, calling people who apparently knew what they were doing "rookies" and such.https://www.ssllabs.com/ssltest/analyze.html?d=login.gov&lat...
HN comment: https://news.ycombinator.com/item?id=15204989
Github Issue: https://github.com/18F/identity-idp/issues/1665
Now I may be misunderstanding their implementation, but it seems to me actually worse than "this isn't FIPS 140". I take no issue with their use of scrypt at all. The complaints in this Gist actually seem to miss the mark to me.
The problem isn't scrypt, or storing a hash. The real problem is storing d which, seems to me, defeats the purpose of using an HSM in the first place!
Again, with the disclaimer that I'm not 100% certain that's what they're doing, it's just what the documentation says, and what it seems like is happening from reading the Ruby code. I don't develop in Ruby, but while the language is fairly easy to read, with all their variables named 'encryption_code', 'encryption_key', 'encrypted_key', 'encrypted_code', etc. it's easy to get lost.
EDIT: Can someone please co-validate my analysis please? Or please tell me what I got wrong! From what I can see, the design is obviously broken. I don't consider myself qualified to find flaws in other people's crypto so, when I find obvious flaws in what should be well designed crypto I get a little freaked out.
Original comment:
I am not any kind of crypto expert. But I agree with you.
I think they should be XORing with "AssignedSecret" (not "EncryptedAssignedSecret"). Then in order to compare password hashes you would need to decrypt the "EncryptedAssignedSecret" using KMS. (using the terminology in the description of the algorithm here: https://github.com/18F/identity-idp/blob/master/docs/encrypt...) (EDIT: you actually cover this approach in the GH issue, and point out a problem with it).
I think there is another approach like what the OP proposed where they should be using some portion of the scrypt hash (either Z1 or Z2 or just the whole thing) as part of the encryption context passed to KMS. But this seems a little more complicated to me. (EDIT: You also mention this as a possible solution in the GH issue).
I think there's also an approach using the GenerateDataKey API : http://docs.aws.amazon.com/kms/latest/APIReference/API_Gener...
Where you get the key and the key's cipher text back from KMS and store that, and then you have to use KMS to decrypt whatever you encrypted with the key.
My point is you can brute-force the password without the HSM. And their docs specifically say this should not be possible. Isn't the whole point of the HSM to prevent that?
'hash' is derived from 'z2' and 'd' - and they give you 'd'. Password will produce 'z2'. So that's the brute-force attack.
To say it another way, the 'z1' path is secured. But there is the 'z2' path and it's wide open.
Perhaps somewhere during implementation someone realized the document doesn't make sense as written.
Um, no. But thanks for playing. For those who wish to argue that everything that precedes PBKDF2 in scrypt should be considered as "key extraction", you should read NIST SP800-56c, also referenced by FIPS-140-2 Annex-D (tldr: scrypt does not fly). Welcome to USG infosec compliance.