In Part I, I made the argument that even when using public key cryptography you almost always want authenticated encryption. In this second part, we’ll look at how you can actually achieve public key authenticated encryption (PKAE) from commonly available building blocks. We will concentrate only on approaches that do not require an interactive protocol. (Updated 12th January 2019 to add a description of a NIST-approved key-agreement mode that achieves PKAE).
If you read or watch any recent tutorial on symmetric (or “secret key”) cryptography, one lesson should be clear: in 2018 if you want to encrypt something you’d better use authenticated encryption. This not only hides the content of a message, but also ensures that the message was sent by one of the parties that has access to the shared secret key and that it hasn’t been tampered with. It turns out that without these additional guarantees (integrity and authenticity), the contents of a message often does not remain secret for long either.
In the old days these properties were considered separate. If you wanted to encrypt you used an unauthenticated cipher, and if you wanted to authenticate you used a MAC. If you wanted both (and it became clear over time that you almost always did), then you had to combine the cipher and the MAC and hope that the combination was secure. Mostly, it wasn’t. You see, it turns out to be less than straightforward to combine a cipher and a MAC. There is one approach that is (almost) always secure: Encrypt-then-MAC (EtM). First you encrypt the message using the cipher and then you authenticate the encrypted ciphertext using the MAC. But it took quite a long time before that was well known, and a lot of mistakes were made along the way.
In order to prevent these mistakes, cryptographers adopted the combined goal of authenticated encryption and developed cipher modes that combined both functions in one, such as AES-GCM or ChaCha20-Poly1305. Such modes treat the problem as a unified whole rather than as separate pieces to be combined by the user. Now there are many high quality authenticated encryption modes, and so it is relatively easy to do the right thing.
Contrast this with the current situation for public key encryption. In this setting, the security goal is usually seen as confidentiality with ciphertext integrity (also known as IND-CCA security – indistinguishability under a chosen ciphertext attack). This goal ensures confidentiality and integrity, but without sender authentication. The receiver can be sure that the contents are private and that the message has not been tampered with, but they do not know who the sender is. For instance, in this (generally very good) article from Matthew Green, he argues that IND-CCA2 is the correct security definition in a public key setting (compared to authenticated encryption), because in the public key setting “I should be able to (safely) decrypt messages from anyone”. I disagree with this goal however. I argue that in almost all cases I want to know who sent me a message, and I want to make a trust decision based on that information.
Consider Green’s example of Apple’s iMessage service, or even email. I don’t actually want anybody at all to be able to send me a message, as mostly they just send me spam. Even in the rare case that I am willing to accept an email from anybody, I want to be able to positively identify who they are before I decide act on its contents. Even in the public key setting, I almost always want (sender) authentication as well as confidentiality and integrity. I want public key authenticated encryption!
I am slightly mischaracterising Prof. Green’s blog somewhat here. He is not actually arguing (I think) that authentication is not important, but rather arguing a more subtle point: that the combination of (chosen plaintext) confidentiality with sender authentication (in the form of signatures) is not sufficient to prevent chosen ciphertext attacks in the public key setting like it was in the symmetric setting, and that therefore we want IND-CCA2 security. I completely agree with this, but my point is that I still want sender authentication in 99% of cases. In other words, I still want authenticated encryption but rather than combining authentication with a simple CPA-secure cipher as I can in the symmetric setting, I need to combine authentication with a CCA-secure cipher in the public key setting.
These kinds of subtleties are why I would like cryptographers to focus more on authenticated encryption in the public key setting. As was the case for symmetric key crypto, combining authentication with public key encryption is far from straightforward. I have seen developers replace a symmetric authenticated encryption algorithm used for session cookies with RSA-OAEP, and be completely unaware that now anybody at all can now forge a valid session. They needed authentication but didn’t understand the security properties of the crypto. It is easy to see why developers get confused as many standards present symmetric authenticated encryption algorithms and public key encryption algorithms (without authentication) as if they were equivalent and interchangeable.
I said earlier that the security goal for public key encryption is almost always presented as IND-CCA security. There is one prominent exception: NaCl. If you’ve not head of NaCl (pronounced “salt”, geddit?), it is a well-respected cryptography library developed by Daniel Bernstein. NaCl clearly documents the security goal of its
crypto_box function as public key authenticated encryption. As a result, it is much easier to construct a secure system with NaCl than by trying to combine typical public key encryption and signature schemes.
In Part II, we will look at how to achieve public key authenticated encryption in practice, including how NaCl does it (and potential drawbacks). In Part III, we will then consider some changes to JOSE and other standards to clarify and improve the security properties on offer.
Java KeyStores are used to store key material and associated certificates in an encrypted and integrity protected fashion. Like all things Java, this mechanism is pluggable and so there exist a variety of different options. There are lots of articles out there that describe the different types and how you can initialise them, load keys and certificates, etc. However, there is a lack of detailed technical information about exactly how these keystores store and protect your key material. This post attempts to gather those important details in one place for the most common KeyStores.
Continue reading “Java KeyStores – the gory details”
Updated 20th July 2017 to clarify notation for the point of infinity. A previous version used the symbol 0 (zero) rather than O, which may have been confusing.
In the wake of the recent critical security vulnerabilities in some JOSE/JWT libraries around ECDH public key validation, a number of implementations scrambled to implement specific validation of public keys to eliminate these attacks. But how do we know whether these checks are sufficient? Is there any guidance on what checks should be performed? The answer is yes, but it can be a bit hard tracking down exactly what validation needs to be done in which cases. For modern elliptic curve schemes like X25519 and Ed25519, there is some debate over whether validation should be performed at all in the basic primitive implementations, as the curve eliminates some of the issues while high-level protocols can be designed to eliminate others. However, for the NIST standard curves used in JOSE, the question is more clear cut: it is absolutely critical that public keys are correctly validated, as evidenced by the linked security alert.