Public key authenticated encryption and why you want it (Part I)

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.

Key-driven cryptographic agility

One of the criticisms of the JOSE/JWT standards is that they give an attacker too much flexibility, by allowing them to specify how a message should be processed. In particular, the standard “alg” header tells the recipient what cryptographic algorithm was used to sign or encrypt the contents. Letting the attacker chose the algorithm can lead to disastrous security vulnerabilities. Continue reading “Key-driven cryptographic agility”

So how *do* you validate (NIST) ECDH public keys?

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.

Continue reading “So how *do* you validate (NIST) ECDH public keys?”

Updating OpenAM’s encryption

Updated 30th March 2017 to reflect updated information (see comments), add additional links and add some clarifying text about why misuse-resistance is useful.

With the impending release of the ForgeRock Identity Platform, I thought I’d spend some time writing up a few of the bits of OpenAM 14 that I was directly involved with creating. One of my last acts before leaving FR to go solo, was to put in place the first phase of modernising AM’s aging system credential encryption scheme. Before I start, I should say that this encryption scheme is not used for encrypting user passwords (which are hashed by the LDAP user store, not AM). Instead, this scheme is used for encrypting various system credentials (passwords for SMTP servers, HMAC shared secrets, etc) in the config store and in exported system configurations and in a few other places.

The original (and still default) encryption method was first mentioned in Dante’s Inferno. Actually it dates from the original iPlanet codebase from the mid-90s, and uses correspondingly ancient cryptographic algorithms (MD5 and DES). It is best to regard it as providing only limited obfuscation of credentials, rather than any true security guarantees, and the advice has always been to secure the config store by traditional means (TLS, access controls) rather than rely on this encryption. Still, we can do much better than this now, so AM 14 ships with a new AESWrapEncryption scheme that provides significantly improved security:

Continue reading “Updating OpenAM’s encryption”

Should you use JWT/JOSE?

In the wake of some more recent attacks against popular JSON Web Token (JWT)/JSON Object Signing and Encryption (JOSE) libraries, there has been some renewed criticism of the JWT/JOSE standards themselves (see also discussion on lobste.rs with an excellent comment from Thomas Ptacek summarising some of the problems with the standard). Given these criticisms, should you use JOSE at all? Are articles like my recent “best practices” one just encouraging adoption of bad standards that should be left to die a death?

Certainly, there are lots of potential gotchas in the specs, and it is easy for somebody without experience to shoot themselves in the foot using these standards. I agree with pretty much all of the criticisms levelled against the standards. They are too complicated with too many potentially insecure options. It is far too easy to select insecure combinations or misconfigure them. Indeed, much of the advice in my earlier article can be boiled down to limiting which options you use, understanding what security properties those options do and do not provide, and completely ignoring some of the more troublesome aspects of the spec. If you followed my advice of using “headless” JWTs and direct authenticated encryption with a symmetric key, you’d end up not far off from the advice of just encrypting a JSON object with libsodium or using Fernet.

So in that sense, I am already advocating for not really using the specs as-is, at least not without significant work to understand them and how they fit with your requirements. But there are some cases where using JWTs still makes sense:

  • If you need to implement a standard that mandates their use, such as OpenID Connect. In this case you do not have much of a choice.
  • If you need to interoperate with third-party software that is already using JWTs. Again, in this case you also do not have a choice.
  • You have complex requirements mandating particular algorithms/parameters (e.g. NIST/FIPS-approved algorithms) and don’t want to hand-roll a message format or are required to use something with a “standard”. In this case, JWT/JOSE is not a terrible choice, so long as you know what you are doing (and I hope you do if you are in this position).

If you do have a choice, then you should think hard about whether you need the complexity of JWTs or can use a simpler approach that takes care of most of the choices for you or store state on the server and use opaque cookies. In addition to the options mentioned in the referenced posts, I would also like to mention Macaroons, which can be a good alternative for some authorization token use-cases and the existing libraries tend to build on solid foundations (libsodium/NaCl).

So, should you use JWT/JOSE at all? In many cases the answer is no, and you should use a less error-prone alternative. If you do need to use them, then make sure you know what you are doing.

Ephemeral elliptic curve Diffie-Hellman key agreement in Java

Update 2 (17th May, 2017): I’ve written some notes on correctly validating ECDH public keys

Update (20th April, 2017): I’ve noticed that this article gets by far the most daily hits on my blog. This worries me that people are using this code as a template for building real ECDHE key agreement, when it was only intended as a guide to the Java API. There are a lot of details in safe construction of such a protocol. More secure alternatives than to trying to roll this yourself include the various complete protocols listed at the end of the article. With that said, we’ll get back to the original article:

Diffie-Hellman key agreement (DH) is a way for two parties to agree on a symmetric secret key without explicitly communicating that secret key. As such, it provides a way for the parties to negotiate a shared AES cipher key or HMAC shared secret over a potentially insecure channel. It does not by itself provide authentication, however, so it is vulnerable to man-in-the-middle attacks without additional measures. There are several ways to provide these additional measures (e.g. signing the ephemeral public keys using a CA-issued certificate, or using a protocol like OTR), but we will not discuss them here, or go into the details of how the key agreement works. Java provides support out-of-the-box for both original discrete log DH and elliptic curve (ECDH) key agreement protocols, although the latter may not be supported on all JREs. ECDH should be preferred for any new applications as it provides significantly improved security for reasonable key sizes.

elliptic curve
An elliptic curve defined by y2 = x3 – 2x + 2
As is often the case in Java, the use of these classes can be a bit convoluted. Here we demonstrate simple Java code for ECDH key agreement on the command line. We only demonstrate ephemeral key agreement, in which the two parties generate unique public/private key pairs at the start of the protocol and throw them away once the shared secret has been negotiated. This can form the basis for perfect forward secrecy.

WARNING: the code here is not a complete security protocol and should be used for reference on the Java API only.

Continue reading “Ephemeral elliptic curve Diffie-Hellman key agreement in Java”