Adam Caudill

Security Leader, Researcher, Developer, Writer, & Photographer

1Password, PBKDF2, & Implementation Flaws

…or “Crypto Is Hard, Vol. 479”

Earlier today a tweet about a new feature for oclHashcat-plus started a truly interesting debate on Twitter over the implications. The new feature is the ability to crack 1Password keychain files – at an impressive 3 million passwords per second.

To achieve this speed, two optimizations were used – the first is in precomputing ipad and opad for SHA1-HMAC, this effectively cuts the number of SHA1 calls in half. This is clever, but not the part I’m interested in, it’s the second optimization that I find interesting.

1Password uses AES128, in CBC mode to encrypt data – and it’s the design of CBC that enables the next optimization. If you have the wrong IV when you decrypt in CBC mode it corrupts the first block – but only the first block, the rest will be fine. It’s this fact that seems to have been overlooked when 1Password was designed.

The final encryption key is derived from the user’s password via PBKDF2. They generate a 320bit key (so two blocks or four calls to SHA1 after the precompute optimization); of those 320 bits, 128 bits go into the encryption key, another 128 bits go to the IV. For 1Password to work, it needs both the key and the IV – but attackers don’t.

An attacker can look at later blocks to see if they are valid and ignore the first block, by ignoring the IV generation and the first encrypted block, the number of calls to SHA1 is again cut in half.

To their credit, Jeffrey Goldberg of AgileBits (the maker of 1Password) responded very quickly and provided details about what they are doing to address it, and joined in a very open discussion about the impact of how this was implemented. Depending on who you ask, this ‘flaw’ costs either 1 or 2 bits of entropy.

For the end user, it means that an attacker only needs to perform 50% of the SHA1 calls that the 1Password software needs (maybe only 25%, depending on how optimized the 1Password code is). When it comes to password cracking, that certainly seems less secure than what was intended. As flaws go it could be far worse, but it’s likely less secure than intended.

And finally, after all of this, we come to the point:

Crypto is hard, even for smart people.

It’s so easy to accidentally introduce weaknesses like this – everything looks right, but because of how they used PBKDF2 in combination with AES128-CBC, the end result is weaker than was intended. It’s specific, fairly obscure (to many at least), details of how these two algorithms work, and how they were used together that led to this flaw.

AgileBits has made a lot of good decisions, and in general at least, seems to know what they are doing. I certainly don’t mean to beat up on them, they’ve handled this very well and the issue is fairly small. I applaud them for discussing this so openly, it’s hard to do – I know that from personal experience.

This should serve as a great example of why any new crypto implementation needs to be expert reviewed to make sure that it’s right. Nobody gets it right every time, every code base needs to be reviewed, this could (but doesn’t have to) happen to you.

Adam Caudill

Related Posts

  • Hash Storage: Make Attackers Work

    So you hash your passwords? Good. Do you salt? That’s good. Do you use a strong hashing algorithm (PBKDF2/bcrypt/scrypt)? Great! But how do you store the hashes? What happens when you get hit with a SQL injection attack? I’m a big believer in defense in-depth – not that marketing garbage about stacking layers of blinky-light boxes, but using techniques to add extra work for an attacker. You might not be able to stop every attack, but the more work they have to do, the better the odds they won’t get everything they want.

  • Password Hashing: No Silver Bullets

    In the dark days of the web, if a service hashed your password instead of storing it in plain text, they were doing good. As sites were hacked, and credentials stolen, a silver bullet emerged: always hash and salt passwords when storing them. Many, many services were built with this design – LivingSocial is a great example. SHA1 hashing with a 40 byte salt – once upon a time, that was considered reasonable protection.

  • Win by Building for Failure

    Systems fail; it doesn’t matter what the system is. Something will fail sooner or later. When you design a system, are you focused on the happy path, or are you building with the possibility of failure in mind? If you suffered a data breach tomorrow, what would the impact be? Does the system prevent loss by design, or does it just fall apart? Can you easily minimize loss and damage, or would an attacker have free rein once they get in?

  • When Hashing isn’t Hashing

    Anyone working in application security has found themselves saying something like this a thousand times: “always hash passwords with a secure password hashing function.” I’ve said this phrase at nearly all of the developer events I’ve spoken at, it’s become a mantra of sorts for many of us that try to improve the security of applications. We tell developers to hash passwords, then we have to qualify it to explain that it isn’t normal hashing.

  • 1Password 8 Early Access: Security, Comments, & FAQs

    A few days ago, 1Password (my employer) released the first preview of the new application for macOS. The response has been rather dramatic. The release was followed by an excellent blog post by Michael Fey explaining the story of how we got here, and some of the decisions that were made in the process. I’d like to now to a few minutes to answer some questions, provide some insight, and share my thoughts on this release.