<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>lvh (Posts about cryptography)</title><link>https://www.lvh.io/</link><description></description><atom:link href="https://www.lvh.io/tags/cryptography.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Thu, 03 Mar 2022 16:37:53 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>How (not) to sign a JSON object</title><link>https://www.lvh.io/posts/how-not-to-sign-a-json-object/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;Last year we did a blog post on interservice auth. This post is mostly about authenticating consumers to an API. That’s a related but subtly different problem: you can probably impose more requirements on your internal users than your customers. The idea is the same though: you’re trying to differentiate between a legitimate user and an attacker, usually by getting the legitimate user to prove that they know a credential that the attacker doesn’t.&lt;/p&gt;
&lt;h2&gt;You don’t really want a signature&lt;/h2&gt;
&lt;p&gt;When cryptography engineers say "signature" they tend to mean something asymmetric, like RSA or ECDSA. Developers reach for asymmetric tools too often. There are a lot of ways to screw them up. By comparison, symmetric “signing” (MACs) are easy to use and hard to screw up. HMAC is bulletproof and ubiquitous.&lt;/p&gt;
&lt;p&gt;Unless you have a good reason why you need an (asymmetric) signature, you want a MAC. If you really do want a signature, check out our Cryptographic Right Answers post to make that as safe as possible. For the rest of this blog post, "signing" means symmetrically, and in practice that means HMAC.&lt;/p&gt;
&lt;h2&gt;How to sign a JSON object&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Serialize however you want.&lt;/li&gt;
&lt;li&gt;HMAC. With SHA256? Sure, whatever. We did &lt;a href="https://latacora.singles/2018/04/03/cryptographic-right-answers.html"&gt;a blog post&lt;/a&gt; on that too.&lt;/li&gt;
&lt;li&gt;Concatenate the tag with the message, maybe with a comma in between for easy parsing or something.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Wait, isn’t that basically a HS256 JWT?&lt;/h2&gt;
&lt;p&gt;Shut up. Anyway, no, because you need to parse a header to read the JWT, so you inherit all of the problems that stem from that.&lt;/p&gt;
&lt;h2&gt;How &lt;em&gt;not&lt;/em&gt; to sign a JSON object, if you can help it&lt;/h2&gt;
&lt;p&gt;Someone asked how to sign a JSON object "in-band": where the tag is part of the object you’re signing itself. That's a niche use case, but it happens. You have a JSON object that a bunch of intermediate systems want to read and it’s important  none of them mess with its contents. You can't just send &lt;code&gt;tag || json&lt;/code&gt;: that may be the cryptographically right answer, but now it's not a JSON object anymore so third party services and middleboxes will barf. You also can't get them to reliably pass the tag around as metadata (via a HTTP header or something). You need to put the key &lt;em&gt;on the JSON object&lt;/em&gt;, somehow, to "transparently" sign it. Anyone who cares about validating the signature can, and anyone who cares that the JSON object has a particular structure doesn't break (because the blob is still JSON and it still has the data it's supposed to have in all the familiar places).&lt;/p&gt;
&lt;p&gt;This problem sort-of reminds me of format-preserving encryption. I don’t mean that in a nice way, because there’s no nice way to mean that. Format-preserving encryption means you encrypt a credit card number and the result still sorta looks like a credit card number. It’s terrible and you only do it because you have to. Same with in-band JSON signing.&lt;/p&gt;
&lt;p&gt;As stated, in-band JSON signing means modifying a JSON object (e.g. removing the HMAC tag) and validating that it’s the same thing that was signed. You do that by computing the HMAC again and validating the result. Unfortunately there are infinitely many equal JSON objects with distinct byte-level representations (for some useful definition of equality, like Python’s builtin ==).&lt;/p&gt;
&lt;p&gt;Some of those differences are trivial, while others are fiendishly complicated. You can add as many spaces as you want between some parts of the grammar, like after the colon and before the value in an object. You can reorder the keys in an object. You can escape a character using a Unicode escape sequence (\u2603) instead of using the UTF-8 representation. "UTF-8" may be a serialization format for Unicode, but it’s not a canonicalization technique. If a character has multiple diacritics, they might occur in different orders. Some characters can be written as a base character plus a diacritic, but there’s also an equivalent single character. You can’t always know what the “right” character out of context: is this the symbol for the unit of resistance (U+2126 OHM SIGN) or a Greek capital letter Omega (U+03A9)? Don’t even get me started on the different ways you can write the same floating point number!&lt;/p&gt;
&lt;p&gt;Three approaches:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Canonicalize the JSON.&lt;/li&gt;
&lt;li&gt;Add the tag and the exact string you signed to the object, validate the signature and then validate that the JSON object is the same as the one you got.&lt;/li&gt;
&lt;li&gt;Create an alternative format with an easier canonicalization than JSON.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Canonicalization&lt;/h3&gt;
&lt;p&gt;Canonicalization means taking an object and producing a unique representation for it. Two objects that mean the same thing ("are equal") but are expressed differently canonicalize to the same representation.&lt;/p&gt;
&lt;p&gt;Canonicalization is a quagnet, which is a term of art in vulnerability research meaning quagmire and vulnerability magnet. You can tell it’s bad just by how hard it is to type ‘canonicalization’.&lt;/p&gt;
&lt;p&gt;My favorite canonicalization bug in recent memory is probably Kelby Ludwig’s SAML bug. Hold onto your butts, because this bug broke basically every SAML implementation under the sun in a masterful stroke. It used NameIds (SAML-speak for "the entity this assertion is about") that look like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;NameId&amp;gt;&lt;/span&gt;barney@latacora.com&lt;span class="c"&gt;&amp;lt;!----&amp;gt;&lt;/span&gt;.evil.com&lt;span class="nt"&gt;&amp;lt;/NameId&amp;gt;&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;The common canonicalization strategy ("exc-c14n") will remove comments, so that side sees “barney@latacora.com.evil.com”. The common parsing strategy (“yolo”) disagrees, and sees a text node, a comment, and another text node. Since everyone is expecting a NameId to have one text node, you grab the first one. But that says barney@latacora.com, which isn’t what the IdP signed or your XML-DSIG library validated.&lt;/p&gt;
&lt;p&gt;Not to worry: we said we were doing JSON, and JSON is not XML. It’s simpler! Right? There are at least two specs here: Canonical JSON (from OLPC) and an IETF draft (https://tools.ietf.org/id/draft-rundgren-json-canonicalization-scheme-05.html). They work? Probably? But they’re not fun to implement.&lt;/p&gt;
&lt;h3&gt;Include the exact thing you’re signing&lt;/h3&gt;
&lt;p&gt;If you interpret the problem as "to validate a signature I need an exact byte representation of what to sign" and canonicalization is just the default mechanism for getting to an exact byte representation, you could also just attach a specific byte serialization to the object with a tag for it.&lt;/p&gt;
&lt;p&gt;You validate the tag matches the specific serialization, and then you validate that the specific serialization matches the outside object with the tag and specific serialization removed. The upside is that you don’t need to worry about canonicalization; the downside is your messages are about twice the size that they need to be. You can maybe make that a little better with compression, since the repeated data is likely to compress well.&lt;/p&gt;
&lt;h3&gt;The regex bait and switch trick&lt;/h3&gt;
&lt;p&gt;If you interpret the problem as being about already having a perfectly fine serialization to compute a tag over, but the JSON parser/serializer roundtrip screwing it up after you compute the tag, you might try to do something to the serialized format that doesn't know it's JSON. This is a variant of the previous approach: you're just not adding a &lt;em&gt;second&lt;/em&gt; serialization to compute the tag over.&lt;/p&gt;
&lt;p&gt;The clever trick here is to add a field of the appropriate size for your tag with a well-known fake value, then HMAC, then swap the value. For example, if you know the tag is HMAC-SHA256, your tag size is 256 bits aka 32 bytes aka 64 hex chars. You add a unique key (something like &lt;code&gt;__hmac_tag&lt;/code&gt;) with a value of 64 well-known bytes, e.g. 64 ASCII zero bytes. Serialize the object and compute its HMAC. If you document some subset of JSON serialization (e.g. where CRLFs can occur or where extra spaces can occur), you know that the string &lt;code&gt;"__hmac_tag": “000...”&lt;/code&gt; will occur in the serialized byte stream. Now, you can use string replacement to shiv in the real HMAC value. Upon receipt, the decoder finds the tag, reads the HMAC value, replaces it with zeroes, computes the expected tag and compares against the previously read value.&lt;/p&gt;
&lt;p&gt;Because there’s no JSON roundtripping, the parser can’t mess up the JSON object’s specific serialization. The key needs to be unique because of course the string replacement or regular expression doesn’t know how to parse JSON.&lt;/p&gt;
&lt;p&gt;This feels weirdly gross? But at the same time probably less annoying than canonicalization. And it doesn't work if any of the middleboxes modiy the JSON through a parse/re-serialize cycle.&lt;/p&gt;
&lt;h3&gt;An alternative format&lt;/h3&gt;
&lt;p&gt;If you interpret the problem as "canonicalization is hard because JSON is more complex than what I really want to sign", you might think the answer is to reformat the data you want to sign in a format where canonicalization is easy or even automatic.  AWS Signatures do this: there’s a serialization format that’s far less flexible than JSON where you put some key parameters, and then you HMAC that. (There’s an interesting part to it where it also incorporates the hash of the exact message you’re signing -- but we’ll get to that later.)&lt;/p&gt;
&lt;p&gt;This is particularly attractive if there’s a fixed set of simple values you have to sign, or more generally if the thing you’re signing has a predictable format.&lt;/p&gt;
&lt;h2&gt;Request signing in practice&lt;/h2&gt;
&lt;p&gt;Let’s apply this model to a case study of request signing has worked through the years in some popular services. These are not examples of how to do it well, but rather cautionary tales.&lt;/p&gt;
&lt;p&gt;First off, AWS. AWS requires you to sign API requests. The current spec is "v4", which tells you that there is probably at least one interesting version that preceded it.&lt;/p&gt;
&lt;h3&gt;AWS Signing v1&lt;/h3&gt;
&lt;p&gt;Let’s say an AWS operation CreateWidget takes attribute Name which can be any ASCII string. It also takes an attribute Unsafe, which is false by default and the attacker wishes were true. V1 concatenates the key-value pairs you’re signing, so something like Operation=CreateWidget&amp;amp;Name=iddqd became OperationCreateWidgetNameiddqd. You then signed the resulting string using HMAC.&lt;/p&gt;
&lt;p&gt;The problem with this is if I can get you to sign messages for creating widgets with arbitrary names, I can get you to sign operations for arbitrary CreateWidget requests: I just put all the extra keys and values I want in the value you’re signing for me. For example, the request signature for creating a widget named &lt;code&gt;iddqdUnsafetrue&lt;/code&gt; is exactly the same as a request signature for creating a widget named &lt;code&gt;iddqd&lt;/code&gt; with Unsafe equal to true: OperationCreateWidgetNameiddqdUnsafetrue.&lt;/p&gt;
&lt;h3&gt;AWS Signing V2&lt;/h3&gt;
&lt;p&gt;Security-wise: fine.&lt;/p&gt;
&lt;p&gt;Implementation-wise: it’s limited to query-style requests (query parameters for GET, x-www-form-urlencoded for POST bodies) and didn’t support other methods, let alone non-HTTP requests. Sorting request parameters is a burden for big enough requests. Nothing for chunked requests either.&lt;/p&gt;
&lt;p&gt;(Some context: even though most AWS SDKs present you with a uniform interface, there are several different protocol styles in use within AWS. For example, EC2 and S3 are their own thing, some protocols use Query Requests (basically query params in GET queries and POST formencoded bodies), others use REST+JSON, some use REST+XML… There’s even some SOAP! But I think that’s on its way out.)&lt;/p&gt;
&lt;h3&gt;AWS Signing V3&lt;/h3&gt;
&lt;p&gt;AWS doesn’t seem to like V3 very much. The &lt;a href="https://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html"&gt;"what’s new in v4 document"&lt;/a&gt; all but disavows it’s existence, and no live services appear to implement it. It had some annoying problems like distinguishing between signed and unsigned headers (leaving the service to figure it out) and devolving to effectively a bearer token when used over TLS (which is great, as long as it actually gets used over TLS).&lt;/p&gt;
&lt;p&gt;Given how AWS scrubbed it away, it’s hard to say anything with confidence. I’ve found implementations, but that’s not good enough: an implementation may only use a portion of the spec while the badness can be hiding in the rest.&lt;/p&gt;
&lt;h3&gt;AWS Signing V4&lt;/h3&gt;
&lt;p&gt;Security-wise: fine.&lt;/p&gt;
&lt;p&gt;Addressed some problems noted in V2; for example: just signs the raw body bytes and doesn’t care about parameter ordering. This is pretty close to the original recommendation: don’t do inline signing at all, just sign the exact message you’re sending and put a MAC tag on the outside. A traditional objection is that several equivalent requests would have a different representation, e.g. the same arguments but in a different order. It just turns out that in most cases that doesn’t matter, and API auth is one of those cases.&lt;/p&gt;
&lt;p&gt;Also note that all of these schemes are really outside signing, but they’re still interesting because they had a lot of the problems you see on an inline signing scheme (they were just mostly unforced errors).&lt;/p&gt;
&lt;h3&gt;AWS Signing V0&lt;/h3&gt;
&lt;p&gt;For completeness. It is even harder to find than V3: you have to spelunk some SDKs for it. I hear it might have been HMAC(k, service || operation || timestamp), so it didn’t really sign much of the request.&lt;/p&gt;
&lt;h3&gt;Flickr’s API signing&lt;/h3&gt;
&lt;p&gt;One commonality of the AWS vulnerabilities is that none of them attacked the primitive. All of them used HMAC and HMAC has always been safe. Flickr had exactly the same bug as AWS V1 signing, but also used a bad MAC. The tag you sent was MD5(secret + your_concatenated_key_value_pairs). We’ll leave the details of extension attacks for a different time, but the punchline is that if you know the value of H(secret + message) and don’t know s, you get to compute H(secret + message + glue + message2), where glue is some binary nonsense and message2 is an arbitrary attacker controlled string.&lt;/p&gt;
&lt;p&gt;A typical protocol where this gets exploited looks somewhat like query parameters. The simplest implementation will just loop over every key-value pair and assign the value into an associative array. So if you have user=lvh&amp;amp;role=user, I might be able to extend that to a valid signature for user=lvh&amp;amp;role=userSOMEBINARYGARBAGE&amp;amp;role=admin.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Just go ahead and always enforce TLS for your APIs.&lt;/li&gt;
&lt;li&gt;Maybe you don’t need request signing? A bearer token header is fine, or HMAC(k, timestamp) if you’re feeling fancy, or mTLS if you really care.&lt;/li&gt;
&lt;li&gt;Canonicalization is fiendishly difficult.&lt;/li&gt;
&lt;li&gt;Add a signature on the outside of the request body, make sure the request body is complete, and don’t worry about "signing what is said versus what is meant" -- it’s OK to sign the exact byte sequence.&lt;/li&gt;
&lt;li&gt;The corollary here is that it’s way harder to do request signing for a REST API (where stuff like headers and paths and methods matter) than it is to do signing for an RPC-like API.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(This post was syndicated on the Latacora blog.)&lt;/p&gt;</description><category>cryptography</category><category>security</category><guid>https://www.lvh.io/posts/how-not-to-sign-a-json-object/</guid><pubDate>Thu, 25 Jul 2019 01:56:06 GMT</pubDate></item><item><title>The PGP problem</title><link>https://www.lvh.io/posts/the-pgp-problem/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;&lt;a href="https://blog.cryptographyengineering.com/2014/08/13/whats-matter-with-pgp/"&gt;Cryptography engineers have been tearing their hair out over PGP’s deficiencies&lt;/a&gt; for (literally) decades. When other kinds of engineers get wind of this, they’re shocked. PGP is bad? Why do people keep telling me to use PGP? The answer is that they shouldn’t be telling you that, because PGP is bad and needs to go away.&lt;/p&gt;
&lt;p&gt;There are, as you’re about to see, lots of problems with PGP. Fortunately, if you’re not morbidly curious, there’s a simple meta-problem with it: it was designed in the 1990s, before serious modern cryptography. No competent crypto engineer would design a system that looked like PGP today, nor tolerate most of its defects in any other design. Serious cryptographers have largely given up on PGP and don’t spend much time publishing on it anymore (&lt;a href="https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-poddebniak.pdf"&gt;with a notable exception&lt;/a&gt;). Well-understood problems in PGP have gone unaddressed for over a decade because of this.&lt;/p&gt;
&lt;p&gt;Two quick notes: first, we wrote this for engineers, not lawyers and activists. Second: “PGP” can mean a bunch of things, from the &lt;a href="https://tools.ietf.org/html/rfc4880"&gt;OpenPGP standard&lt;/a&gt; to its reference implementation in GnuPG. We use the term “PGP” to cover all of these things.&lt;/p&gt;
&lt;h2&gt;The Problems&lt;/h2&gt;
&lt;h3&gt;Absurd Complexity&lt;/h3&gt;
&lt;p&gt;For reasons none of us here in the future understand, PGP has a packet-based structure. A PGP message (in a “.asc” file) is an archive of typed packets. There are &lt;a href="https://tools.ietf.org/html/rfc4880#page-13"&gt;at least 8 different ways&lt;/a&gt; of encoding the length of a packet, depending on whether you’re using “new” or “old” format packets. The “new format” packets have variable-length lengths, like BER (try to write a PGP implementation and you may wish for the sweet release of ASN.1). Packets can have subpackets. There are overlapping variants of some packets. The most recent keyserver attack happened because GnuPG &lt;a href="https://threadreaderapp.com/thread/1147162583969009664.html"&gt;accidentally went quadratic&lt;/a&gt; in parsing keys, which also follow this deranged format.&lt;/p&gt;
&lt;p&gt;That’s just the encoding. The actual system doesn’t get simpler. There are keys and subkeys. Key IDs and key servers and key signatures. Sign-only and encrypt-only. Multiple “key rings”. Revocation certificates. Three different compression formats. This is all before we get to smartcard support.&lt;/p&gt;
&lt;h3&gt;Swiss Army Knife Design&lt;/h3&gt;
&lt;p&gt;If you’re stranded in the woods and, I don’t know, need to repair your jean cuffs, it’s handy if your utility knife has a pair of scissors. But nobody who does serious work uses their multitool scissors regularly.&lt;/p&gt;
&lt;p&gt;A Swiss Army knife does a bunch of things, all of them poorly. PGP does a mediocre job of signing things, a relatively poor job of encrypting them with passwords, and a pretty bad job of encrypting them with public keys. PGP is not an especially good way to securely transfer a file. It’s a clunky way to sign packages. It’s not great at protecting backups. It’s a downright dangerous way to converse in secure messages.&lt;/p&gt;
&lt;p&gt;Back in the MC Hammer era from which PGP originates, “encryption” was its own special thing; there was one tool to send a file, or to back up a directory, and another tool to encrypt and sign a file. Modern cryptography doesn’t work like this; it’s purpose built. Secure messaging wants crypto that is different from secure backups or package signing.&lt;/p&gt;
&lt;h3&gt;Mired In Backwards Compatibility&lt;/h3&gt;
&lt;p&gt;PGP predates modern cryptography; there are Hanson albums that have aged better. If you’re lucky, your local GnuPG defaults to 2048-bit RSA, the 64-bit-block CAST5 cipher in CFB, and the OpenPGP MDC checksum (about which more later). If you encrypt with a password rather than with a public key, the OpenPGP protocol specifies PGP’s S2K password KDF. These are, to put it gently, not the primitives a cryptography engineer would select for a modern system.&lt;/p&gt;
&lt;p&gt;We’ve learned a lot since Steve  Urkel graced the airwaves during ABC’s TGIF: that you should authenticate your ciphertexts (and avoid CFB mode) would be an obvious example, but also that 64-bit block ciphers are bad, that we can do much better than RSA, that mixing compression and encryption is dangerous, and that KDFs should be both time- and memory-hard.&lt;/p&gt;
&lt;p&gt;Whatever the OpenPGP RFCs may say, you’re probably not doing any of these things if you’re using PGP, nor can you predict when you will. Take AEAD ciphers: the Rust-language Sequoia PGP defaulted to the AES-EAX AEAD mode, which is great, and nobody can read those messages because most PGP installs don’t know what EAX mode is, which is not great. Every well-known bad cryptosystem eventually sprouts an RFC extension that supports curves or AEAD, so that its proponents can claim on message boards that they support modern cryptography. RFC’s don’t matter: only the installed base does. We’ve understood authenticated encryption for 2 decades, and PGP is old enough to buy me drinks; enough excuses.&lt;/p&gt;
&lt;p&gt;You can have backwards compatibility with the 1990s or you can have sound cryptography; &lt;em&gt;you can’t have both&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Obnoxious UX&lt;/h3&gt;
&lt;p&gt;We can’t say this any better than Ted Unangst:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There was a PGP usability study conducted a few years ago where a group of technical people were placed in a room with a computer and asked to set up PGP. Two hours later, they were never seen or heard from again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you’d like empirical data of your own to back this up, here’s an experiment you can run: find an immigration lawyer and talk them through the process of getting Signal working on their phone. You probably don’t suddenly smell burning toast. Now try doing that with PGP.&lt;/p&gt;
&lt;h3&gt;Long-Term Secrets&lt;/h3&gt;
&lt;p&gt;PGP begs users to keep a practically-forever root key tied to their identity. It does this by making keys annoying to generate and exchange, by encouraging “key signing parties”, and by creating a “web of trust” where keys depend on other keys.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.filippo.io/giving-up-on-long-term-pgp/"&gt;Long term keys are almost never what you want&lt;/a&gt;. If you keep using a key, it eventually gets exposed. You want the blast radius of a compromise to be as small as possible, and, just as importantly, you don’t want users to hesitate even for a moment at the thought of rolling a new key if there’s any concern at all about the safety of their current key.&lt;/p&gt;
&lt;p&gt;The PGP cheering section will immediately reply “that’s why you keep keys on a Yubikey”. To a decent first approximation, nobody in the whole world uses the expensive Yubikeys that do this, and you can’t imagine a future in which that changes (we can barely get U2F rolled out, and those keys are disposable). We can’t accept bad cryptosystems just to make Unix nerds feel better about their toys.&lt;/p&gt;
&lt;h3&gt;Broken Authentication&lt;/h3&gt;
&lt;p&gt;More on PGP’s archaic primitives: way back in 2000, the OpenPGP working group realized they needed to authenticate ciphertext, and that PGP’s signatures weren’t accomplishing that. So OpenPGP invented &lt;a href="https://tools.ietf.org/html/rfc4880#section-5.14"&gt;the MDC system&lt;/a&gt;: PGP messages with MDCs attach a SHA-1 of the plaintext to the plaintext, which is then encrypted (as normal) in CFB mode.&lt;/p&gt;
&lt;p&gt;If you’re wondering how PGP gets away with this when modern systems use relatively complex AEAD modes (why can’t everyone just tack a SHA-1 to their plaintext), you’re not alone. Where to start with this Rube Goldberg contraption? The PGP MDC can be stripped off messages  it was encoded in such a way that you can simply chop off the last 22 bytes of the ciphertext to do that. To retain backwards compatibility with insecure older messages, PGP introduced a new packet type to signal that the MDC needs to be validated; if you use the wrong type, the MDC doesn’t get checked. Even if you do, the new SEIP packet format is close enough to the insecure SE format that you can potentially trick readers into downgrading; &lt;a href="https://mailarchive.ietf.org/arch/msg/openpgp/tB00vO5r-qneX9wz1xz3netpXVU"&gt;Trevor Perrin worked the SEIP out to 16 whole bits of security.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And, finally, even if everything goes right, the reference PGP implementation will (wait for it) release unauthenticated plaintext to callers, &lt;em&gt;even if the MDC doesn’t match&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Incoherent Identity&lt;/h3&gt;
&lt;p&gt;PGP is an application. It’s a set of integrations with other applications. It’s a file format. It’s also a social network, and a subculture.&lt;/p&gt;
&lt;p&gt;PGP pushes notion of a cryptographic identity. You generate a key, save it in your keyring, print its fingerprint on your business card, and publish it to a keyserver. You sign other people’s keys. They in turn may or may not rely on your signatures to verify other keys. Some people go out of their way to meet other PGP users in person to exchange keys and more securely attach themselves to this “web of trust”. Other people organize “key signing parties”. The image you’re conjuring in your head of that accurately explains how hard it is to PGP’s devotees to switch to newer stuff.&lt;/p&gt;
&lt;p&gt;None of this identity goop works. Not the key signing web of trust, not the keyservers, not the parties. Ordinary people will trust anything that looks like a PGP key no matter where it came from  how could they not, when even an expert would have a hard time articulating how to evaluate a key? Experts don’t trust keys they haven’t exchanged personally. Everyone else relies on centralized authorities to distribute keys. PGP’s key distribution mechanisms are theater.&lt;/p&gt;
&lt;h3&gt;Leaks Metadata&lt;/h3&gt;
&lt;p&gt;Forget the email debacle for a second (we’ll get to that later). PGP by itself leaks metadata. Messages are (in normal usage) linked directly to key identifiers, which are, throughout PGP’s cobweb of trust, linked to user identity. Further, a rather large fraction of PGP users make use of keyservers, which can themselves leak to the network the identities of which PGP users are communicating with each other.&lt;/p&gt;
&lt;h3&gt;No Forward Secrecy&lt;/h3&gt;
&lt;p&gt;A good example of that last problem: secure messaging crypto demands forward secrecy. Forward secrecy means that if you lose your key to an attacker today, they still can’t go back and read yesterday’s messages; they had to be there with the key yesterday to read them. In modern cryptography engineering, we assume our adversary is recording everything, into infinite storage. PGP’s claimed adversaries include world governments, many of whom are certainly doing exactly that. Against serious adversaries and without forward secrecy, breaches are a question of “when”, not “if”.&lt;/p&gt;
&lt;p&gt;To get forward secrecy in practice, you typically keep two secret keys: a short term session key and a longer-term trusted key. The session key is ephemeral (usually the product of a DH exchange) and the trusted key signs it, so that a man-in-the-middle can’t swap their own key in. It’s theoretically possible to achieve a facsimile of forward secrecy using the tools PGP provides. Of course, pretty much nobody does this.&lt;/p&gt;
&lt;h3&gt;Clumsy Keys&lt;/h3&gt;
&lt;p&gt;An OpenBSD signify(1) public key is a Base64 string short enough to fit in the middle of a sentence in an email; the private key, which isn’t an interchange format, is just a line or so longer. A PGP public key is a whole giant Base64 document; if you’ve used them often, you’re probably already in the habit of attaching them rather than pasting them into messages so they don’t get corrupted. Signify’s key is a state-of-the-art Ed25519 key; PGP’s is a weaker RSA key.&lt;/p&gt;
&lt;p&gt;You might think this stuff doesn’t matter, but it matters a lot; orders of magnitude more people use SSH and manage SSH keys than use PGP. SSH keys are trivial to handle; PGP’s are not.&lt;/p&gt;
&lt;h3&gt;Negotiation&lt;/h3&gt;
&lt;p&gt;PGP supports ElGamal. PGP supports RSA. PGP supports the NIST P-Curves. PGP supports Brainpool. PGP supports Curve25519. PGP supports SHA-1. PGP supports SHA-2. PGP supports RIPEMD160. PGP supports IDEA. PGP supports 3DES. PGP supports CAST5. PGP supports AES. There is no way this is a complete list of what PGP supports.&lt;/p&gt;
&lt;p&gt;If we’ve learned 3 important things about cryptography design in the last 20 years, at least 2 of them are that negotiation and compatibility are evil. The flaws in cryptosystems tend to appear in the joinery, not the lumber, and expansive crypto compatibility increases the amount of joinery. Modern protocols like TLS 1.3 are jettisoning backwards compatibility with things like RSA, not adding it. New systems support &lt;em&gt;just a single suite of primitives&lt;/em&gt;, and a simple version number. If one of those primitives fails, you bump the version and chuck the old protocol all at once.&lt;/p&gt;
&lt;p&gt;If we’re unlucky, and people are still using PGP 20 years from now, PGP will be the only reason any code anywhere includes CAST5. We can’t say this more clearly or often enough: you can have backwards compatibility with the 1990s or you can have sound cryptography; you can’t have both.&lt;/p&gt;
&lt;h3&gt;Janky Code&lt;/h3&gt;
&lt;p&gt;The de facto standard implementation of PGP is GnuPG. GnuPG is not carefully built. It’s a sprawling C-language codebase with duplicative functionality (write-ups of the most recent SKS key parsing denial of service noted that it has multiple key parsers, for instance) with a &lt;a href="https://www.cvedetails.com/vulnerability-list/vendor_id-4711/Gnupg.html"&gt;long track record of CVEs&lt;/a&gt; ranging from memory corruption to cryptographic side channels. It has at times been possible to strip authenticators off messages without GnuPG noticing. It’s been possible to feed it keys that don’t fingerprint properly without it noticing. The 2018 Efail vulnerability was a result of it releasing unauthenticated plaintext to callers. GnuPG is not good.&lt;/p&gt;
&lt;p&gt;GnuPG is also effectively the reference implementation for PGP, and also the basis for most other tools that integrate PGP cryptography. It isn’t going anywhere. To rely on PGP is to rely on GPG.&lt;/p&gt;
&lt;h2&gt;The Answers&lt;/h2&gt;
&lt;p&gt;One of the rhetorical challenges of persuading people to stop using PGP is that there’s no one thing you can replace it with, &lt;em&gt;nor should there be&lt;/em&gt;. What you should use instead depends on what you’re doing.&lt;/p&gt;
&lt;h3&gt;Talking To People&lt;/h3&gt;
&lt;p&gt;Use Signal. Or Wire, or WhatsApp, or some other Signal-protocol-based secure messenger.&lt;/p&gt;
&lt;p&gt;Modern secure messengers are purpose-built around messaging. They use privacy-preserving authentication handshakes, repudiable messages, &lt;em&gt;cryptographic ratchets&lt;/em&gt; that rekey on every message exchange, and, of course, modern encryption primitives. Messengers are trivially easy to use and there’s no fussing over keys and subkeys. If you use Signal, you get even more than that: you get a system so paranoid about keeping private metadata off servers that it tunnels Giphy searches to avoid traffic analysis attacks, and until relatively recently didn’t even support user profiles.&lt;/p&gt;
&lt;h3&gt;Encrypting Email&lt;/h3&gt;
&lt;p&gt;Don’t.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=16088386"&gt;Email is insecure&lt;/a&gt;. Even with PGP, it’s default-plaintext, which means that even if you do everything right, some totally reasonable person you mail, doing totally reasonable things, will invariably CC the quoted plaintext of your encrypted message to someone else (we don’t know a PGP email user who hasn’t seen this happen). PGP email is forward-insecure. Email metadata, including the subject (which is literally message content), are always plaintext.&lt;/p&gt;
&lt;p&gt;If you needed another reason, &lt;a href="https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-poddebniak.pdf"&gt;read the Efail paper&lt;/a&gt;. The GnuPG community, &lt;a href="https://web.archive.org/web/20181225214730/https://flaked.sockpuppet.org/2018/05/16/a-unified-timeline.html"&gt;which mishandled the Efail disclosure&lt;/a&gt;, talks this research down a lot, but it was accepted at Usenix Security (one of the top academic software security venues) and at Black Hat USA (&lt;em&gt;the&lt;/em&gt; top industry software security venue), was one of the best cryptographic attacks of the last 5 years, and is a pretty devastating indictment of the PGP ecosystem. As you’ll see from the paper, S/MIME isn’t better.&lt;/p&gt;
&lt;p&gt;This isn’t going to get fixed. To make actually-secure email, you’d have to tunnel another protocol over email (you’d still be conceding traffic analysis attacks). At that point, why bother pretending?&lt;/p&gt;
&lt;p&gt;Encrypting email is asking for a calamity. Recommending email encryption to at-risk users is malpractice. Anyone who tells you it’s secure to communicate over PGP-encrypted email is putting their weird preferences ahead of your safety.&lt;/p&gt;
&lt;h3&gt;Sending Files&lt;/h3&gt;
&lt;p&gt;Use &lt;a href="https://github.com/warner/magic-wormhole"&gt;Magic Wormhole&lt;/a&gt;. Wormhole clients use a one-time password-authenticated key exchange (PAKE) to encrypt files to recipients. It’s easy (for nerds, at least), secure, and fun: we haven’t introduced wormhole to anyone who didn’t start gleefully wormholing things immediately just like we did.&lt;/p&gt;
&lt;p&gt;Someone stick a Windows installer on a Go or Rust implementation of Magic Wormhole right away; it’s too great for everyone not to have.&lt;/p&gt;
&lt;p&gt;If you’re working with lawyers and not with technologists, Signal does a perfectly cromulent job of securing file transfers. Put a Signal number on your security page to receive bug bounty reports, not a PGP key.&lt;/p&gt;
&lt;h3&gt;Encrypting Backups&lt;/h3&gt;
&lt;p&gt;Use Tarsnap. &lt;a href="https://www.tarsnap.com/design.html"&gt;Colin can tell you all about how Tarsnap is optimized to protect backups.&lt;/a&gt; Or really, use any other encrypted backup tool that lots of other people use; they won’t be as good as Tarsnap but they’ll all do a better job than PGP will.&lt;/p&gt;
&lt;p&gt;Need offline backups? Use encrypted disk images; they’re built into modern Windows, Linux, and macOS. &lt;a href="https://sockpuppet.org/blog/2014/04/30/you-dont-want-xts/"&gt;Full disk encryption isn’t great&lt;/a&gt;, but it works fine for this use case, and it’s easier and safer than PGP.&lt;/p&gt;
&lt;h3&gt;Signing Packages&lt;/h3&gt;
&lt;p&gt;Use Signify/Minisign. &lt;a href="https://www.openbsd.org/papers/bsdcan-signify.html"&gt;Ted Unangst will tell you all about it.&lt;/a&gt; It’s what OpenBSD uses to sign packages. It’s extremely simple and uses modern signing. &lt;a href="https://jedisct1.github.io/minisign/"&gt;Minisign&lt;/a&gt;, from Frank Denis, the libsodium guy, brings the same design to Windows and macOS; it has bindings for Go, Rust, Python, Javascript, and .NET; it’s even compatible with Signify.&lt;/p&gt;
&lt;h3&gt;Encrypting Application Data&lt;/h3&gt;
&lt;p&gt;Use  &lt;a href="https://github.com/jedisct1/libsodium"&gt;libsodium&lt;/a&gt; It builds everywhere, has interface that’s designed to be hard to misuse, and you won’t have to shell out to a binary to use it.&lt;/p&gt;
&lt;h3&gt;Encrypting Files&lt;/h3&gt;
&lt;p&gt;This really is a problem. If you’re/not/making a backup, and you’re /not/archiving something offline for long-term storage, and you’re /not/encrypting in order to securely send the file to someone else, and you’re /not/encrypting virtual drives that you mount/unmount as needed to get work done, then there’s no one good tool that does this now. Filippo Valsorda is working on “&lt;a href="https://docs.google.com/document/d/11yHom20CrsuX8KQJXBBw04s80Unjv8zCg_A7sPAX_9Y/view"&gt;age&lt;/a&gt;” for these use cases, and I'm super optimistic about it, but it's not there yet.&lt;/p&gt;
&lt;p&gt;Hopefully it’s clear that this is a pretty narrow use case. We work in software security and handle sensitive data, including bug bounty reports (another super common “we need PGP!” use case), and we almost never have to touch PGP.&lt;/p&gt;
&lt;p&gt;(This post was syndicated on the Latacora blog.)&lt;/p&gt;</description><category>cryptography</category><category>security</category><guid>https://www.lvh.io/posts/the-pgp-problem/</guid><pubDate>Wed, 17 Jul 2019 03:14:00 GMT</pubDate></item><item><title>Analyzing a simple encryption scheme using GitHub SSH keys</title><link>https://www.lvh.io/posts/analyzing-a-simple-encryption-scheme-using-github-ssh-keys/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;(This is an introductory level analysis of a scheme involving RSA. If you're already comfortable with Bleichenbacher oracles you should skip it.)&lt;/p&gt;
&lt;p&gt;Someone pointed me at the following suggestion on the Internet for encrypting secrets to people based on their GitHub SSH keys. I like the idea of making it easier for people to leverage key material and tools they already have.  The encryption instructions are:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"my secret"&lt;/span&gt; &amp;gt; message.txt
curl -q github.com/&lt;span class="nv"&gt;$USER&lt;/span&gt;.keys &lt;span class="p"&gt;|&lt;/span&gt; head -n &lt;span class="m"&gt;1&lt;/span&gt; &amp;gt; recipient.pub
ssh-keygen -e -m pkcs8 -f recipient.pub &amp;gt; recipient.pem
openssl rsautl -encrypt -pubin -inkey recipient.pem -ssl &lt;span class="se"&gt;\&lt;/span&gt;
    -in message.txt -out encrypted.txt
&lt;/pre&gt;


&lt;p&gt;Anything using an openssl command line tool makes me a little uncomfortable. Let's poke at it a little.&lt;/p&gt;
&lt;p&gt;We'll assume that that first key is really an RSA key and we don't have to worry about EdDSA or ECDSA (or heaven forbid, DSA). You're encrypting a password for someone. The straightforward threat model is an attacker who has the public key and ciphertext (but no plaintext) and wants to decrypt the ciphertext.&lt;/p&gt;
&lt;p&gt;There are a few ways you can try to attack RSA schemes. You could attack the underlying math: maybe the keys were generated with insufficient entropy (e.g. &lt;a href="https://www.lvh.io/posts/analyzing-a-simple-encryption-scheme-using-github-ssh-keys/%5Bcve.mitre.org/cgi-bin/c...%5D(http:/cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2008-0166)"&gt;the Debian weak SSH keys problem&lt;/a&gt;) or bogus prime generation (e.g. &lt;a href="https://www.lvh.io/posts/analyzing-a-simple-encryption-scheme-using-github-ssh-keys/%5Bcve.mitre.org/cgi-bin/c...%5D(https:/cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15361)"&gt;ROCA&lt;/a&gt;). In either case, you can generate the private key from the public key. These keys off of GitHub are likely OpenSSH-generated SSH keys generated on developer laptops and hence unlikely to have that sort of problem. It's also not specific to this scheme. (A real attacker would still check.)&lt;/p&gt;
&lt;p&gt;Other attacks depend on the type of RSA padding used. The thing that sticks out about that &lt;code&gt;openssl rsautl -encrypt&lt;/code&gt; is the &lt;code&gt;-ssl&lt;/code&gt; flag. The man page claims:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;-pkcs, -oaep, -ssl, -raw&lt;/p&gt;
&lt;p&gt;the padding to use: PKCS#1 v1.5 (the default), PKCS#1 OAEP, special padding used in SSL v2
   backwards compatible handshakes, or no padding, respectively.  For signatures, only -pkcs
   and -raw can be used.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;iA! iA! I forgot that SSLv2 has its own weird padding variant: I remembered it as PKCSv15 from the last time I looked (DROWN). After some source diving (thanks pbsd!) I figured out that backwards-compatible SSLv2 padding is like PKCS1v15, but the first 8 bytes of the random padding are &lt;code&gt;0x03&lt;/code&gt; (&lt;a href="https://www.lvh.io/posts/analyzing-a-simple-encryption-scheme-using-github-ssh-keys/%5Bgithub.com/openssl/o...%5D(https:/github.com/openssl/openssl/blob/1212818eb07add297fe562eba80ac46a9893781e/crypto/rsa/rsa_pk1.c#L117-L152)"&gt;PKCS1v15 code&lt;/a&gt;, &lt;a href="https://www.lvh.io/posts/analyzing-a-simple-encryption-scheme-using-github-ssh-keys/%5Bgithub.com/openssl/o...%5D(https:/github.com/openssl/openssl/blob/1212818eb07add297fe562eba80ac46a9893781e/crypto/rsa/rsa_ssl.c#L16-L53)"&gt;SSLv2 code&lt;/a&gt;). That's weird, but OK: let's just say it's weird PKCSv15 and move on.&lt;/p&gt;
&lt;p&gt;PKCS1v15 and its SSLv2 variant are both vulnerable to Bleichenbacher's oracle attack. That attack relies on being able to mess with a ciphertext and learn from how it fails decryption via an error message or a timing side channel. That doesn't work here: this model is "offline": the attacker gets a ciphertext and a public key, but they don't get to talk to anything that knows how to decrypt.  Hence, they don't get to try to get it to decrypt maliciously modified ciphertexts either.&lt;/p&gt;
&lt;p&gt;There are lots of ways unpadded ("textbook") RSA is unsafe, but one of them is that it's deterministic. If &lt;em&gt;c = m&lt;sup&gt;e&lt;/sup&gt; mod N&lt;/em&gt; and an attacker is given a &lt;em&gt;c&lt;/em&gt; and they can guess a bunch of &lt;em&gt;m&lt;/em&gt;, they know &lt;em&gt;which&lt;/em&gt; &lt;em&gt;m&lt;/em&gt; produced a particular &lt;em&gt;c&lt;/em&gt;, and so decrypted the ciphertext. That sounds like a weird model at first, since the attacker comes up with &lt;em&gt;m&lt;/em&gt; and just "confirms" it's the right one. It would work here regardless: passwords are often low-entropy and can be enumerated, that's the premise of modern password cracking.&lt;/p&gt;
&lt;p&gt;But that's raw RSA, not PKCS1v15 padding, which is &lt;code&gt;EB = 00 || BT || PS || 00 || D&lt;/code&gt; (see &lt;a href="https://www.lvh.io/posts/analyzing-a-simple-encryption-scheme-using-github-ssh-keys/%5Btools.ietf.org/html/rfc2...%5D(https:/tools.ietf.org/html/rfc2313)"&gt;RFC&lt;/a&gt;), where BT is the block type (here 02 for public key encryption). D is the data you're encrypting. PS is the  "padding string", which is a little confusing because the entire operation is padding. It's randomly generated when you're doing an RSA encryption operation. If you call the maximum size we can run through RSA k (the modulus size), the maximum length for PS is k - D - 3 (one for each null byte and one for the BT byte). The spec insists (and OpenSSL correctly enforces) this to be at least 8 bytes, or 64 bits of entropy. You can do about 50k/s public key operations on my dinky virtualized and heavily power throttled laptop. 64 bits is a bunch but not infinity. That's still not a very satisfactory result.&lt;/p&gt;
&lt;p&gt;But wait--it's &lt;em&gt;not&lt;/em&gt; PKCS1V15, it's that weird SSLv2 padding which sets the first 8 bytes of the padding string to 0x03 bytes. If the padding string is just 8 bytes long, that means the padding string is entirely determined. We can verify that by trying to encrypt a message of the appropriate size. For a 2048 bit RSA key, that's 2048 // 8 == 256 bytes worth of modulus, 3 bytes worth of header bytes and 8 bytes worth of padding, so a 256 - 8 - 3 == 245 byte message. You can go check that any 245 message encrypts to the same ciphertext every time. There's no lower bound on the amount of entropy in the ciphertext. A 244 byte message will encrypt to one of 256 ciphertexts: one for each possible pseudorandom padding value.&lt;/p&gt;
&lt;p&gt;Practically, is this still fine? Probably, but only within narrow parameters. If the message you're encrypting is very close to 245 bytes and has plenty of structure known to the attacker, it isn't. If I can get you to generate a lot of these (say, a CI system automating the same scheme), it won't be. It's the kind of crypto that makes me vaguely uncomfortable but you'll probably get away with because there's no justice in the world.&lt;/p&gt;
&lt;p&gt;There's a straightforward way to improve this. Remember how I said &lt;code&gt;-ssl&lt;/code&gt; was weird? Not specifying anything would've resulted in the better-still-not-great PKCS1v15 padding. If you are going to specify a padding strategy, specify &lt;code&gt;-oaep&lt;/code&gt;. OAEP is the good RSA encryption padding. By default, OpenSSL uses SHA1 with it (for both the message digest and in MGF1), which is fine for this purpose. That gives you 160 bits of randomness, which ought to be plenty.&lt;/p&gt;
&lt;p&gt;This is why most schemes use RSA to encrypt a symmetric key.&lt;/p&gt;
&lt;p&gt;Future blog posts: how to fix this, creative scenarios in which we mess with those parameters so it breaks, and how to do the same with ECDSA/EdDSA keys. For the latter: I asked a smart person and the "obvious" thing to them was not the thing I'd have done. For EdDSA, my first choice would be to convert the public key from Ed25519 to X25519 and then use NaCl box. They'd use the EdDSA key directly. So, if you're interested, we'll could do a post on that. And then we'd probably talk about why you use NIST P-256 for both signatures and ECDH, but different curve formats in djb country: Ed25519 for signatures and X25519 for ECDH. Oh, and we should do some entropy estimation. People often know how to do that for passwords, but for this threat model we also need to do that for English prose.&lt;/p&gt;</description><category>cryptography</category><guid>https://www.lvh.io/posts/analyzing-a-simple-encryption-scheme-using-github-ssh-keys/</guid><pubDate>Sun, 30 Sep 2018 19:54:00 GMT</pubDate></item><item><title>The default OpenSSH key encryption is worse than plaintext</title><link>https://www.lvh.io/posts/the-default-openssh-key-encryption-is-worse-than-plaintext/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;The eslint-scope npm package got compromised recently, stealing npm credentials from your home directory. We started running tabletop exercises: what else would you smash-and-grab, and how can we mitigate that risk?&lt;/p&gt;
&lt;p&gt;Most people have an RSA SSH key laying around. That SSH key has all sorts of privileges: typically logging into prod and GitHub access. Unlike an npm credential, an SSH key is encrypted, so perhaps it’s safe even if it leaks? Let’s find out!&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;work&lt;/span&gt; &lt;span class="nv"&gt;/tmp&lt;/span&gt; &lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;ssh-keygen&lt;/span&gt;
&lt;span class="nv"&gt;Generating&lt;/span&gt; &lt;span class="nv"&gt;public/private&lt;/span&gt; &lt;span class="nv"&gt;rsa&lt;/span&gt; &lt;span class="nb"&gt;key &lt;/span&gt;&lt;span class="nv"&gt;pair.&lt;/span&gt;
&lt;span class="nv"&gt;Enter&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt; &lt;span class="nv"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;which&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;save&lt;/span&gt; &lt;span class="nv"&gt;the&lt;/span&gt; &lt;span class="nb"&gt;key &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;/home/user/.ssh/id_rsa&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;mykey&lt;/span&gt;
&lt;span class="nv"&gt;...&lt;/span&gt;
&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;work&lt;/span&gt; &lt;span class="nv"&gt;/tmp&lt;/span&gt; &lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;head&lt;/span&gt; &lt;span class="nv"&gt;-n&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="nv"&gt;mykey&lt;/span&gt;
&lt;span class="nv"&gt;-----BEGIN&lt;/span&gt; &lt;span class="nv"&gt;RSA&lt;/span&gt; &lt;span class="nv"&gt;PRIVATE&lt;/span&gt; &lt;span class="nv"&gt;KEY-----&lt;/span&gt;
&lt;span class="nv"&gt;Proc-Type&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;,&lt;span class="nv"&gt;ENCRYPTED&lt;/span&gt;
&lt;span class="nv"&gt;DEK-Info&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;AES-128-CBC&lt;/span&gt;,&lt;span class="nv"&gt;CB973D5520E952B8D5A6B86716C6223F&lt;/span&gt;

&lt;span class="nv"&gt;+5ZVNE65kl8kwZ808e4+Y7Pr8IFstgoArpZJ/bkOs7rB9eAfYrx2CLBqLATk1RT/&lt;/span&gt;
&lt;/pre&gt;


&lt;p&gt;You can tell it’s encrypted because it says so right there. It also doesn’t start with &lt;code&gt;MII&lt;/code&gt; -- the base64 DER clue that an RSA key follows. And AES! That’s good, right? CBC with ostensibly a random IV, even! No MAC, but without something like a padding oracle to try modified ciphertexts on, so that might be OK?&lt;/p&gt;
&lt;p&gt;It’s tricky to find out what this DEK-Info stuff means. Searching the openssh-portable repo for the string DEK-Info only shows sample keys. The punchline is that the AES key is just MD5(password || IV[:8]). That’s not good at all: password storage best practice holds that passwords are bad (low entropy) and in order to turn them into cryptographic key material you need an expensive function like Argon2. MD5 is very cheap to compute. The only thing this design has going for it is that the salt goes after the password, so you can’t just compute the intermediate state of MD5(IV[8:]) and try passwords from there. That’s faint praise, especially in a world where I can rent a machine that tries billions of MD5 calls per second. There just aren’t that many passwords.&lt;/p&gt;
&lt;p&gt;You might ask yourself how OpenSSH ended up with this. The sad answer is the OpenSSL command line tool had it as a default, and now we’re stuck with it.&lt;/p&gt;
&lt;p&gt;That’s a fair argument to say that standard password-encrypted keys are about as good as plaintext: the encryption is ineffective. But I made a stronger statement: it’s &lt;em&gt;worse&lt;/em&gt;. The argument there is simple: an SSH key password is unlikely to be managed by a password manager: instead it’s something you remember. If you remember it, you probably reused it somewhere. Perhaps it’s even your device password. This leaked key provides an oracle: if I guess the password correctly (and that’s feasible because the KDF is bad), I know I guessed correctly because I can check against your public key.&lt;/p&gt;
&lt;p&gt;There’s nothing wrong with the RSA key pair itself: it’s just the symmetric encryption of the private key. You can’t mount this attack from just a public key.&lt;/p&gt;
&lt;p&gt;How do you fix this? OpenSSH has a new key format that you should use. “New” means 2013. This format uses bcrypt_pbkdf, which is essentially bcrypt with fixed difficulty, operated in a PBKDF2 construction. Conveniently, you always get the new format when generating Ed25519 keys, because the old SSH key format doesn’t support newer key types. That’s a weird argument: you don’t really need your key format to define how Ed25519 serialization works since Ed25519 itself already defines how serialization works. But if that’s how we get good KDFs, that’s not the pedantic hill I want to die on. Hence, one answer is ssh-keygen -t ed25519. If, for compatibility reasons, you need to stick to RSA, you can use ssh-keygen -o. That will produce the new format, even for old key types. You can upgrade existing keys with ssh-keygen -p -o -f PRIVATEKEY. If your keys live on a Yubikey or a smart card, you don't have this problem either.&lt;/p&gt;
&lt;p&gt;We want to provide a better answer to this. On the one hand, aws-vault has shown the way by moving credentials off disk and into keychains. Another parallel approach is to move development into partitioned environments. Finally, most startups should consider not having long-held SSH keys, instead using temporary credentials issued by an SSH CA, ideally gated on SSO. Unfortunately this doesn't work for GitHub.&lt;/p&gt;
&lt;p&gt;PS: It’s hard to find an authoritative source, but from my memory: the versioned parameter in the PEM-like OpenSSH private key format only affect the encryption method. That doesn’t matter in the slightest: it’s the KDF that’s broken. That’s an argument against piecemeal negotiating parts of protocols, I’m sure. We’ll get you a blog post on that later.&lt;/p&gt;
&lt;p&gt;The full key is available here, just in case you feel like running john the ripper on something today: &lt;a href="https://gist.github.com/lvh/c532c8fd46115d2857f40a433a2416fd"&gt;gist.github.com/lvh/c532c...&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(This post was syndicated on the Latacora blog.)&lt;/p&gt;</description><category>cryptography</category><category>security</category><guid>https://www.lvh.io/posts/the-default-openssh-key-encryption-is-worse-than-plaintext/</guid><pubDate>Sat, 04 Aug 2018 02:00:18 GMT</pubDate></item><item><title>A child's garden of inter-service authentication schemes</title><link>https://www.lvh.io/posts/a-childs-garden-of-inter-service-authentication-schemes/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;Modern applications tend to be composed from relationships between smaller applications. Secure modern applications thus need a way to express and enforce security policies that span multiple services. This is the “server-to-server” (S2S) authentication and authorization problem (for simplicity, I’ll mash both concepts into the term “auth” for most of this post).&lt;/p&gt;
&lt;p&gt;Designers today have a lot of options for S2S auth, but there isn’t much clarity about what the options are or why you’d select any of them. Bad decisions sometimes result. What follows is a stab at clearing the question up.&lt;/p&gt;
&lt;h3&gt;Cast Of Characters&lt;/h3&gt;
&lt;p&gt;Alice and Bob are services on a production VPC. Alice wants to make a request of Bob. How can we design a system that allows this to happen?&lt;/p&gt;
&lt;p&gt;Here’s, I think, a pretty comprehensive overview of available S2S schemes. I’ve done my best to describe the “what’s” and minimize the “why’s”, beyond just explaining the motivation for each scheme. Importantly, these are all things that reasonable teams use for S2S auth.&lt;/p&gt;
&lt;h4&gt;Nothing At All&lt;/h4&gt;
&lt;p&gt;Far and away the most popular S2S scheme is “no auth at all”. Internet users can’t reach internal services. There’s little perceived need to protect a service whose only clients are already trusted.&lt;/p&gt;
&lt;h4&gt;Bearer Token&lt;/h4&gt;
&lt;p&gt;Bearer tokens rule everything around us. Give Alice a small blob of data, such that when Bob sees that data presented, he assumes he’s talking to Alice. Cookies are bearer tokens. Most API keys are bearer tokens. OAuth is an elaborate scheme for generating and relaying bearer tokens. SAML assertions are delivered in bearer tokens.&lt;/p&gt;
&lt;p&gt;The canonical bearer token is a random string, generated from a secure RNG, that is at least 16 bytes long (that is: we generally consider 128 bits a reasonable common security denominator). But part of the point of a bearer token is that the holder doesn’t care what it is, so Alice’s bearer token could also encode data that Bob could recover. This is common in client-server designs and less common in S2S designs.&lt;/p&gt;
&lt;h5&gt;A few words about passwords&lt;/h5&gt;
&lt;p&gt;S2S passwords are disappointingly common. You see them in a lot of over-the-Internet APIs (ie, for S2S relationships that span companies). A password is basically a bearer token that you can memorize and quickly type. Computers are, in 2018, actually pretty good at memorizing and typing, and so you should use real secrets, rather than passwords, in S2S applications.&lt;/p&gt;
&lt;h4&gt;HMAC(timestamp)&lt;/h4&gt;
&lt;p&gt;The problem with bearer tokens is that anybody who has them can use them. And they’re routinely transmitted. They could get captured off the wire, or logged by a proxy. This keeps smart ops people up at night, and motivates a lot of “innovation”.&lt;/p&gt;
&lt;p&gt;You can keep the simplicity of bearer tokens while avoiding the capture-in-flight problem by exchanging the tokens with secrets, and using the secrets to authenticate a timestamp. A valid HMAC proves ownership of the shared secret without revealing it. You’d then proceed as with bearer tokens.&lt;/p&gt;
&lt;h5&gt;A few words about TOTP&lt;/h5&gt;
&lt;p&gt;TOTP is basically HMAC(timestamp) stripped down to make it easy for humans to briefly memorize and type. As with passwords, you shouldn’t see TOTP in S2S applications.&lt;/p&gt;
&lt;h5&gt;A few words about PAKEs&lt;/h5&gt;
&lt;p&gt;PAKEs are a sort of inexplicably popular cryptographic construction for securely proving knowledge of a password and, from that proof, deriving an ephemeral shared secret. SRP is a PAKE. People go out of their way to find applications for PAKEs. The thing to understand about them is that they’re fundamentally a way to extract cryptographic strength from passwords. Since this isn’t a problem computers have, PAKEs don’t make sense for S2S auth.&lt;/p&gt;
&lt;h4&gt;Encrypted Tokens&lt;/h4&gt;
&lt;p&gt;HMAC(timestamp) is stateful; it works because there’s pairwise knowledge of secrets and the metadata associated with them.  Usually, this is fine. But sometimes it’s hard to get all the parties to share metadata.&lt;/p&gt;
&lt;p&gt;Instead of making that metadata implicit to the protocol, you can store it directly in the credential: include it alongside the timestamp and HMAC or encrypt it. This is how Rails cookie storage works; it’s also the dominant use case for JWTs. AWS-style request “signing” is another example (using HMAC and forgoing encryption).&lt;/p&gt;
&lt;p&gt;By themselves, encrypted tokens make more sense in client-server settings than they do for S2S. Unlike client-server, where a server can just use the same secret for all the clients, S2S tokens still require some kind of pairwise state-keeping.&lt;/p&gt;
&lt;h4&gt;Macaroons&lt;/h4&gt;
&lt;p&gt;You can’t easily design a system where Alice takes her encrypted token, reduces its security scope (for instance, from read-write to read-only), and then passes it to Dave to use on her behalf. No matter how “sophisticated” we make the encoding and transmission mechanisms, encrypted tokens still basically express bearer logic.&lt;/p&gt;
&lt;p&gt;Macaroons are an interesting (and criminally underused) construction that directly provides both &lt;em&gt;delegation&lt;/em&gt; and &lt;em&gt;attenuation&lt;/em&gt;. They’re a kind of token from which you can derive more restricted tokens (that’s the “attenuation”), and, if you want, pass that token to someone else to use without them being able to exceed the authorization you gave them. Macaroons accomplish this by chaining HMAC; the HMAC of a macaroon is the HMAC secret for its derived attenuated macaroons.&lt;/p&gt;
&lt;p&gt;By adding encryption along with HMAC, Macaroons also express “third-party” conditions. Alice can get Charles to attest that Alice is a member of the super-awesome-best-friends-club, and include that in the Macaroon she delivers to Bob. If Bob also trusts Charles, Bob can safely learn whether Alice is in the club. Macaroons can flexibly express whole trees of these kinds of relationships, capturing identity, revocation, and… actually, revocation and identity are the only two big wins I can think of for this feature.&lt;/p&gt;
&lt;h4&gt;Asymmetric Tokens&lt;/h4&gt;
&lt;p&gt;You can swap the symmetric constructions used in tokens for asymmetric tokens and get some additional properties.&lt;/p&gt;
&lt;p&gt;Using signatures instead of HMACs, you get non-repudiability: Bob can verify Alice’s token, but can’t necessarily mint a new Alice token himself.&lt;/p&gt;
&lt;p&gt;More importantly, you can eliminate pairwise configuration. Bob and Alice can trust Charles, who doesn’t even need to be online all the time, and from that trust derive mutual authentication.&lt;/p&gt;
&lt;p&gt;The trade-offs for these capabilities are speed and complexity. Asymmetric cryptography is much slower and much more error-prone than symmetric cryptography.&lt;/p&gt;
&lt;h4&gt;Mutual TLS&lt;/h4&gt;
&lt;p&gt;Rather than designing a new asymmetric token format, every service can have a certificate. When Alice connects to Bob, Bob can check a whitelist of valid certificate fingerprints, and whether Alice’s name on her client certificate is allowed. Or, you could set up a simple CA, and Bob could trust any certificate signed by the CA. Things can get more complex; you might take advantage of X.509 and directly encode claims in certs (beyond just names).&lt;/p&gt;
&lt;h5&gt;A few words about SPIFFE&lt;/h5&gt;
&lt;p&gt;If you’re a Kubernetes person this scheme is also sometimes called SPIFFE.&lt;/p&gt;
&lt;h5&gt;A few words about Tokbind&lt;/h5&gt;
&lt;p&gt;If you’re a participant in the IETF TLS Working Group, you can combine bearer tokens and MTLS using tokbind. Think of tokbind as a sort of “TLS cookie”. It’s derived from the client and server certificate and survives multiple TLS connections. You can use a tokbind secret to sign a bearer token, resulting in a bearer token that is confined to a particular MTLS relationship that can’t be used in any other context.&lt;/p&gt;
&lt;h4&gt;Magic Headers&lt;/h4&gt;
&lt;p&gt;Instead of building an explicit application-layer S2S scheme, you can punt the problem to your infrastructure. Ensure all requests are routed through one or more trusted, stateful proxies. Have the proxies set headers on the forwarded requests. Have the services trust the headers.&lt;/p&gt;
&lt;p&gt;This accomplishes the same things a complicated Mutual TLS scheme does without requiring slow, error-prone public-key encryption. The trade-off is that your policy is directly coupled to your network infrastructure.&lt;/p&gt;
&lt;h4&gt;Kerberos&lt;/h4&gt;
&lt;p&gt;You can try to get the benefits of magic headers and encrypted tokens at the same time using something like Kerberos, where there’s a magic server trusted by all parties, but bound by cryptography rather than network configuration. Services need to be introduced to the Kerberos server, but not to each other; mutual trust of the Kerberos server, and authorization logic that lives on that Kerberos server, resolves all auth questions. Notably, no asymmetric cryptography is needed to make this work.&lt;/p&gt;
&lt;h3&gt;Themes&lt;/h3&gt;
&lt;p&gt;What are the things we might want to achieve from an S2S scheme? Here’s a list. It’s incomplete. Understand that it’s probably not reasonable to expect &lt;em&gt;all of these things&lt;/em&gt; from a single scheme.&lt;/p&gt;
&lt;h4&gt;Minimalism&lt;/h4&gt;
&lt;p&gt;This goal is less obvious than it seems. People adopt complicated auth schemes without clear rationales. It’s easy to lose security by doing this; every feature you add to an application  especially security features  adds attack surface. From an application security perspective, “do the simplest thing you can get away with” has a lot of merit. If you understand and keep careful track of your threat model, “nothing at all” can be a security-maximizing option. Certainly, minimalism motivates a lot of bearer token deployments.&lt;/p&gt;
&lt;p&gt;The opposite of minimalism is complexity. A reasonable way to think about the tradeoffs in S2S design is to think of complexity as a currency you have to spend. If you introduce new complexity, what are you getting for it?&lt;/p&gt;
&lt;h4&gt;Claims&lt;/h4&gt;
&lt;p&gt;Authentication and authorization are two different things: who are you, and what are you allowed to do? Of the two problems, authorization is the harder one. An auth scheme can handle authorization, or assist authorization, or punt on it altogether.&lt;/p&gt;
&lt;p&gt;Opaque bearer token schemes usually just convey identity. An encrypted token, on the other hand, might bind &lt;em&gt;claims&lt;/em&gt;: statements that limit the scope of what the token enables, or metadata about the identity of the requestor.&lt;/p&gt;
&lt;p&gt;Schemes that don’t bind claims can make sense if authorization logic between services is straightforward, or if there’s already a trusted system (for instance, a service discovery layer) that expresses authorization. Schemes that do bind claims can be problematic if the claims carried in an credential can be abused, or targeted by application flaws. On the other hand, an S2S scheme that supports claims can do useful things like propagating on-behalf-of requestor identities or supporting distributed tracing.&lt;/p&gt;
&lt;h4&gt;Confinement&lt;/h4&gt;
&lt;p&gt;The big problem with HTTP cookies is that once they’ve captured one, an attacker can abuse it however they see fit. You can do better than that by adding mitigations or caveats to credentials. They might be valid only for a short period of time, or valid only for a specific IP address (especially powerful when combined with short expiry),  or, as in the case of Tokbind, valid only on a particular MTLS relationship.&lt;/p&gt;
&lt;h4&gt;Statelessness&lt;/h4&gt;
&lt;p&gt;Statelessness means Bob doesn’t have to remember much (or, ideally, anything) about Alice. This is an immensely popular motivator for some S2S schemes. It’s perceived as eliminating a potential performance bottleneck, and as simplifying deployment.&lt;/p&gt;
&lt;p&gt;The tricky thing about statelessness is that it often doesn’t make sense to minimize state, only to eliminate it. If pairwise statefulness creeps back into the application for some other reason (for instance, Bob has to remember anything at all about Alice), stateless S2S auth can spend a lot of complexity for no real gain.&lt;/p&gt;
&lt;h4&gt;Pairwise Configuration&lt;/h4&gt;
&lt;p&gt;Pairwise configuration is the bête noire of S2S operational requirements. An application secret that has to be generated once for each of several peers and that &lt;em&gt;anybody might ever store in code&lt;/em&gt; is part of a scheme in which secrets are never, ever rotated. In a relatively common set of circumstances, pairwise config means that new services can only be introduced during maintenance windows.&lt;/p&gt;
&lt;p&gt;Still, if you have a relatively small and stable set of services (or if all instances of a particular service might simply share a credential), it can make sense to move complexity out of the application design and into the operational requirements.  Also it makes sense if you have an ops team and you never have to drink with them.&lt;/p&gt;
&lt;p&gt;I kid, really, because if you can get away with it, not spending complexity to eliminate pairwise configuration can make sense. Also, many of the ways S2S schemes manage to eliminate pairwise configurations involve &lt;em&gt;introducing yet another service&lt;/em&gt;, which has a sort of constant factor cost that can swamp the variable cost.&lt;/p&gt;
&lt;h4&gt;Delegation and Attenuation&lt;/h4&gt;
&lt;p&gt;People deploy a lot of pointless delegation. Application providers might use OAuth for their client-server login, for instance, even though no third-party applications exist.  The flip side of this is that if you actually need delegation, you really want to have it expressed carefully in your protocol. The thing you don’t want to do is ever share a bearer token.&lt;/p&gt;
&lt;p&gt;Delegation can show up in internal S2S designs as a building block. For instance, a Macaroon design might have a central identity issuance server that grants all-powerful tokens to systems that in turn filter them for specific requestors.&lt;/p&gt;
&lt;p&gt;Some delegation schemes have implied or out-of-band attenuation. For instance, you might not be able to look at an OAuth token and know what it’s restrictions are. These systems are rough in practice; from an operational security perspective, your starting point probably needs to be that any lost token is game-over for its owner.&lt;/p&gt;
&lt;p&gt;A problem with writing about attenuation is that Macaroons express it so well that it’s hard to write about its value without lapsing into the case for Macaroons.&lt;/p&gt;
&lt;h4&gt;Flexibility&lt;/h4&gt;
&lt;p&gt;If use JSON as your credential format, and you later build a feature that allows a credential to express not just Alice’s name but also whether she’s an admin, you can add that feature without changing the credential format. Later, attackers can add the feature where they turn any user into an admin, and you can then add the feature that breaks that attack. JSON is just features all the way down.&lt;/p&gt;
&lt;p&gt;I’m only mostly serious. If you’re doing something more complicated than a bearer token, you’re going to choose an extensible mechanism. If not, I already made the case for minimalism.&lt;/p&gt;
&lt;h4&gt;Coupling&lt;/h4&gt;
&lt;p&gt;All things being equal, coupling is bad. If your S2S scheme is expressed by network controls and unprotected headers, it’s tightly coupled to the network deployment, which can’t change without updating the security scheme. But if your network configuration doesn’t change often, that limitation might save you a lot of complexity.&lt;/p&gt;
&lt;h4&gt;Revocation&lt;/h4&gt;
&lt;p&gt;People talk about this problem a lot. Stateless schemes have revocation problems: the whole point of a stateless scheme is for Bob not to have to remember anything about Alice (other than perhaps some configuration that says Alice is allowed to make requests, but not Dave, and this gets complicated really quickly and can quickly call into question the value of statelessness but let’s not go there). At any rate: a stateless bearer token will eventually be compromised, and you can’t just let it get used over and over again to steal data.&lt;/p&gt;
&lt;p&gt;The two mainstream answers to this problem are short expiry and revocation lists.&lt;/p&gt;
&lt;p&gt;Short expiry addresses revocation if: (a) you have a dedicated auth server and the channel to that server is somehow more secure than the channel between Alice and Bob.; (b) the auth server relies on a long-lived secret that never appears on the less-secure channel, and (c) issues an access secret that is transmitted on the less-secure channel, but lives only for a few minutes. These schemes are called “refresh tokens”. Refresh tends to find its way into a lot of designs where this fact pattern doesn’t hold. Security design is full of wooden headphones and coconut phones.&lt;/p&gt;
&lt;p&gt;Revocation lists (and, usually, some attendant revocation service) are a sort of all-purpose solution to this problem; you just blacklist revoked tokens, for at least as long as the lifetime of the token. This obviously introduces state, but it’s a specific kind of state that doesn’t (you hope) grow as quickly as your service does. If it’s the only state you have to keep, it’s nice to have the flexibility of putting it wherever you want.&lt;/p&gt;
&lt;h4&gt;Rigidity&lt;/h4&gt;
&lt;p&gt;It is hard to screw up a random bearer token. Alice stores the token and supply it on requests. Bob uses the token to look up an entry in a database. There aren’t a lot of questions.&lt;/p&gt;
&lt;p&gt;It is extraordinarily easy to screw up JWT. JWT is a JSON format where you have to parse and interpret a JSON document to figure out how to decrypt and authenticate a JSON document. It has revived bugs we thought long dead, like “repurposing asymmetric public keys as symmetric private keys”.&lt;/p&gt;
&lt;p&gt;Problems with rigidity creep up a lot in distributed security. The first draft of this post said that MTLS was rigid; you’re either speaking TLS with a client cert or you’re not. But that ignores how hard X.509 validation is. If you’re not careful, an attacker can just ask Comodo for a free email certificate and use it to access your services. Worse still, MTLS can “fail open” in a way that TLS sort of doesn’t: if a service forgets to check for client certificates, TLS will still get negotiated, and you might not notice until an attacker does.&lt;/p&gt;
&lt;p&gt;Long story short: bearer tokens are rigid. JWT is a kind of evil pudding. Don’t use JWT.&lt;/p&gt;
&lt;h4&gt;Universality&lt;/h4&gt;
&lt;p&gt;A nice attribute of widely deployed MTLS is that it can mitigate SSRF bugs (the very bad bug where an attacker coerces one of your service to make an arbitrary HTTP request, probably targeting your internal services, on their behalf). If the normal HTTP-request-generating code doesn’t add a client certificate, and every internal service needs to see one to honor a request, you’ve limited the SSRF attackers options a lot.&lt;/p&gt;
&lt;p&gt;On the other hand, we forget that a lot of our internal services consist of code that we didn’t write. The best example of this is Redis, which for years proudly waved the banner of “if you can talk to it, you already own the whole application”.&lt;/p&gt;
&lt;p&gt;It’s helpful if we can reasonably expect an auth control to span all the systems we use, from Postgres to our custom revocation server. That might be a realistic goal with Kerberos, or with network controls and magic headers; with tunnels or proxies, it’s even something you can do with MTLS  this is a reason MTLS is such a big deal for Kubernetes, where it’s reasonable for the infrastructure to provide every container with an MTLS-enabled Envoy proxy.  On the other hand it’s unlikely to be something you can achieve with Macaroons or evil puddings.&lt;/p&gt;
&lt;h4&gt;Performance and Complexity&lt;/h4&gt;
&lt;p&gt;If you want performance and simplicity, you probably avoid asymmetric crypto, unless your request frequency is (and will remain) quite low. Similarly, you’d probably want to avoid dedicated auth servers, especially if Bob needs to be in constant contact with them for Alice to make requests to him; this is a reason people tend to migrate away from Kerberos.&lt;/p&gt;
&lt;h3&gt;Our Thoughts&lt;/h3&gt;
&lt;p&gt;Do the simplest thing that makes sense for your application right now. A true fact we can relate from something like a decade of consulting work on these problems: intricate S2S auth schemes are not the norm; if there’s a norm, it’s “nothing at all except for ELBs”.  If you need something, but you have to ask whether that something oughtn’t just be bearer tokens, then just use bearer tokens.&lt;/p&gt;
&lt;p&gt;Unfortunately, if there’s a second norm, it’s adopting complicated auth mechanisms independently or, worse, in combination, and then succumbing to vulnerabilities.&lt;/p&gt;
&lt;p&gt;Macaroons are inexplicably underused. They’re the Velvet Underground of authentication mechanisms, hugely influential but with little radio airplay. Unlike the Velvets, Macaroons aren’t overrated. They work well for client-server auth and for s2s auth. They’re very flexible but have reassuring format rigidity, and they elegantly take advantage of just a couple simple crypto operations. There are libraries for all the mainstream languages. You will have a hard time coming up with a scenario where we’d try to talk you out of using them.&lt;/p&gt;
&lt;p&gt;JWT is a standard that tries to do too much and ends up doing everything haphazardly.  Our loathing of JWT motivated this post, but this post isn’t about JWT; we’ll write more about it in the future.&lt;/p&gt;
&lt;p&gt;If your inter-service auth problem really decomposes to inter-container (or, without containers, inter-instance) auth, MTLS starts to make sense. The container-container MTLS story usually involves containers including a proxy, like Envoy, that mediates access. If you’re not connecting containers, or have ad-hoc components, MTLS can really start to take on a CORBA feel: random sidecar processes (here stunnel, there Envoy, and this one app that tries to do everything itself). It can be a pain to configure properly, and this is a place you need to get configurations right.&lt;/p&gt;
&lt;p&gt;If you can do MTLS in such a way that there is exactly one way all your applications use it (probably: a single proxy that all your applications install), consider MTLS. Otherwise, be cautious about it.&lt;/p&gt;
&lt;p&gt;Beyond that, we don’t want to be too much more prescriptive. Rather, we’d just urge you to think about what you’re actually getting from an S2S auth scheme before adopting it.&lt;/p&gt;
&lt;p&gt;(But really, you should just use Macaroons.)&lt;/p&gt;
&lt;p&gt;(This post was syndicated on the Latacora blog.)&lt;/p&gt;</description><category>cryptography</category><category>security</category><guid>https://www.lvh.io/posts/a-childs-garden-of-inter-service-authentication-schemes/</guid><pubDate>Tue, 12 Jun 2018 22:27:00 GMT</pubDate></item><item><title>Cryptographic right answers</title><link>https://www.lvh.io/posts/cryptographic-right-answers/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;We’re less interested in empowering developers and a lot more pessimistic about the prospects of getting this stuff right.&lt;/p&gt;
&lt;p&gt;There are, in the literature and in the most sophisticated modern systems, “better” answers for many of these items. If you’re building for low-footprint embedded systems, you can use STROBE and a sound, modern, authenticated encryption stack entirely out of a single SHA-3-like sponge constructions. You can use NOISE to build a secure transport protocol with its own AKE. Speaking of AKEs, there are, like, 30 different password AKEs you could choose from.&lt;/p&gt;
&lt;p&gt;But if you’re a developer and not a cryptography engineer, you shouldn’t do any of that. You should keep things simple and conventional and easy to analyze; “boring”, as the Google TLS people would say.&lt;/p&gt;
&lt;p&gt;(This content has been developed and updated by different people over a decade. We've kept what Colin Percival originally said in 2009, Thomas Ptacek said in 2015, and what we're saying in 2018 for comparison. If you're designing something today, just use the 2018 Latacora recommendation.)&lt;/p&gt;
&lt;h3&gt;Cryptographic Right Answers&lt;/h3&gt;
&lt;h4&gt;Encrypting Data&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009:&lt;/em&gt; AES-CTR with HMAC.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015:&lt;/em&gt; (1) NaCl/libsodium’s default, (2) ChaCha20-Poly1305, or (3) AES-GCM.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt; KMS or XSalsa20+Poly1305&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; you're hiding information from users or the network.&lt;/p&gt;
&lt;p&gt;If you are in a position to use KMS, Amazon’s (or Google’s) Hardware Security Module time share, use KMS. If you could use KMS but encrypting is just a fun weekend project and you might be able to save some money by minimizing your KMS usage, use KMS. If you’re just encrypting secrets like API tokens for your application at startup, use SSM Parameter Store, which is KMS. You don’t have to understand how KMS works.&lt;/p&gt;
&lt;p&gt;Otherwise, what you want ideally is “AEAD”: authenticated encryption with additional data (the option for plaintext authenticated headers).&lt;/p&gt;
&lt;p&gt;The mainstream way to get authenticated encryption is to use a stream cipher (usually: AES in CTR mode) composed with a polynomial MAC (a cryptographic CRC).&lt;/p&gt;
&lt;p&gt;The problem you’ll run into with all those mainstream options is nonces: they want you to come up with a unique (usually random) number for each stream which can never be reused. It’s simplest to generate nonces from a secure random number generator, so you want a scheme that makes that easy.&lt;/p&gt;
&lt;p&gt;Nonces are particularly important for AES-GCM, which is the most popular mode of encryption. Unfortunately, it’s particularly tricky with AES-GCM, where it’s just-barely-but-maybe-not-quite on the border of safe to use random nonces.&lt;/p&gt;
&lt;p&gt;So we recommend you use XSalsa20-Poly1305. This is a species of “ChaPoly” constructions, which, put together, are the most common encryption constructions outside of AES-GCM. Get XSalsa20-Poly1305 from libsodium or NaCl.&lt;/p&gt;
&lt;p&gt;The advantage to XSalsa20 over ChaCha20 and Salsa20 is that XSalsa supports an extended nonce; it’s big enough that you can simply generate a big long random nonce for every stream and not worry about how many streams you’re encrypting.&lt;/p&gt;
&lt;p&gt;There are “NMR” or “MRAE” schemes in the pipeline that promise some degree of security even if nonces are mishandled; these include GCM-SIV (all the SIVs, really) and CAESAR-contest-finalist Deoxys-II. They’re interesting, but nobody really supports or uses them yet, and with an extended nonce, the security win is kind of marginal. They’re not boring. Stay boring for now.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; AES-CBC, AES-CTR by itself, block ciphers with 64-bit blocks --- most especially Blowfish, which is inexplicably popular, OFB mode. Don't ever use RC4, which is comically broken.&lt;/p&gt;
&lt;h4&gt;Symmetric key length&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Use 256-bit keys.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Use 256-bit keys.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt; Go ahead and use 256 bit keys.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; you're using cryptography.&lt;/p&gt;
&lt;p&gt;But remember: your AES key is far less likely to be broken than your public key pair, so the latter key size should be larger if you're going to obsess about this.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; constructions with huge keys, cipher "cascades", key sizes under 128 bits.&lt;/p&gt;
&lt;h4&gt;Symmetric “Signatures”&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Use HMAC.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Yep, use HMAC.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt; Still HMAC.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; you're securing an API, encrypting session cookies, or are encrypting user data but, against medical advice, not using an AEAD construction.&lt;/p&gt;
&lt;p&gt;If you're authenticating but not encrypting, as with API requests, don't do anything complicated. There is a class of crypto implementation bugs that arises from how you feed data to your MAC, so, if you're designing a new system from scratch, Google "crypto canonicalization bugs". Also, use a secure compare function.&lt;/p&gt;
&lt;p&gt;If you use HMAC, people will feel the need to point out that SHA3 (and the truncated SHA2 hashes) can do “KMAC”, which is to say you can just concatenate the key and data and hash them and be secure. This means that in theory HMAC is doing unnecessary extra work with SHA-3 or truncated SHA-2. But who cares? Think of HMAC as cheap insurance for your design, in case someone switches to non-truncated SHA-2.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; custom "keyed hash" constructions, HMAC-MD5, HMAC-SHA1, complex polynomial MACs, encrypted hashes, CRC.&lt;/p&gt;
&lt;h4&gt;Hashing algorithm&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Use SHA256 (SHA-2).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Use SHA-2.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt; Still SHA-2.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; you always care about this.&lt;/p&gt;
&lt;p&gt;If you can get away with it: use SHA-512/256, which truncates its output and sidesteps length extension attacks.&lt;/p&gt;
&lt;p&gt;We still think it's less likely that you'll upgrade from SHA-2 to SHA-3 than it is that you'll upgrade from SHA-2 to something faster than SHA-3, and SHA-2 still looks great, so get comfortable and cuddly with SHA-2.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; SHA-1, MD5, MD6.&lt;/p&gt;
&lt;h4&gt;Random IDs&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Use 256-bit random numbers.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Use 256-bit random numbers.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt; Use 256-bit random numbers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; you always care about this.&lt;/p&gt;
&lt;p&gt;From /dev/urandom.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; userspace random number generators, the OpenSSL RNG, havaged, prngd, egd, /dev/random.&lt;/p&gt;
&lt;h4&gt;Password handling&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: scrypt or PBKDF2.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;:  In order of preference, use scrypt, bcrypt, and then if nothing else is available PBKDF2.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt;  In order of preference, use scrypt, argon2, bcrypt, and then if nothing else is available PBKDF2.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; you accept passwords from users or, anywhere in your system, have human-intelligible secret keys.&lt;/p&gt;
&lt;p&gt;But, seriously: you can throw a dart at a wall to pick one of these. Technically, argon2 and scrypt are materially better than bcrypt, which is much better than PBKDF2. In practice, it mostly matters that you use a real secure password hash, and not as much which one you use.&lt;/p&gt;
&lt;p&gt;Don’t build elaborate password-hash-agility schemes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; SHA-3, naked SHA-2, SHA-1, MD5.&lt;/p&gt;
&lt;h4&gt;Asymmetric encryption&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Use RSAES-OAEP with SHA256 and MGF1+SHA256 bzzrt pop ffssssssst exponent 65537.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Use NaCl/libsodium (box / crypto_box).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt;  Use Nacl/libsodium (box / crypto_box).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if&lt;/em&gt;: you need to encrypt the same kind of message to many different people, some of them strangers, and they need to be able to accept the message asynchronously, like it was store-and-forward email, and then decrypt it offline. It's a pretty narrow use case.&lt;/p&gt;
&lt;p&gt;Of all the cryptographic "right answers", this is the one you're least likely to get right on your own. Don't freelance public key encryption, and don't use a low-level crypto library like OpenSSL or BouncyCastle.&lt;/p&gt;
&lt;p&gt;Here are several reasons you should stop using RSA and switch to elliptic curve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RSA (and DH) drag you towards "backwards compatibility" (ie: downgrade-attack compatibility) with insecure systems.&lt;/li&gt;
&lt;li&gt;RSA begs implementors to encrypt directly with its public key primitive, which is usually not what you want to do&lt;/li&gt;
&lt;li&gt;RSA has too many knobs. In modern curve systems, like Curve25519, everything is pre-set for security.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;NaCl uses Curve25519 (the most popular modern curve, carefully designed to eliminate several classes of attacks against the NIST standard curves) in conjunction with a ChaPoly AEAD scheme. Your language will have bindings (or, in the case of Go, its own library implementation) to NaCl/libsodium; use them. Don’t try to assemble this yourself. Libsodium has &lt;a href="https://libsodium.gitbook.io/doc/bindings_for_other_languages"&gt;a list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Don't use RSA.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; Systems designed after 2015 that use RSA, RSA-PKCS1v15, RSA, ElGamal, I don't know, Merkle-Hellman knapsacks? Just avoid RSA.&lt;/p&gt;
&lt;h4&gt;Asymmetric signatures&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Use RSASSA-PSS with SHA256 then MGF1+SHA256 in tricolor systemic silicate orientation.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Use Nacl, Ed25519, or RFC6979.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt;  Use Nacl or Ed25519.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if&lt;/em&gt;: you're designing a new cryptocurrency. Or, a system to sign Ruby Gems or Vagrant images, or a DRM scheme, where the authenticity of a series of files arriving at random times needs to be checked offline against the same secret key. Or, you're designing an encrypted message transport.&lt;/p&gt;
&lt;p&gt;The allegations from the previous answer are incorporated herein as if stated in full.&lt;/p&gt;
&lt;p&gt;The two dominating use cases within the last 10 years for asymmetric signatures are cryptocurrencies and forward-secret key agreement, as with ECDHE-TLS. The dominating algorithms for these use cases are all elliptic-curve based. Be wary of new systems that use RSA signatures.&lt;/p&gt;
&lt;p&gt;In the last few years there has been a major shift away from conventional DSA signatures and towards misuse-resistent "deterministic" signature schemes, of which EdDSA and RFC6979 are the best examples. You can think of these schemes as "user-proofed" responses to the Playstation 3 ECDSA flaw, in which reuse of a random number leaked secret keys. Use deterministic signatures in preference to any other signature scheme.&lt;/p&gt;
&lt;p&gt;Ed25519, the NaCl/libsodium default, is by far the most popular public key signature scheme outside of Bitcoin. It’s misuse-resistant and carefully designed in other ways as well. You shouldn’t freelance this either; get it from NaCl.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; RSA-PKCS1v15, RSA, ECDSA, DSA; really, especially avoid conventional DSA and ECDSA.&lt;/p&gt;
&lt;h4&gt;Diffie-Hellman&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Operate over the 2048-bit Group #14 with a generator of 2.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Probably still DH-2048, or Nacl.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt;  Probably nothing. Or use Curve25519.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; you're designing an encrypted transport or messaging system that will be used someday by a stranger, and so static AES keys won't work.&lt;/p&gt;
&lt;p&gt;The 2015 version of this document confused the hell out of everyone.&lt;/p&gt;
&lt;p&gt;Part of the problem is that our “Right Answers” are a response to Colin Percival’s “Right Answers”, and his included a “Diffie-Hellman” answer, as if “Diffie-Hellmanning” was a thing developers routinely do. In reality, developers simply shouldn’t freelance their own encrypted transports. To get a sense of the complexity of this issue, read the documentation for the Noise Protocol Framework. If you’re doing a key-exchange with DH, you probably want an authenticated key exchange (AKE) that resists key compromise impersonation (KCI), and so the primitive you use for DH is not the only important security concern.&lt;/p&gt;
&lt;p&gt;But whatever.&lt;/p&gt;
&lt;p&gt;It remains the case: if you can just use NaCl, use NaCl. You don't even have to care what NaCl does. That’s the point of NaCl.&lt;/p&gt;
&lt;p&gt;Otherwise: use Curve25519. There are libraries for virtually every language. In 2015, we were worried about encouraging people to write their own Curve25519 libraries, with visions of Javascript bignum implementations dancing in our heads. But really, part of the point of Curve25519 is that the entire curve was carefully chosen to minimize implementation errors. Don’t write your own! But really, just use Curve25519.&lt;/p&gt;
&lt;p&gt;Don’t do ECDH with the NIST curves, where you’ll have to carefully verify elliptic curve points before computing with them to avoid leaking secrets. That attack is very simple to implement, easier than a CBC padding oracle, and far more devastating.&lt;/p&gt;
&lt;p&gt;The 2015 document included a clause about using DH-1024 in preference to sketchy curve libraries. You know what? That’s still a valid point. Valid and stupid. The way to solve the “DH-1024 vs. sketchy curve library” problem is, the same as the “should I use Blowfish or IDEA?” problem. Don’t have that problem. Use Curve25519.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; conventional DH, SRP, J-PAKE, handshakes and negotiation, elaborate key negotiation schemes that only use block ciphers, srand(time()).*&lt;/p&gt;
&lt;h4&gt;Website security&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Use OpenSSL.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Remains: OpenSSL, or BoringSSL if you can. Or just use AWS ELBs&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt;  Use AWS ALB/ELB or OpenSSL, with LetsEncrypt&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; you have a website.&lt;/p&gt;
&lt;p&gt;If you can pay AWS not to care about this problem, we recommend you do that.&lt;/p&gt;
&lt;p&gt;Otherwise, there was a dark period between 2010 and 2016 where OpenSSL might not have been the right answer, but that time has passed. OpenSSL has gotten better, and, more importantly, OpenSSL is on-the-ball with vulnerability disclosure and response.&lt;/p&gt;
&lt;p&gt;Using anything besides OpenSSL will drastically complicate your system for little, no, or even negative security benefit. So just keep it simple.&lt;/p&gt;
&lt;p&gt;Speaking of simple: LetsEncrypt is free and automated. Set up a cron job to re-fetch certificates regularly, and test it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; offbeat TLS libraries like PolarSSL, GnuTLS, and MatrixSSL.&lt;/p&gt;
&lt;h4&gt;Client-server application security&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Distribute the server's public RSA key with the client code, and do not use SSL.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Use OpenSSL, or BoringSSL if you can. Or just use AWS ELBs&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt;  Use AWS ALB/ELB or OpenSSL, with LetsEncrypt&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; the previous recommendations about public-key crypto were relevant to you.*&lt;/p&gt;
&lt;p&gt;It seems a little crazy to recommend TLS given its recent history:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Logjam DH negotiation attack&lt;/li&gt;
&lt;li&gt;The FREAK export cipher attack&lt;/li&gt;
&lt;li&gt;The POODLE CBC oracle attack&lt;/li&gt;
&lt;li&gt;The RC4 fiasco&lt;/li&gt;
&lt;li&gt;The CRIME compression attack&lt;/li&gt;
&lt;li&gt;The Lucky13 CBC padding oracle timing attack&lt;/li&gt;
&lt;li&gt;The BEAST CBC chained IV attack&lt;/li&gt;
&lt;li&gt;Heartbleed&lt;/li&gt;
&lt;li&gt;Renegotiation&lt;/li&gt;
&lt;li&gt;Triple Handshakes&lt;/li&gt;
&lt;li&gt;Compromised CAs&lt;/li&gt;
&lt;li&gt;DROWN (though personally we’re warped and an opportunity to play with attacks like DROWN would be in our “pro” column)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's why you should still use TLS for your custom transport problem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In custom protocols, you don’t have to (and shouldn’t) depend on 3rd party CAs. You don’t even have to use CAs at all (though it’s not hard to set up your own); you can just use a whitelist of self-signed certificates  which is approximately what SSH does by default, and what you’d come up with on your own.&lt;/li&gt;
&lt;li&gt;Since you’re doing a custom protocol, you can use the best possible TLS cipher suites: TLS 1.2+, Curve25519, and ChaPoly. That eliminates most attacks on TLS. The reason everyone doesn’t do this is that they need backwards-compatibility, but in custom protocols you don’t need that.&lt;/li&gt;
&lt;li&gt;Many of these attacks only work against browsers, because they rely on the victim accepting and executing attacker-controlled Javascript in order to generate repeated known/chosen plaintexts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Avoid:&lt;/em&gt; designing your own encrypted transport, which is a genuinely hard engineering problem; using TLS but in a default configuration, like, with "curl"; using "curl", IPSEC.&lt;/p&gt;
&lt;h4&gt;Online backups&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Percival, 2009&lt;/em&gt;: Use Tarsnap.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ptacek, 2015&lt;/em&gt;: Use Tarsnap.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Latacora, 2018:&lt;/em&gt;  Store PMAC-SIV-encrypted arc files to S3 and save fingerprints of your backups to an ERC20-compatible blockchain.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;You care about this if:&lt;/em&gt; you bother backing things up.&lt;/p&gt;
&lt;p&gt;Just kidding. You should still use Tarsnap.&lt;/p&gt;
&lt;p&gt;(This post was syndicated on the Latacora blog.)&lt;/p&gt;</description><category>cryptography</category><guid>https://www.lvh.io/posts/cryptographic-right-answers/</guid><pubDate>Tue, 03 Apr 2018 21:25:00 GMT</pubDate></item><item><title>Crypto APIs and JVM byte types</title><link>https://www.lvh.io/posts/crypto-apis-and-jvm-byte-types/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;In a previous post, I talked about &lt;a href="https://www.lvh.io/posts/tradeoffs-in-cryptographic-api-design.html"&gt;crypto API tradeoffs&lt;/a&gt;. In this
post, I'll go into a specific API design case in &lt;a href="https://github.com/lvh/caesium"&gt;&lt;code&gt;caesium&lt;/code&gt;&lt;/a&gt;, my
cryptographic library for Clojure, a language that runs on the Java Virtual
Machine.&lt;/p&gt;
&lt;h3&gt;JVM byte types&lt;/h3&gt;
&lt;p&gt;The JVM has several standard byte types. For one-shot cryptographic APIs, the
two most relevant ones are byte arrays (also known as &lt;code&gt;byte[]&lt;/code&gt;) and
&lt;code&gt;java.nio.ByteBuffer&lt;/code&gt;.  Unfortunately, they have different pros and cons, so
there is no unambiguously superior choice.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ByteBuffer&lt;/code&gt; can produce slices of byte arrays and other byte buffers with
zero-copy semantics. This makes a useful tool when want to place an encrypted
message in a pre-allocated binary format. One example of this is my
&lt;a href="https://github.com/lvh/caesium/blob/master/src/caesium/magicnonce/secretbox.clj"&gt;experimental NMR suite&lt;/a&gt;. Another use case is generating more than
one key out of a single call to a key derivation function. The call produces
one (long) output, and &lt;code&gt;ByteBuffer&lt;/code&gt; lets you slice it into different keys.&lt;/p&gt;
&lt;p&gt;Byte arrays are easily serializable, but &lt;code&gt;ByteBuffer&lt;/code&gt; is not. Even if you
teach your serialization library about &lt;code&gt;ByteBuffer&lt;/code&gt;, this usually results in
extra copying during serialization.&lt;/p&gt;
&lt;p&gt;Byte arrays are constant length, and that length is stored with the array, so
it's cheap to access. Figuring out how much to read from a &lt;code&gt;ByteBuffer&lt;/code&gt;
requires a (trivial) amount of math by calling &lt;code&gt;remaining&lt;/code&gt;. This is because
the &lt;code&gt;ByteBuffer&lt;/code&gt; is a view, and it can be looking at a different part of the
underlying memory at different times. For a byte array, this is all fixed: a
byte array's starting and stopping points remain constant. Computing the
remaining length of a &lt;code&gt;ByteBuffer&lt;/code&gt; may not always be constant time, although
it probably is. Even if it isn't, it's probably not in a way that is relevant
to the security of the scheme (in &lt;code&gt;caesium&lt;/code&gt;, only cryptographic hashes,
detached signatures and detached MACs don't publicly specify the message
length).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ByteBuffer&lt;/code&gt; has a public API for allocating &lt;em&gt;direct&lt;/em&gt; buffers. This means they
are not managed by the JVM. Therefore they won't be copied around by the
garbage collector, and memory pinning is free. "Memory pinning" means that you
notify the JVM that some external C code is using this object, so it should
not be moved around or garbage collected until that code is done using that
buffer. You can't pass "regular" (non-direct) buffers to C code. When you do
that, the buffer is first copied under the hood. Directly allocated buffers
let you securely manage the entire lifecycle of the buffer. For example, they
can be securely zeroed out after use. Directly allocated &lt;code&gt;ByteBuffer&lt;/code&gt;
instances might have underlying arrays; this is explicitly unspecified.
Therefore, going back to an array &lt;em&gt;might&lt;/em&gt; be zero-copy. In my experiments,
these byte buffers never have underlying arrays, so copying is always
required. I have not yet done further research to determine if this generally
the case. In addition to &lt;code&gt;ByteBuffer&lt;/code&gt;, the&lt;code&gt;sun.misc.Unsafe&lt;/code&gt; class does have
options for allocating memory directly, but it's pretty clear that use of that
class is strongly discouraged. Outside of the JDK, the &lt;code&gt;Pointer&lt;/code&gt; API in
&lt;code&gt;jnr-ffi&lt;/code&gt; works identically to &lt;code&gt;ByteBuffer&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Design decisions&lt;/h3&gt;
&lt;p&gt;As a brief recap from my previous post, it's important that we design an API
that makes common things easy and hard things possible while remaining secure
and performant. For the cryptographic APIs in &lt;code&gt;caesium&lt;/code&gt;, there are a number of
variables to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Are the return types and arguments &lt;code&gt;ByteBuffer&lt;/code&gt; instances, byte arrays
   (&lt;code&gt;[B&lt;/code&gt;), &lt;code&gt;Pointer&lt;/code&gt; instances, or something else?&lt;/li&gt;
&lt;li&gt;Is the return type fixed per exposed function, or is the return
   type based on the input types, like Clojure's &lt;a href="https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/empty"&gt;&lt;code&gt;empty&lt;/code&gt;&lt;/a&gt;?&lt;/li&gt;
&lt;li&gt;Are the APIs "C style" (which passes in the output buffer as an argument)
   or "functional style" (which allocates the output buffer for you)?&lt;/li&gt;
&lt;li&gt;Does the implementation convert to the appropriate type (which might
   involve copying), does it use reflection to find the appropriate type, does
   it explicitly dispatch on argument types, or does it assume you give
   it some specific types?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these choices are orthogonal, meaning we can choose them
independently. With dozens of exposed functions, half a dozen or so arguments
per function with 2-4 argument types each, two function styles, four argument
conversion styles, and two ways of picking the return type, this easily turns
into a combinatorial explosion of many thousands of exposed functions.&lt;/p&gt;
&lt;p&gt;All of these choices pose trade-offs. We've already discussed the differences
between the different byte types, so I won't repeat them here. Having the
function manage the output buffer for you is the most convenient option, but
it also precludes using direct byte buffers effectively. Type conversion is
most convenient, but type dispatch is faster, and statically resolvable
dispatching to the right implementation is faster still. The correct return
value depends on context. Trying to divine what the user really wanted is
tricky, and, as we discussed before, the differences between those types are
significant.&lt;/p&gt;
&lt;p&gt;The functions exposed in caesium live on the inside of a bigger system, in the
same sense that IO libraries like &lt;a href="https://twistedmatrix.com/"&gt;Twisted&lt;/a&gt; and &lt;a href="https://github.com/ztellman/manifold"&gt;manifold&lt;/a&gt;
live on the edges. Something gives you some bytes, you perform some
cryptographic operations on them, and then the resulting bytes go somewhere
else. This is important, because it reduces the number of contexts in which
people end up with particular types.&lt;/p&gt;
&lt;h3&gt;Implementing the API&lt;/h3&gt;
&lt;p&gt;One easy decision is that the underlying binding should support every
permutation, regardless of what the API exposes. This would most likely
involve annoying code generation in a regular Java/jnr-ffi project, but
caesium is written in Clojure. The information on how to bind libsodium is a
Clojure data structure that gets compiled into an interface, which is what
jnr-ffi consumes. This makes it easy to expose every permutation, since it's
just some code that operates on a value. You can see this at work in the
&lt;a href="https://github.com/lvh/caesium/blob/master/src/caesium/binding.clj#L13"&gt;&lt;code&gt;caesium.binding&lt;/code&gt; namespace&lt;/a&gt;. As a consequence, an expert
implementer (who knows exactly which underlying function they want to call
with no "smart" APIs or performance overhead) can always just drop down to the
binding layer.&lt;/p&gt;
&lt;p&gt;Another easy call is that all APIs should raise exceptions, instead of
returning success codes. Success codes make sense for a C API, because there's
no reasonable exception mechanism available. However, problems like failed
decryption should definitely just raise exceptions.&lt;/p&gt;
&lt;p&gt;It gets tricky when we compare APIs that take an output buffer versus APIs
that build the output buffer for you. The latter are clearly the easiest to
use, but the former are necessary for explicit buffer life cycle
management. You can also easily build the managed version from the unmanaged
version, but you can't do the converse. As a consequence, we should expose
both.&lt;/p&gt;
&lt;p&gt;Having to expose both has the downside that we haven't put a dent in that
combinatorial explosion of APIs yet. Let's consider the cases in which someone
might have a byte buffer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They're using them as a slice of memory, where the underlying memory could
   be another byte buffer (direct or indirect) or a byte array -- usually a
   byte array wrapping a byte buffer.&lt;/li&gt;
&lt;li&gt;They're managing their own (presumably direct) output buffers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the former case, the byte buffers primarily act as inputs. In the latter,
they exclusively act as outputs. Because both byte buffers and byte arrays can
act as inputs, any API should be flexible in what it accepts. However, this
asymmetry in how the types are used, and how they can be converted, has
consequences for APIs where the caller manages the output buffer versus APIs
that manage it for you.&lt;/p&gt;
&lt;p&gt;When the API that manages the output buffer for you, the most reasonable
return type is a byte array. There is no difference between byte arrays
created by the API and those created by the caller, and there's no reasonable
way to reuse them. If you do really need a byte buffer for some reason,
wrapping that output array is simple and cheap. Conversely, APIs where the
caller manages the output buffer should use output byte buffers. Callers who
are managing their own byte buffer need to call an API that supports that, and
there's nothing to be gained from managing your own byte arrays (only direct
byte buffers). This is fine for internal use within &lt;code&gt;caesium&lt;/code&gt; — the byte array
producing API can just wrap it in a byte buffer view.&lt;/p&gt;
&lt;p&gt;This means we've reduced the surface significantly: APIs with caller-managed
buffers output to &lt;code&gt;ByteBuffer&lt;/code&gt;, and APIs that manage it themselves return byte
arrays. This takes care of the output types, but not the input types.&lt;/p&gt;
&lt;p&gt;Keys, salts, nonces, messages et cetera will usually be byte arrays, since
they're typically just read directly from a file or made on the spot. However
rare, there can be good reasons for having any of these as byte buffers. For
example, a key might have been generated from a different key using a key
derivation function; a nonce might be synthetically generated (as with
deterministic or nonce-misuse resistant schemes); either might be randomly
generated but just into a pre-existing buffer.&lt;/p&gt;
&lt;p&gt;The easiest way for this to work by default is reflection. That mostly works,
until it doesn't. Firstly, reflecting can be brittle. For example, if all of
your byte sequence types are known but a buffer length isn't, Clojure's
reflection will fail to find the appropriate method, even if it is
unambiguous. Secondly, unannotated Clojure fns always take boxed objects, not
primitives, which is what we want for calling into C. Annotating is imperfect,
too, because it moves the onus of producing a primitive to the caller. These
aren't really criticisms of Clojure. At this point we're well into weird edge
case territory which this system wasn't designed for.&lt;/p&gt;
&lt;p&gt;We can't do static dispatch for the public API, because we've established that
we should be flexible in our input types. We can work around the unknown type
problems with reflection using explicitly annotated call sites. That means
we're dispatching on types, which comes with its own set of issues. In the
next blog post, I'll go into more detail on how that works, with a bunch of
benchmarks. Stay tuned!&lt;/p&gt;</description><category>cryptography</category><guid>https://www.lvh.io/posts/crypto-apis-and-jvm-byte-types/</guid><pubDate>Mon, 11 Jul 2016 21:00:00 GMT</pubDate></item><item><title>Tradeoffs in cryptographic API design</title><link>https://www.lvh.io/posts/tradeoffs-in-cryptographic-api-design/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;Producing cryptographic software is a difficult and specialized endeavor. One
of the pitfalls is that getting it wrong looks exactly like getting it
right. Much like a latent memory corruption bug or a broken distributed
consensus algorithm, a piece of cryptographic software can appear to be
functioning perfectly, while being subtly broken in a way that only comes to
light years later. As the adage goes, attacks never get worse; they only get
better. Implementation concerns like timing attacks can be fiendishly
complicated to solve, involving problems like division instructions on modern
Intel CPUs taking a variable number of cycles depending on the size of the
input. Implementation concerns aren't the only problem; just designing the
APIs themselves is a complex task as well.&lt;/p&gt;
&lt;p&gt;Like all API design, cryptographic API design is a user experience
exercise. It doesn't matter how strong or fast your cryptographic software is
if no one uses it. The people who end up with ECB mode didn't end up with it
because they understood what that meant. They got stuck with it because it was
the default and it didn't require thinking about scary parameters like IVs,
nonces, salts and tweaks. Even if someone ended up with CTR or CBC, these APIs
are still precarious; they'll still be vulnerable to issues like nonce
reuse, fixed IV, key-as-IV, unauthenticated encryption...&lt;/p&gt;
&lt;p&gt;User experience design always means deep consideration of who your users
are. A particular API might be necessary for a cryptographic engineer to build
new protocols, but that API is probably not a reasonable default encryption
API. An explicit-nonce encryption scheme is great for a record layer protocol
between two peers like TLS, but it's awful for someone trying to encrypt a
session cookie. We can't keep complaining about people getting it wrong when
we keep giving them no chances at getting it right. This is why I'm building
educational material like &lt;a href="https://www.crypto101.io/"&gt;Crypto 101&lt;/a&gt; and why I care about
cryptography like &lt;a href="https://www.lvh.io/posts/nonce-misuse-resistance-101.html"&gt;nonce-misuse resistance&lt;/a&gt; that's easier to use
correctly.  (The blog post on my new nonce-misuse resistant schemes for
libsodium is coming soon, I promise!)&lt;/p&gt;
&lt;p&gt;Before you can make your API easy to use, first you have to worry about
getting it to work at all.&lt;/p&gt;
&lt;p&gt;An underlying cryptographic library might expose an unfortunate API. It might
be unwieldy because of historical reasons, backwards compatibility, language
limitations, or even simple oversight. Regardless of why the API is the way it
is, even minute changes to it—a nicer type, an implied parameter—might have
subtle but catastrophic consequences for the security of the final
product. Figuring out if an arbitrary-length integer in your programming
language is interchangeable with other representations, like the
implementation in your crypto library or a &lt;code&gt;char *&lt;/code&gt;, has many complex
facets. It doesn't just have to be true under some conditions; ideally, it's
true for every platform your users will run your software on, in perpetuity.&lt;/p&gt;
&lt;p&gt;There might be an easy workaround to an annoying API. C APIs often take a
&lt;code&gt;char *&lt;/code&gt; together with a length parameter, because C doesn't have a standard
way of passing a byte sequence together with its length. Most higher level
languages, including Java and Python, have byte sequence types that know their
own length. Therefore, you can specify the &lt;code&gt;char *&lt;/code&gt; and its associated length
in a single parameter on the high-level side. That's just the moral equivalent
of building a small C struct that holds both. (Whether or not you can trust C
compilers to get anything right at all is a point of contention.)&lt;/p&gt;
&lt;p&gt;These problems compound when you are binding libraries in languages and
environments with wildly different semantics. For example, your runtime might
have a relocating garbage collector.  Pointers in C and objects in CPython
stay put, but objects move around all the time in environments like the JVM
(HotSpot) or PyPy. That implies copying to or from a buffer whenever you call
C code, unless the underlying virtual machine supports "memory pinning":
forcing the object to stay put for the duration of the call.&lt;/p&gt;
&lt;p&gt;Programmers normally operate in a drastically simplified model of the
world. We praise programming designs for their ability to separate concerns,
so that programmers can deal with one problem at a time. The modern CPU your
code runs on is always an intricate beast, but you don't worry about cache
lines when you're writing a Python program. Only a fraction of programmers
ever has to worry about them at all. Those that do typically only do so after
the program already works so they can still focus on one part of the problem.&lt;/p&gt;
&lt;p&gt;When designing cryptographic software, these simplified models we normally
program in don't generally work.  A cryptographic engineer often needs to
worry about concerns all the way up and down the stack simultaneously: from
application layer concerns, to runtime semantics like the
&lt;a href="https://docs.oracle.com/javase/specs/jls/se8/html/index.html"&gt;Java Language Specification&lt;/a&gt;, to FFI semantics and the C ABI on all
relevant platforms, to the underlying CPU, to the mathematical underpinnings
themselves. The engineer has to manage all of those, often while being
hamstrung by flawed designs like TLS' MAC-then-pad-then-encrypt mess.&lt;/p&gt;
&lt;p&gt;In future blog posts, I'll go into more detail about particular cryptographic
API design concerns, starting with JVM byte types. If you're interested, you
should &lt;a href="https://twitter.com/lvh"&gt;follow me on Twitter&lt;/a&gt; or &lt;a href="https://www.lvh.io/rss.xml"&gt;subscribe to my blog's feed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Footnote:&lt;/em&gt; I'm happy to note that &lt;a href="https://bitbucket.org/cffi/cffi/commits/61e03368485cb78471f701adbfd1bde69a6eaa31"&gt;cffi&lt;/a&gt; now also has
support for memory pinning since PyPy will support it in the upcoming
5.2 release, although that means I'll no longer be able to make
&lt;a href="https://github.com/reaperhulk"&gt;Paul Kehrer of PyCA fame&lt;/a&gt; jealous with the pinning support in
&lt;a href="https://github.com/lvh/caesium"&gt;caesium&lt;/a&gt;.&lt;/p&gt;</description><category>cryptography</category><guid>https://www.lvh.io/posts/tradeoffs-in-cryptographic-api-design/</guid><pubDate>Sat, 18 Jun 2016 20:45:35 GMT</pubDate></item><item><title>Nonce misuse resistance 101</title><link>https://www.lvh.io/posts/nonce-misuse-resistance-101/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;&lt;em&gt;This post is an introduction to nonce-misused resistant cryptosystems and why
I think they matter. The first part of this post is about nonce-based
authenticated encryption schemes: how they work, and how they fail. If you're
already familiar with them, you can skip to the section on
&lt;a href="https://www.lvh.io/posts/nonce-misuse-resistance-101/#proto"&gt;protocol design&lt;/a&gt;. If you're completely new to cryptography, you might
like my free introductory course to cryptography, &lt;a href="https://www.crypto101.io"&gt;Crypto 101&lt;/a&gt;. In a
future blog post, I'll talk about some nonce-misuse resistant schemes I've
implemented using libsodium.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Many stream ciphers and stream cipher-like constructions such as CTR,
GCM, (X)Salsa20... take a nonce. You can think of it as a pointer that lets
you jump to a particular point in the keystream. This makes these ciphers
"seekable", meaning that you can decrypt a small part of a big ciphertext,
instead of having to decrypt everything up to that point first. (That ends up
being trickier than it seems, because you still want to authenticate that
small chunk of ciphertext, but that's a topic for another time.)&lt;/p&gt;
&lt;p&gt;The critical security property of a nonce is that it's never repeated under
the same key. You can remember this by the mnemonic that a &lt;em&gt;nonce&lt;/em&gt; is a
"number used once". If you were to repeat the nonce, the keystream would also
repeat. That means that an attacker can take the two ciphertexts and XOR them
to compute the XOR of the plaintexts. If &lt;code&gt;C_n&lt;/code&gt; are ciphertexts, &lt;code&gt;P_n&lt;/code&gt;
plaintexts, &lt;code&gt;K_n&lt;/code&gt; keystreams, and &lt;code&gt;^&lt;/code&gt; is bitwise exclusive or:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;C_1 = K_1 ^ P_1
C_2 = K_2 ^ P_2
&lt;/pre&gt;


&lt;p&gt;The attacker just XORs &lt;code&gt;C_1&lt;/code&gt; and &lt;code&gt;C_2&lt;/code&gt; together:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;C_1 ^ C_2 = K_1 ^ P_1 ^ K_2 ^ P_2
&lt;/pre&gt;


&lt;p&gt;Since XOR is commutative (you can rearrange the order), &lt;code&gt;K_1 = K_2&lt;/code&gt;, and
XOR'ing two equal values cancels them out:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;C_1 ^ C_2 = P_1 ^ P_2
&lt;/pre&gt;


&lt;p&gt;That tells an attacker a lot about the plaintext, especially if some of one of
the plaintexts is predictable. If the attacker has access to an encryption
oracle, meaning that they can get encryptions for plaintexts of their
choosing, they can even get perfect decryptions. That is not an unrealistic
scenario. For example, if you're encrypting session cookies that contain the
user name and e-mail, I can register using a name and e-mail address that has
a lot of &lt;code&gt;Z&lt;/code&gt; characters, and then I know that just XORing with &lt;code&gt;Z&lt;/code&gt; will reveal
most of the plaintext. For an idea of the state of the art in attacking
two-time pads (the usual term for two ciphertexts with a reused keystream),
see &lt;a href="https://www.cs.jhu.edu/~jason/papers/mason+al.ccs06.pdf"&gt;Mason06&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a id="proto"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Protocol design&lt;/h3&gt;
&lt;p&gt;For many on-line protocols like TLS, the explicit nonce provides a convenient
way to securely send many messages under a per-session key. Because the
critical security property for a nonce is that it is never repeated with the
same key, it's safe to use a counter. In protocols where both peers send
messages to each other, you can just have one peer use odd nonces and have the
other use even ones. There are some caveats here: for example, if the nonce
size is sufficiently small, an attacker might try to make that counter
overflow, resulting in a repeated nonce.&lt;/p&gt;
&lt;p&gt;For off-line (or at-rest) protocols, it's a little trickier. You don't have a
live communication channel to negotiate a new ephemeral key over, so you're
stuck with longer-term keys or keys derived from them. If multiple systems are
participating, you need to decide ahead of time which systems own which
nonces. Even then, systems need to keep track of which nonces they've
used. That doesn't work well, especially not in a distributed system where
nodes and connections can fail at any time. This is why some cryptosystems
like &lt;a href="https://cryptography.io/en/latest/fernet/"&gt;Fernet&lt;/a&gt; provide an API that doesn't require you to specify
anything besides a key and a message.&lt;/p&gt;
&lt;p&gt;One solution is to use randomized nonces. Since nonces can't repeat, random
nonces should be large: if they're too small, you might randomly select the
same nonce twice, per the birthday bound. That is the only difference between
Salsa20 and XSalsa20: Salsa20 has a 64 bit nonce, whereas XSalsa20 has a 192
bit nonce. That change exists explicitly to make random nonces secure.&lt;/p&gt;
&lt;p&gt;Picking a random nonce and just prepending it to the secretbox ciphertext is
secure, but there are a few problems with this approach. It's not clear to
practitioners that that's a secure construct. Doing this may seem obvious to a
cryptographer, but not to someone who just wants to encrypt a
message. Prepending a nonce doesn't feel much different from e.g. appending a
MAC. A somewhat knowledgeable practitioner knows that there's plenty of ways
to use MACs that are insecure, and they don't immediately see that the
prefix-nonce construction is secure. Not wanting to design your own
cryptosystems is a good reflex which we should be encouraging.&lt;/p&gt;
&lt;p&gt;Random nonces also mean that any system sending messages needs access to
high-quality random number generators while they're sending a message. That's
often, but not always true. Bugs around random number generation, especially
userspace CSPRNGs, &lt;a href="http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/"&gt;keep popping up&lt;/a&gt;. This is often a consequence of
poor programming practice, but it can also be a consequence of
poorly-configured VMs or limitations of embedded hardware.&lt;/p&gt;
&lt;h3&gt;Nonce-misuse resistant systems&lt;/h3&gt;
&lt;p&gt;To recap, not all protocols have the luxury of an obvious nonce choice, and
through circumstances or poor practices, nonces might repeat
anyway. Regardless of how cryptographers feel about how important nonce misuse
is, we can anecdotally and empirically verify that such issues are real and
common. This is true even for systems like TLS where there is an "obvious"
nonce available (&lt;a href="https://eprint.iacr.org/2016/475.pdf"&gt;Böck et al, 2016&lt;/a&gt;). It's easy to point fingers, but
it's better to produce cryptosystems that fail gracefully.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://web.cs.ucdavis.edu/~rogaway/papers/keywrap.pdf"&gt;Rogaway and Shrimpton (2006)&lt;/a&gt; defined a new model called nonce-misuse
resistance. Informally, nonce-misuse resistance schemes ensure that a repeated
random nonce doesn't result in plaintext compromise. In the case of a broken
system where the attacker can cause repeated nonces, an attacker will only be
able to discern if a particular message repeated, but they will not be able
to decrypt the message.&lt;/p&gt;
&lt;p&gt;Rogaway and Shrimpton also later developed a mode of operation called SIV
(synthetic IV), which Gueron and Lindell are refined to GCM-SIV, a SIV-like
that takes advantage of fast GCM hardware implementations. Those two authors
are currently working with Adam Langley to standardize the AES-GCM-SIV
construction through CFRG. AEZ and HS1-SIV, two entries in the CAESAR
competition, also feature nonce-misuse resistance. CAESAR is an ongoing
competition, and GCM-SIV is not officially finished yet, so this is clearly
a field that is still evolving.&lt;/p&gt;
&lt;p&gt;There are parallels between nonce-misuse resistance and length extension
attacks. Both address issues that arguably only affected systems that were
doing it wrong to begin with. (Note, however, in the embedded case above, it
might not be a software design flaw but a hardware limitation.) Fortunately,
the SHA-3 competition showed that you can have increased performance and
still be immune to a class of problems. I'm hopeful that CAESAR will consider
nonce-misuse resistance an important property of an authenticated encryption
standard.&lt;/p&gt;
&lt;h3&gt;Repeated messages&lt;/h3&gt;
&lt;p&gt;Repeated messages are suboptimal, and in some protocols they might be
unacceptable. However, they're a fail-safe failure mode for nonce
misuse. You're not choosing to have a repeated ciphertext, you're just getting
a repeated ciphertext instead of a plaintext disclosure (where the attacker
would also know that you repeated a message). In the case of a secure random
nonce, a nonce-misuse resistant scheme is just as secure, at the cost of a
performance hit.&lt;/p&gt;
&lt;p&gt;In a context where attackers can see individual messages to detect repeated
ciphertexts, it makes sense to also consider a model where attackers can
replay messages. If replaying messages (which presumably have side effects) is
a problem, a common approach is to add a validity timestamp. This is a feature
of &lt;a href="https://cryptography.io/en/latest/fernet/"&gt;Fernet&lt;/a&gt;, for example. A device that doesn't have access to
sufficient entropy will still typically have access to a reasonably
high-resolution clock, which is still more than good enough to make sure the
synthetic IVs don't repeat either.&lt;/p&gt;
&lt;h3&gt;OK, but how does it work?&lt;/h3&gt;
&lt;p&gt;Being able to trade plaintext disclosure for attackers being able to detect
repeated messages sounds like magic, but it makes sense once you realize how
they work. As demonstrated in the start of this post, nonce re-use normally
allows an attacker to have two keystreams cancel out. That only makes sense if
two &lt;em&gt;distinct&lt;/em&gt; messages are encrypted using the same (key, nonce) pair. NMR
solves this by making the nonce also depend on the message itself. Informally,
it means that a nonce should never repeat for two distinct
messages. Therefore, an attacker can't cancel out the keystreams without
cancelling out the messages themselves as well.&lt;/p&gt;
&lt;p&gt;This model does imply off-line operation, in that the entire message has to be
scanned before the nonce can be computed. For some protocols, that may not be
acceptable, although plenty of protocols work around this assumption by simply
making individual messages sufficiently small.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Aaron Zauner and Kurt Griffiths for proofreading this post.&lt;/em&gt;&lt;/p&gt;</description><category>cryptography</category><category>security</category><guid>https://www.lvh.io/posts/nonce-misuse-resistance-101/</guid><pubDate>Thu, 19 May 2016 19:25:44 GMT</pubDate></item><item><title>Supersingular isogeny Diffie-Hellman 101</title><link>https://www.lvh.io/posts/supersingular-isogeny-diffie-hellman-101/</link><dc:creator>lvh</dc:creator><description>&lt;p&gt;Craig Costello, Patrick Longa and Michael Naehrig, three cryptographers at
Microsoft Research, recently published a &lt;a href="https://eprint.iacr.org/2016/413"&gt;paper&lt;/a&gt; on supersingular
isogeny Diffie-Hellman. This paper garnered a lot of interest in the security
community and even made it to the front page of Hacker News. Most of the
discussion around it seemed to be how no one understands isogenies, even
within cryptography-literate communities. This article aims to give you a
high-level understanding of what this cryptosystem is and why it works.&lt;/p&gt;
&lt;p&gt;This post assumes that you already know how Diffie-Hellman works in the
abstract, and that you know elliptic curves are a mathematical construct that
you can use to perform Diffie-Hellman operations, just like you can with the
integers &lt;em&gt;mod p&lt;/em&gt; (that would be "regular" Diffie-Hellman). If that was
gibberish to you and you'd like to know more, check out &lt;a href="https://www.crypto101.io"&gt;Crypto 101&lt;/a&gt;, my
free introductory book on cryptography. You don't need a math background to
understand those concepts at a high level. The main difference is that Crypto
101 sticks to production cryptography, while this is still experimental.&lt;/p&gt;
&lt;p&gt;It's not surprising that isogeny-based cryptography is so confusing. Up until
recently, it was unambiguously in the realm of research, not even close to
being practically applicable. Its mathematical underpinnings are much more
complex than regular elliptic curves, let alone integers &lt;em&gt;mod p&lt;/em&gt;. It also
looks superficially similar to elliptic curve Diffie-Hellman, which only adds
to the confusion.&lt;/p&gt;
&lt;p&gt;With that, let's begin!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is this paper about?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Supersingular isogeny Diffie-Hellman (SIDH) is one of a handful of
"post-quantum" cryptosystems. Those are cryptosystems that will remain secure
even if the attacker has access to a large quantum computer. This has nothing
to do with quantum cryptography (for example, quantum key distribution)
beyond their shared quantum mechanical underpinning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why should I care about quantum computers?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;General quantum computers are not useful as general-purpose computing devices,
but they can solve some problems much faster than classical
computers. Classical computers can emulate quantum computers, but only with
exponential slowdown. A sufficiently large quantum computer could break most
production cryptography, including cryptosystems based on the difficulty of
factoring large numbers (like RSA), taking discrete logs over the integers
&lt;em&gt;mod p&lt;/em&gt; (like regular DH), or taking discrete logs over elliptic curves (like
ECDH and ECDSA). To quantify that, consider the following table:&lt;/p&gt;
&lt;p&gt;&lt;img alt="quantum computer attack cost versus classical" src="https://www.lvh.io/img/post-quantum/quantum-computer-relative-cost.png"&gt;&lt;/p&gt;
&lt;p&gt;In this table, n refers to the modulus size for RSA, and the field size for
ECC. Look at the rightmost column, which represents time taken by the
classical algorithm, and compare it to the "time" columns, which represent how
much a quantum computer would take. As &lt;em&gt;n&lt;/em&gt; increases, the amount of time the
quantum computer would take stays in the same ballpark, whereas, for a
classical computer, it increases (almost) exponentially. Therefore, increasing
n is an effective strategy for keeping up with ever-faster classical
computers, but it is ineffective at increasing the run time for a quantum
computer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Aah! Why isn't everyone panicking about this?!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The good news is that these large quantum computers don't exist yet.&lt;/p&gt;
&lt;p&gt;If you look at the qubits column, you'll see that these attacks require large
universal quantum computers. The state of the art in those only has a handful
of qubits. In 2011, IBM successfully factored 143 using a 4-qubit quantum
computer. Scaling the number of qubits up is troublesome. In that light,
larger key sizes may prove effective after all; we simply don't know yet how
hard it is to build quantum computers that big.&lt;/p&gt;
&lt;p&gt;D-wave, a quantum computing company, has produced computers with 128 and 512
qubits and even &amp;gt;1000 qubits. While there is some discussion if D-waves
provide quantum speedup or are even real quantum computers at all; there is no
discussion that they are not &lt;em&gt;universal&lt;/em&gt; quantum computers. Specifically, they
only claim to solve one particular problem called quantum annealing. The 1000
qubit D-Wave 2X cannot factor RSA moduli of ~512 bits or solve discrete logs
on curves of ~120 bits.&lt;/p&gt;
&lt;p&gt;The systems at risk implement asymmetric encryption, signatures, and
Diffie-Hellman key exchanges. That's no accident: all post-quantum
alternatives are asymmetric algorithms. Post-quantum secure symmetric
cryptography is easier: we can just use bigger key sizes, which are still
small enough to be practical and result in fast primitives. Quantum computers
simply halve the security level, so all we need to do to maintain a 128 bit
security level is to use ciphers with 256 bit keys, like Salsa20.&lt;/p&gt;
&lt;p&gt;Quantum computers also have an advantage against SIDH, but both are still
exponential in the field size. The SIDH scheme in the new paper has 192 bits
of security against a classical attacker, but still has 128 bits of security
against a quantum attacker. That's in the same ballpark as most symmetric
cryptography, and better than the 2048-bit RSA certificates that underpin the
security of the Internet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What makes this paper special?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Post-quantum cryptography has been firmly in the realm of academic research
and experiments. This paper makes significant advancements in how practically
applicable SIDH is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Being future-proof sounds good. If this makes it practical, why don't we
start using it right now?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;SIDH is a young cryptosystem in a young field, and hasn't had the same level
of scrutiny as some of the other post-quantum cryptosystems, let alone the
"regular" cryptosystems we use daily. Attacks only get better, they never get
worse. It's possible that SIDH is insecure, and we just don't know how to
break it yet. It does have a good argument for why quantum algorithms wouldn't
be able to crack it (more on that later), but that's a hypothesis, not a
proof.&lt;/p&gt;
&lt;p&gt;The new performance figures from this paper are impressive, but this system is
still much slower than the ones we use today. Key generation and key exchange
take a good 50 million cycles or so each. That's about a thousand times slower
than Curve25519, a curve designed about 10 years ago. Key sizes are also much
larger: SIDH public keys are 751 bytes, whereas Curve25519 keys are only 32
bytes. For on-line protocols like HTTPS operating over TCP, that's a
significant cost.&lt;/p&gt;
&lt;p&gt;Finally, there are issues with implementing SIDH safely. Systems like
Diffie-Hellman over integers &lt;em&gt;mod p&lt;/em&gt; are much less complex than elliptic curve
Diffie-Hellman (ECDH), let alone SIDH. With ECDH and ECC in general, we've
seen new implementation difficulties, especially with early curves. Point
addition formulas would work, unless you were adding a point to itself. You
have to check that input points are on the curve, or leak the secret key
modulo some small order. These are real implementation problems, even though
we know how to solve them.&lt;/p&gt;
&lt;p&gt;This is nothing compared to the difficulties implementing SIDH. Currently,
SIDH security arguments rely on honest peers. A peer that gives you a
pathological input can utterly break the security of the scheme. To make
matters worse, while we understand how to verify inputs for elliptic curve
Diffie-Hellman, we don't have a way to verify inputs for isogeny-based
cryptography at all. We don't have much research to fall back on here
either. This isn't a SIDH-specific problem; post-quantum cryptography isn't
mature enough yet to have implementation issues like these nailed down
yet. (For an example from lattice-based cryptography, see the recent paper by
&lt;a href="https://eprint.iacr.org/2016/415"&gt;Bindel et al&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;I don't want to diminish the importance of this paper in any way!  Just
because it's not something that your browser is going to be doing tomorrow
doesn't mean it's not an impressive accomplishment. It's just a step on the
path that might lead to production crypto one day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OK, fine. Why is this so different from elliptic curve Diffie-Hellman?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While SIDH and ECDH both use elliptic curves, they're different beasts. SIDH
generates new curves to perform a DH exchange, whereas ECDH uses points on one
fixed curve. These supersingular curves also have different properties from
regular curves. Using a supersingular curve for regular elliptic curve
operations would be horribly insecure. If you have some background in elliptic
curves: supersingular curves have a tiny embedding degree, meaning that
solving the ECDLP over &lt;code&gt;F(p)&lt;/code&gt; can easily be transformed into solving the DLP
over &lt;code&gt;F(p^n)&lt;/code&gt; where &lt;code&gt;n&lt;/code&gt; is that small embedding degree. Most curves have large
embedding degrees, meaning that solving the ECDLP directly is easier than
translating it into a DLP and then solving that.  You generally have to go out
of your way to find a curve with a small embedding degree. That is only done
in specialized systems, like for pairing-based cryptography, or, as in this
case, supersingular isogeny-based Diffie-Hellman.&lt;/p&gt;
&lt;p&gt;Let's recap ECDH. Public keys are points on a curve, and secret keys are
numbers. Alice and Bob agree on the parameters of the exchange ahead of time,
such as the curve &lt;em&gt;E&lt;/em&gt; and a generator point &lt;em&gt;P&lt;/em&gt; on that curve. Alice picks a
secret integer &lt;em&gt;a&lt;/em&gt; and computes her public key &lt;em&gt;aP&lt;/em&gt;. Bob picks a secret
integer &lt;em&gt;b&lt;/em&gt; and computes his public key &lt;em&gt;bP&lt;/em&gt;. Alice and Bob send each other
their public keys, and multiply their secret key by the other peer's public
key. Since &lt;em&gt;abP = baP&lt;/em&gt;, they compute the same secret. Since an attacker has
neither secret key, they can't compute the shared secret.&lt;/p&gt;
&lt;p&gt;SIDH is different. Secret keys are isogenies...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Whoa whoa whoa. What the heck are isogenies?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An isogeny between elliptic curves is a function from one elliptic curve to
another that preserves base points. That means it takes points on one curve
and returns points on the other curve. Every point on the input curve will map
to a point on the output curve; but multiple points may map to the same
point. Formally speaking, the isogeny is surjective. An isogeny is also a
homomorphism. That is, it preserves the structure of the curve. For any two
points P and Q, &lt;code&gt;phi(P + Q) = phi(P) + phi(Q)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We have a bunch of formulas for generating isogenies from a curve and a
point. You might remember that the set of values a function takes is its
"domain", and the set of values it returns is called its "codomain". The
domain of such an isogeny is the curve you give it; its codomain might be the
same curve, or it might be a different one. In general, for SIDH, we care
about the case where it produces a new curve.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OK, so explain how SIDH works again.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Roughly speaking, a secret key is an isogeny, and a public key is an elliptic
curve. By "mixing" their isogeny with the peer's public curve, each peer
generates a secret curve. The two peers will generally generate different
curves, but those curves will have the same j-invariant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wait, what's a j-invariant?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The j-invariant is a number you can compute for a particular curve. Perhaps
the best analogy would be the discriminant for quadratic equation you might
remember from high school math; it's a single number that tells you something
interesting about the underlying curve. There are different formulas for
curves in different forms. For example, for a curve in short Weierstrass form
&lt;code&gt;y^2 = x^3 + ax + b&lt;/code&gt;, the j-invariant is:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;j(E) = (1728 * 4a^3)/(4a^3 + 27b^2)
&lt;/pre&gt;


&lt;p&gt;The j-invariant has a few cool properties. For example, while this is the
formula for the short Weierstrass form, the value of j doesn't change if you
put the same curve in a different form. Also, all curves with the same
j-invariant are isomorphic. However, for SIDH you don't really care about
these properties; you just care that the j-invariant is a number you can
compute, and it'll be the same for the two secret curves that are generated by
the DH exchange.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OK, try explaining SIDH again.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The protocol fixes a supersingular curve E and four points on that
curve: P_A, Q_A, P_B, Q_B.&lt;/p&gt;
&lt;p&gt;Alice picks two random integers, m_A and n_A. She takes a linear combination
of those two integers with P_A and Q_A to produce a random point R_A, so:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;R_A = n_A * P_A + m_A * Q_A
&lt;/pre&gt;


&lt;p&gt;That random point defines Alice's secret isogeny through the isogeny formulas
I talked about above. The codomain of that isogeny forms Alice's public
curve. Alice transforms points P_B and Q_B with the isogeny. She sends Bob her
public curve and the two transformed points.&lt;/p&gt;
&lt;p&gt;Bob does the same thing, except with A and B swapped.&lt;/p&gt;
&lt;p&gt;Once Alice gets Bob's public key, she applies m_A and n_A again to the
corresponding transformed points she got from Bob. She generates a new isogeny
phiBA from the resulting point just like she did before to generate her
private key. That isogeny's codomain will be an elliptic curve E_BA.&lt;/p&gt;
&lt;p&gt;When Bob performs his side of the exchange, he'll produce a different isogeny
and a different elliptic curve E_AB; but it will have the same j-invariant as
the curve Alice computed.  That j-invariant is the shared key.&lt;/p&gt;
&lt;p&gt;I've compiled a &lt;a href="https://www.lvh.io/sage/Supersingular%20Isogeny%20Elliptic%20Curve%20Cryptography%20--%20Sage.pdf"&gt;transcript&lt;/a&gt; of a Diffie-Hellman exchange using
Sage so you can see a (toy!) demo in action.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I know a little about elliptic curves. I thought they were always
non-singular. What's a supersingular elliptic curve but a contradiction in
terms?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You're right! Supersingular elliptic curves are somewhat confusingly
named. Supersingular elliptic curves are still elliptic curves, and they are
non-singular just like all other elliptic curves. The "supersingular" refers
to the singular values of the j-invariant. Equivalently, the Hasse invariant
will be 0.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So, why does it matter that the curve is supersingular?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Firstly, computing the isogeny is much easier on supersingular curves than on
ordinary (not supersingular) elliptic curves. Secondly, if the curve is
ordinary, the scheme can be broken in subexponential time by a quantum
attacker.&lt;/p&gt;
&lt;p&gt;Isogeny-based cryptography using ordinary curves was considered as a
post-quantum secure cryptosystem before SIDH. However, Childs et al. showed a
subexponential quantum algorithm in 2010. This paper appeared to have ended
isogeny-based cryptography: it was already slower than other post-quantum
systems, and now it was shown that it wasn't even post-quantum secure.&lt;/p&gt;
&lt;p&gt;Because supersingular curves are rare, they had not previously been considered
for isogeny-based cryptography. However, the paper itself suggested that
supersingular curves might be worth examining, so it ended up pushing research
in a new direction rather than ending it.&lt;/p&gt;
&lt;p&gt;Explaining why the supersingular curve makes the problem quantum-hard is
tricky without being thoroughly familiar with isogenies and quantum
computing. If you're really interested, &lt;a href="https://arxiv.org/pdf/1012.4019v2.pdf"&gt;the Childs paper&lt;/a&gt; explains
how the quantum attack in the ordinary case works. Informally, in the ordinary
case, there is a group action (the &lt;em&gt;isogeny star operator&lt;/em&gt;) of the ideal class
group onto the set of isomorphism classes of isogenous curves with the same
endomorphism ring. That can be shown to be a special case of the abelian group
hidden shift problem, which can be solved quickly on a quantum computer. In
the supersingular case, there is no such group action to exploit. (If you're
trying to solve for this at home; this is why SIDH needs to define the 4
points P_A, P_B, Q_A, Q_B.)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I would like to thank Thomas Ptacek for reviewing this blog post and bearing
with me as I struggle through trying to come up with human-readable
explanations for all of this stuff; Sean Devlin for reminding me that Sage is
an excellent educational tool; and Watson Ladd for pointing out a correction
w.r.t the Hasse invariant (the Hasse-Witt matrix is undefined, not
singular.). Finally, I'd like to thank all the people who reviewed drafts of
this post, including (in no particular order) Bryan Geraghty, Shane Wilton,
Sean Devlin, Thomas Ptacek, Tanner Prynn, Glyph Lefkowitz and Chris Wolfe.&lt;/em&gt;&lt;/p&gt;</description><category>cryptography</category><category>security</category><guid>https://www.lvh.io/posts/supersingular-isogeny-diffie-hellman-101/</guid><pubDate>Sat, 30 Apr 2016 16:00:28 GMT</pubDate></item></channel></rss>