<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>ImperialViolet</title>
 <link href="http://www.imperialviolet.org/iv-rss.xml" rel="self"/>
 <link href="http://www.imperialviolet.org/"/>
 <updated>2018-04-19T13:21:52-04:00</updated>
 <id>http://www.imperialviolet.org/</id>
 <author>
   <name>Adam Langley</name>
 </author>

 
 <entry>
   <title>Post-quantum confidentiality for TLS</title>
   <link href="http://www.imperialviolet.org/2018/04/11/pqconftls.html"/>
   <updated>2018-04-11T00:00:00-04:00</updated>
   <id>http://www.imperialviolet.org/2018/04/11/pqconftls</id>
   <content type="html">&lt;p&gt;In 2016, my colleague, Matt Braithwaite, ran &lt;a href=&quot;https://security.googleblog.com/2016/07/experimenting-with-post-quantum.html&quot;&gt;an experiment&lt;/a&gt; in Google Chrome which integrated a post-quantum key-agreement primitive (&lt;a href=&quot;https://eprint.iacr.org/2015/1092.pdf&quot;&gt;NewHope&lt;/a&gt;) with a standard, elliptic-curve one (X25519). Since that time, &lt;a href=&quot;https://csrc.nist.gov/projects/post-quantum-cryptography/round-1-submissions&quot;&gt;the submissions&lt;/a&gt; for the 1&lt;sup&gt;st&lt;/sup&gt; round of &lt;a href=&quot;https://csrc.nist.gov/projects/post-quantum-cryptography&quot;&gt;NIST’s post-quantum process&lt;/a&gt; have arrived. We thus wanted to consider which of the submissions, representing the new state of the art, would be most suitable for future work on post-quantum confidentiality in TLS.&lt;/p&gt;

&lt;p&gt;A major change since the 2016 experiment is the transition from TLS 1.2 to TLS 1.3 (a nearly-final version of which is now enabled by default in Chrome). This impacts where in the TLS handshake the larger post-quantum messages appear:&lt;/p&gt;

&lt;p&gt;In TLS 1.2, the client offers possible cipher suites in its initial flow, the server selects one and sends a public-key in its reply, then the client completes the key-agreement in its second flow. With TLS 1.3, the client &lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-tls-tls13-26#section-4.2.8&quot;&gt;offers several possible public-keys&lt;/a&gt; in its initial flow and the server completes one of them in its reply. Thus, in a TLS 1.3 world, the larger post-quantum keys will be sent to &lt;em&gt;every&lt;/em&gt; TLS server, whether or not they’ll use it.&lt;/p&gt;

&lt;p&gt;(There is a mechanism in TLS 1.3 for a client to advertise support for a key-agreement but not provide a public-key for it. In this case, if the server wishes to use that key-agreement, it replies with a &lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-tls-tls13-26#section-4.1.4&quot;&gt;special message&lt;/a&gt; to indicate that the client should try again and include a public-key because it’ll be accepted. However, this obviously adds an extra round-trip and we don’t want to penalise more secure options—at least not if we want them adopted. Therefore I’m assuming here that any post-quantum key agreement will be optimistically included in the initial message. For a diagram of how this might work with a post-quantum KEM, see figure one of the &lt;a href=&quot;https://eprint.iacr.org/2017/634.pdf&quot;&gt;Kyber paper&lt;/a&gt;. Also I'm using the term &amp;ldquo;public-key&amp;rdquo; here in keeping with the KEM constructions of the post-quantum candidates. It's not quite the same as a Diffie-Hellman value, but it's close enough in this context.)&lt;/p&gt;

&lt;p&gt;In order to evaluate the likely latency impact of a post-quantum key-exchange in TLS, Chrome was augmented with the ability to include a dummy, arbitrarily-sized extension in the TLS ClientHello. To be clear: this was &lt;em&gt;not&lt;/em&gt; an implementation of any post-quantum primitive, it was just a fixed number of bytes of random noise that could be sized to simulate the bandwidth impact of different options. It was included for all versions of TLS because this experiment straddled the enabling of TLS 1.3.&lt;/p&gt;

&lt;h4 id=&quot;post-quantum-families&quot;&gt;Post quantum families&lt;/h4&gt;
&lt;p&gt;Based on submissions to NIST’s process, we grouped likely candidates into three “families” of algorithms, based on size: supersingular isogenies (SI), structured lattices (SL), and unstructured lattices (UL). Not all submissions fit into these families, of course: in some cases the public-key + ciphertext size was too large to be viable in the context of TLS, and others were based on problems that we were too unfamiliar with to be able to evaluate.&lt;/p&gt;

&lt;p&gt;As with our 2016 experiment, we expect any post-quantum algorithm to be coupled with a traditional, elliptic-curve primitive so that, if the post-quantum component is later found to be flawed, confidentiality is still protected as well as it would otherwise have been.&lt;/p&gt;

&lt;p&gt;This led to the following, rough sizes for evaluation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Supersingular isogenies (SI): 400 bytes
&lt;/li&gt;
&lt;li&gt;
Structured lattices (SL): 1 100 bytes
&lt;/li&gt;
&lt;li&gt;
Unstructured lattices (UL): 10 000 bytes
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;incompatibilities-with-unstructured-lattices&quot;&gt;Incompatibilities with unstructured lattices&lt;/h4&gt;
&lt;p&gt;Before the experiment began, in order to establish some confidence that TLS connections wouldn’t break, the top 2 500 sites from the Alexa list were probed to see whether large handshakes caused problems. Unfortunately, the 10 000-byte extension caused 21 of these sites to fail, including common sites such as &lt;code&gt;godaddy.com&lt;/code&gt;, &lt;code&gt;linkedin.com&lt;/code&gt;, and &lt;code&gt;python.org&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Oddly enough, reducing the size of the extension to 9 999 bytes reduced that number to eight, but &lt;code&gt;linkedin.com&lt;/code&gt; was still included. These remaining eight sites seem to reject ClientHello messages larger than 3 970 bytes.&lt;/p&gt;

&lt;p&gt;This indicated that widespread testing of a 10 000-byte extension was not viable. Thus the unstructured lattice configuration was replaced with a 3 300-byte “unstructured lattice stand-in” (ULS). This size was chosen to be about as large as we could reasonably test (although four sites still broke.&lt;/p&gt;

&lt;h4 id=&quot;phase-one&quot;&gt;Phase One&lt;/h4&gt;
&lt;p&gt;In February 2018, a fraction of Chrome installs (Canary and Dev channels only) were configured to enable the dummy extension in one of four sizes, with the configuration randomly selected, per install, from:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Control group: no extension sent
&lt;/li&gt;
&lt;li&gt;
Supersingular isogenies (SI): 400 bytes
&lt;/li&gt;
&lt;li&gt;
Structured lattices (SL): 1 100 bytes
&lt;/li&gt;
&lt;li&gt;
Unstructured lattice standing (ULS): 3 300 bytes
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We measured TLS handshake latency at the 50&lt;sup&gt;th&lt;/sup&gt; and 95&lt;sup&gt;th&lt;/sup&gt; percentile, split out by mobile / non-mobile and by whether the handshake was a full or resumption handshake.&lt;/p&gt;

&lt;p&gt;Given that we measured a stand-in for the UL case, we needed to extrapolate from that to an estimate for the UL latency. We modeled a linear cost of each additional byte in the handshake, 66 bytes of overhead per packet, and an MTU around 1 500 bytes. The number of packets for the UL case is the same for MTU values around 1 500, but the number of packets for the SL case is less certain: a session ticket could push the ClientHello message into two packets there. We chose to model the SL case as a single packet for the purposes of estimating the UL cost.&lt;/p&gt;

&lt;p&gt;We also ignored the possibility that the client’s initial congestion window could impact the UL case. If that were to happen, a UL client would have to wait an additional round-trip, thus our UL estimates might be optimistic.&lt;/p&gt;

&lt;p&gt;Despite the simplicity of the model, the control, SI, and SL points for the various configurations are reasonably co-linear under it and we draw the least-squares line out to 10 000 bytes to estimate the UL latency.&lt;/p&gt;

&lt;table style=&quot;text-align: center&quot;&gt;
&lt;tr&gt;
&lt;th&gt;
Configuration
&lt;/th&gt;
&lt;th colspan=&quot;3&quot;&gt;
Additional latency over control group
&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;/th&gt;
&lt;th&gt;
SI
&lt;/th&gt;
&lt;th&gt;
SL
&lt;/th&gt;
&lt;th&gt;
UL (estimated)
&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Desktop, Full, Median
&lt;/td&gt;
&lt;td&gt;
4.0%
&lt;/td&gt;
&lt;td&gt;
6.4%
&lt;/td&gt;
&lt;td&gt;
71.2%
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Desktop, Full, 95%
&lt;/td&gt;
&lt;td&gt;
4.7%
&lt;/td&gt;
&lt;td&gt;
9.6%
&lt;/td&gt;
&lt;td&gt;
117.0%
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Desktop, Resume, Median
&lt;/td&gt;
&lt;td&gt;
4.3%
&lt;/td&gt;
&lt;td&gt;
12.5%
&lt;/td&gt;
&lt;td&gt;
118.6%
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Desktop, Resume, 95%
&lt;/td&gt;
&lt;td&gt;
5.2%
&lt;/td&gt;
&lt;td&gt;
17.7%
&lt;/td&gt;
&lt;td&gt;
205.1%
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Mobile, Full, Median
&lt;/td&gt;
&lt;td&gt;
-0.2%
&lt;/td&gt;
&lt;td&gt;
3.4%
&lt;/td&gt;
&lt;td&gt;
34.3%
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Mobile, Full, 95%
&lt;/td&gt;
&lt;td&gt;
0.5%
&lt;/td&gt;
&lt;td&gt;
7.2%
&lt;/td&gt;
&lt;td&gt;
110.7%
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Mobile, Resume, Median
&lt;/td&gt;
&lt;td&gt;
0.6%
&lt;/td&gt;
&lt;td&gt;
7.2%
&lt;/td&gt;
&lt;td&gt;
66.7%
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Mobile, Resume, 95%
&lt;/td&gt;
&lt;td&gt;
4.2%
&lt;/td&gt;
&lt;td&gt;
12.5%
&lt;/td&gt;
&lt;td&gt;
149.5%
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;(The fact that one of the SI values came out implausibly negative should give some feeling for the accuracy of the results&amp;mdash;i.e. the first decimal place is probably just noise, even at the median.)&lt;/p&gt;

&lt;p&gt;As can be seen, the estimated latency overhead of unstructured lattices is notably large in TLS, even without including the effects of the initial congestion window. For this reason, we feel that UL primitives are probably not preferable for real-time TLS connections.&lt;/p&gt;

&lt;p&gt;It is also important to note that, in a real deployment, the server would also have to return a message to the client. Therefore the transmission overhead, when connecting to a compatible server, would be doubled. This phase of the experiment experiment did not take that into account at all. Which leads us to…&lt;/p&gt;

&lt;h4 id=&quot;phase-two&quot;&gt;Phase Two&lt;/h4&gt;
&lt;p&gt;In the second phase of the experiment we wished to measure the effect of actually negotiating a post-quantum primitive, i.e. when both client and server send post-quantum messages. We again added random noise of various sizes to simulate the bandwidth costs of this. Cloudflare and Google servers were augmented to echo an equal amount of random noise back to clients that included it.&lt;/p&gt;

&lt;p&gt;In this phase, latencies were only measured when the server echoed the random noise back so that the set of measured servers could be equal between control and experiment groups. This required that the control group send one byte of noise (rather than nothing).&lt;/p&gt;

&lt;p&gt;Since unstructured lattices were not our focus after the phase one results, there were only three groups in phase two: one byte (control), 400 bytes (SI), and 1100 bytes (SL).&lt;/p&gt;

&lt;p&gt;Unlike phase one, we did not break the measurements out into resumption / full handshakes this time. We did that in phase one simply because that’s what Chrome measures by default. However, it begs the question of what fraction of handshakes resume, since that value is needed to correctly weigh the two numbers. Thus, in phase two, we simply measured the overall latency, with resumption (or not) implicitly included.&lt;/p&gt;

&lt;p&gt;Here are the latency results, this time in milliseconds in order to reason about CPU costs below:&lt;/p&gt;

&lt;table style=&quot;text-align: center&quot;&gt;
&lt;tr&gt;
&lt;th&gt;
Configuration
&lt;/th&gt;
&lt;th colspan=&quot;2&quot;&gt;
Additional latency over control group (ms)
&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;/th&gt;
&lt;th&gt;
SI
&lt;/th&gt;
&lt;th&gt;
SL
&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Mobile, Median
&lt;/td&gt;
&lt;td&gt;
3.5
&lt;/td&gt;
&lt;td&gt;
9.6
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Mobile, 95%
&lt;/td&gt;
&lt;td&gt;
18.4
&lt;/td&gt;
&lt;td&gt;
159.0
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Desktop, Median
&lt;/td&gt;
&lt;td&gt;
2.6
&lt;/td&gt;
&lt;td&gt;
5.5
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Desktop, 95%
&lt;/td&gt;
&lt;td&gt;
19.2
&lt;/td&gt;
&lt;td&gt;
136.9
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;So far we’ve only talked about families of algorithms but, to analyse these results, we have to be more specific. That’s easy in the case supersingular isogenies (SI) because there is only one SI-based submission to NIST: &lt;a href=&quot;https://github.com/Microsoft/PQCrypto-SIKE&quot;&gt;SIKE&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For SIKEp503, the paper claims an encapsulation speed on a 3.4GHz Skylake of 16&amp;thinsp;619 kilocycles, or 4.9ms of work on a server. They also report on an assembly implementation for Aarch64, which makes a good example client. There the key generation + decapsulation time is 86&amp;thinsp;078 kilocycles, or 43ms on their 2GHz Cortex-A79.&lt;/p&gt;

&lt;p&gt;On the other hand, structured lattices (SL) are much faster. There are several candidates here but most have comparable speed, and it’s under a 10th of a millisecond on modern Intel chips.&lt;/p&gt;

&lt;p&gt;Therefore, if computation were included, the SI numbers above would have 48ms added to them. That happens to makes SL clearly faster at the median, although it does not close the gap at the 95% level. (The SI key-generation could be amortised across connections, at the cost of code complexity and maybe some forward security. Amortising key-generation across 16 connections results in 28ms of computation per connection, which doesn’t affect the argument.)&lt;/p&gt;

&lt;p&gt;We had previously deployed CECPQ1 (X25519 + NewHope) in TLS, which should be comparable to SL measurements, and gotten quite different &lt;a href=&quot;https://www.imperialviolet.org/2016/11/28/cecpq1.html&quot;&gt;results&lt;/a&gt;: we found a 1ms increase at the median and only 20ms at 95%. (And CECPQ1 took roughly 1 900 bytes.)&lt;/p&gt;

&lt;p&gt;On a purely technical level, CECPQ1 was based on TLS 1.2 and therefore increased the sizes of the server’s first flow and the client’s &lt;em&gt;second&lt;/em&gt; flow. It’s possible that bytes in the client’s second flow are less expensive, but much more significantly, TLS 1.2 does not do a fresh key-agreement for a resumption handshake. Therefore all the successful resumptions had no overhead with CECPQ1, but with TLS 1.3, they would. Going back to historical Chrome statistics from the time of the CECPQ1 experiment, we estimate that about 50% of connections would have been resumptions, which closes the gap.&lt;/p&gt;

&lt;p&gt;Additionally, there may be a significant difference in Chrome user populations between the experiments. CECPQ1 went to Chrome Stable (non-mobile only) while the post-quantum measurements here have been done on Dev and Canary channels. It is the case that, for all non-mobile TLS connections (completely unrelated to any post-quantum experiments), the population of Dev and Canary channel users see higher TLS latencies and the effect is larger than the SI or SL effect measured above. Thus the user population for these experiments might have had poorer internet connections than the population for CECPQ1, exaggerating the costs of extra handshake bytes.&lt;/p&gt;

&lt;p&gt;Apart from CPU time, a second major consideration is that we are not comparing like with like. Our 400-byte figure for SI maps to a NIST “category one” strength, while 1&amp;thinsp;100 bytes for SL is roughly in line with “category three”. A comparable, “category one” SL primitive comes in at more like 800 bytes, while a “category three” SI is much slower.&lt;/p&gt;

&lt;p&gt;(Although there is a &lt;a href=&quot;https://eprint.iacr.org/2018/313.pdf&quot;&gt;recent paper&lt;/a&gt; suggesting that SIKEp503 might be more like category three after all. So maybe this point is moot, but such gyrations highlight that SI is a relatively new field of study.)&lt;/p&gt;

&lt;p&gt;Lastly, and much more qualitatively, we have had many years of dealing with subtle bugs in elliptic-curve implementations. The desire for performance pushes for carefully-optimised implementations, but missed carries, or other range violations, are typically impossible for random tests to find. After many years, we are at the point where we are starting to use &lt;a href=&quot;https://people.csail.mit.edu/jgross/personal-website/papers/2018-fiat-crypto-pldi-draft.pdf&quot;&gt;formally-synthesised&lt;/a&gt; code for elliptic-curve field operations but SI would take us deeper into the same territory, likely ensuring that the pattern of ECC bugs continues into the future. (As Hamburg says in &lt;a href=&quot;https://sourceforge.net/projects/threebears/&quot;&gt;his NIST submission&lt;/a&gt;, “some cryptographers were probably hoping never to see a carry chain again”.)&lt;/p&gt;

&lt;p&gt;On the other hand, SL designs are much more like symmetric primitives, using small fields and bitwise operations. While it’s not impossible to botch, say, AES, my experience is that the defect rates in implementations of things like AES and SHA-256 is dramatically lower, and this is strong argument for SL over SI. Combining post-quantum primitives with traditional ECC is a good defense against bugs, but we should still be reticent to adopt potentially fragile constructs.&lt;/p&gt;

&lt;p&gt;(Not all SL designs have this benefit, mind you. Hamburg, quoted above, uses ℤ/(2&lt;sup&gt;3120&lt;/sup&gt; - 2&lt;sup&gt;1560&lt;/sup&gt; - 1) in ThreeBears and lattice schemes for other primitives may need operations like discrete Gaussian sampling. But it holds for a number of SL-based KEMs.)&lt;/p&gt;

&lt;p&gt;Thus the overall conclusion of these experiments is that post-quantum confidentiality in TLS should probably be based on structured lattices although there is still an open question around QUIC, for which exceeding a single packet is problematic and thus the larger size of SL is more significant.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Security Keys</title>
   <link href="http://www.imperialviolet.org/2018/03/27/webauthn.html"/>
   <updated>2018-03-27T00:00:00-04:00</updated>
   <id>http://www.imperialviolet.org/2018/03/27/webauthn</id>
   <content type="html">&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Predictions of, and calls for, the end of passwords have been ringing through the press for many years now. The first instance of this that Google can find is &lt;a href=&quot;https://www.cnet.com/news/gates-predicts-death-of-the-password/&quot;&gt;from Bill Gates in 2004&lt;/a&gt;, although I suspect it wasn’t the first.&lt;/p&gt;
&lt;p&gt;None the less, the experience of most people is that passwords remain a central, albeit frustrating, feature of their online lives.&lt;/p&gt;
&lt;p&gt;Security Keys are another attempt address this problem—initially in the form of a second authentication factor but, in the future, potentially as a complete replacement. Security Keys have gotten more traction than many other attempts to solve this problem and this post exists to explain and, to some extent, advocate for them to a technical audience.&lt;/p&gt;
&lt;p&gt;Very briefly, Security Keys are separate pieces of hardware capable of generating public/private key pairs and signing with them. By being separate, they can hopefully better protect those keys than a general purpose computer can, and they can be moved between devices to serve as a means of safely authorising multiple devices. Most current examples &lt;a href=&quot;https://www.yubico.com/products/yubikey-hardware/fido-u2f-security-key/&quot;&gt;attach via USB&lt;/a&gt;, but NFC and Bluetooth devices also exist.&lt;/p&gt;
&lt;h3 id=&quot;contrasts-with-existing-solutions&quot;&gt;Contrasts with existing solutions&lt;/h3&gt;
&lt;p&gt;Security Keys are not the first attempt at solving the problems of passwords, but they do have different properties than many of the other solutions.&lt;/p&gt;
&lt;p&gt;One common form of second factor authentication is &lt;a href=&quot;https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm&quot;&gt;TOTP&lt;/a&gt;/&lt;a href=&quot;https://en.wikipedia.org/wiki/HMAC-based_One-time_Password_Algorithm&quot;&gt;HOTP&lt;/a&gt;. This often takes the form of an app on the user’s phone (e.g. &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&amp;amp;hl=en&quot;&gt;Google Authenticator&lt;/a&gt;) which produces codes that change every minute or so. It can also take the form of a token with an LCD display to show such codes (e.g. &lt;a href=&quot;https://en.wikipedia.org/wiki/RSA_SecurID&quot;&gt;RSA SecurID&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;These codes largely solve the problem of password reuse between sites as different sites have different seed values. Thus stealing the password (and/or seed) database from one site no longer compromises accounts at other sites, as is the case with passwords.&lt;/p&gt;
&lt;p&gt;However, these codes are still phishable: the user may be tricked into entering their password and code on a fake site, which can promptly forward them to the real site and impersonate the user. The codes may also be socially engineered as they can be read over the phone etc by a confused user.&lt;/p&gt;
&lt;p&gt;Another common form of second factor authentication are SMS-delivered codes. These share all the flaws of HOTP/TOTP and add concerns around the &lt;a href=&quot;https://medium.com/@CodyBrown/how-to-lose-8k-worth-of-bitcoin-in-15-minutes-with-verizon-and-coinbase-com-ba75fb8d0bac&quot;&gt;social engineering of phone companies&lt;/a&gt; to redirect messages and, in extreme cases, manipulation of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Signalling_System_No._7&quot;&gt;SS7 network&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lastly, many security guides advocate for the use of password managers. These, if used correctly, can also solve the password reuse problem and significantly help with phishing, since passwords will not be auto-filled on the wrong site. Thus this is sound advice and, uniquely amongst the solutions discussed here, can be deployed unilaterally by users.&lt;/p&gt;
&lt;p&gt;Password managers, however, do not conveniently solve the problem of authenticating new devices, and their automated assistance is generally limited to a web context. They also change a password authentication from an (admittedly weak) verification of the &lt;em&gt;user&lt;/em&gt;, to a verification of the &lt;em&gt;device&lt;/em&gt;; an effect which has provoked hostility and counter-measures from relying parties.&lt;/p&gt;
&lt;p&gt;In light of this, Security Keys should be seen as a way to improve upon, and exceed the abilities of, password managers in a context where the relying party is cooperating and willing to make changes. Security Keys are unphishable to a greater extent than password managers because credentials are bound to a given site, plus it’s infeasible to socially engineer someone to read a binary signature over the phone. Also, like TOTP/HOTP, they use fresh credentials for each site so that no reuse is possible. Unlike password managers, they can work outside of a web context and they can serve to authenticate new devices.&lt;/p&gt;
&lt;p&gt;They aren’t magic, however. The unphishability of Security Keys depends on the extent to which the user may be mislead into compromising other aspects of their device. If the user can be tricked into installing malware, it could access the Security Key and request login signatures for arbitrary sites. Also, malware may compromise the user’s login session in a browser &lt;em&gt;after&lt;/em&gt; successfully authenticating with a Security Key. Still, that’s a heck of a lot better than the common case of people using the same password across dozens of sites.&lt;/p&gt;
&lt;h3 id=&quot;all-the-different-terms&quot;&gt;All the different terms&lt;/h3&gt;
&lt;p&gt;There is a lot of terminology specific to this topic. The first of which I’ve already used above: “relying parties”. This term refers to any entity trying to authenticate a user. When logging into a website, for example, the website is the relying party.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://fidoalliance.org&quot;&gt;FIDO Alliance&lt;/a&gt; is a group of major relying parties, secure token manufacturers, and others which defines many of the standards around Security Keys. The term that FIDO uses for Security Keys is “Universal 2&lt;sup&gt;nd&lt;/sup&gt; factor” (U2F) so you’ll often see “U2F security key” used—it’s talking about the same thing. The terms “authenticator” and “token” are also often used interchangeably to refer to these devices.&lt;/p&gt;
&lt;p&gt;At the time of writing, all Security Keys are based version one of FIDO’s “Client To Authenticator Protocol” (CTAP1). This protocol is split between documentation of the &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html&quot;&gt;core protocol&lt;/a&gt; and separate documents that describe how the core protocol is transported over &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-hid-protocol-v1.2-ps-20170411.html&quot;&gt;USB&lt;/a&gt;, &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-nfc-protocol-v1.2-ps-20170411.html&quot;&gt;NFC&lt;/a&gt;, and &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-bt-protocol-v1.2-ps-20170411.html&quot;&gt;Bluetooth&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;FIDO also defines &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-javascript-api-v1.2-ps-20170411.html&quot;&gt;a U2F Javascript API&lt;/a&gt; for websites to be able to interact with and use Security Keys. However, no browser ever implemented that API prior to a forthcoming (at the time of writing) version of Firefox.&lt;/p&gt;
&lt;p&gt;But sites have been able to use Security Keys with Google Chrome for some years because Chrome ships with a hidden, internal extension through which the U2F API can be implemented with a Javascript polyfill, which Google &lt;a href=&quot;https://github.com/google/u2f-ref-code/blob/master/u2f-gae-demo/war/js/u2f-api.js&quot;&gt;also provides&lt;/a&gt;. (Extensions for Firefox were also available prior to native support in that browser.)&lt;/p&gt;
&lt;p&gt;Thus all sites which supported Security Keys prior to 2018 used some polyfill in combination with Chrome’s internal extension, or one of the Firefox extensions, to do so.&lt;/p&gt;
&lt;p&gt;The FIDO Javascript API is not the future, however. Instead, the W3C is defining an official &lt;a href=&quot;https://github.com/w3c/webauthn&quot;&gt;Web Authentication standard&lt;/a&gt; for Security Keys, which is commonly called by its short name “webauthn”. This standard is significantly more capable (and significantly more complex) than the U2F API but, by the end of 2018, it is likely that all of Edge, Chrome, and Firefox will support it by default.&lt;/p&gt;
&lt;p&gt;The webauthn standard has been designed to work with existing (CTAP1-based) devices, but FIDO is working on an updated standard for tokens, CTAP2, which will allow them to take advantage of the new capabilities in webauthn. (The standards were co-developed so it’s equally reasonable to see it from the other direction and say that webauthn allows browsers to take advantage of the new capabilities in CTAP2.)&lt;/p&gt;
&lt;p&gt;There are no CTAP2 devices on the market yet but their major distinguishing feature will be that they can be used as a 1&lt;sup&gt;st&lt;/sup&gt; (and only) factor. I.e. they have enough internal storage that they can contain a username and so both provide an identity and authenticate it. This text will mostly skim over CTAP2 since the devices are not yet available. But developers should keep it in mind when dealing with webauthn as it explains many, otherwise superfluous, features in that standard.&lt;/p&gt;
&lt;h3 id=&quot;ctap1-basics&quot;&gt;CTAP1 Basics&lt;/h3&gt;
&lt;p&gt;Since all current Security Keys use CTAP1, and webauthn is backwards compatible with it, understanding CTAP1 is pretty helpful for understanding the space in general. Here I’ll include some Python snippets for communicating with USB CTAP1 devices to make things concrete, although I’ll skip over everything that deals with framing.&lt;/p&gt;
&lt;p&gt;CTAP1 defines two operations: creating a new key, and signing with an existing key. I’ll focus on them in turn.&lt;/p&gt;
&lt;h4 id=&quot;creating-a-new-key&quot;&gt;Creating a new key&lt;/h4&gt;
&lt;p&gt;This operation is called “registration“ in CTAP1 terminology and it takes two, 32-byte arguments: a “challenge” and an “application parameter”. From the point of view of the token these arguments are opaque byte strings, but they’re intended to be hashes and the hash function has to be SHA-256 if you want to interoperate.&lt;/p&gt;
&lt;p&gt;The challenge argument, when used with a web browser, ends up being the hash of a JSON-encoded structure that includes a random nonce from the relying party as well as other information. This nonce is intended to prove freshness: if it was signed by the newly generated key then the relying party could know that the key really was fresh and that this was the only time it had been registered. Unfortunately, CTAP1 doesn’t include any self-signature (and CTAP2 devices probably won’t either). Instead the situation is a lot more complex, which we’ll get to.&lt;/p&gt;
&lt;p&gt;The application parameter identifies a relying party. In U2F it’s a hash of the origin (e.g. SHA-256(“&lt;code&gt;https://example.com&lt;/code&gt;”)) while in webauthn it’s a hash of the domain (e.g. SHA-256(“&lt;code&gt;example.com&lt;/code&gt;”)). As we’ll see, the signing operation also takes an application parameter and the token checks that it’s the same value that was given when the key was created. A phishing site will operate on a look-alike domain, but when the browser hashes that domain, the result will be different. Thus the application parameter sent to the token will be different and the token will refuse to allow the key to be used. Thus keys are bound to specific origins (or, with webauthn, domains) and cannot be used outside of that context.&lt;/p&gt;
&lt;p&gt;Here’s some sample code that’ll shine some light on other aspects of the protocol, including the outputs from key creation:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb1&quot;&gt;&lt;pre class=&quot;sourceCode python&quot;&gt;&lt;code class=&quot;sourceCode python&quot;&gt;&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-1&quot; data-line-number=&quot;1&quot;&gt;&lt;span class=&quot;cf&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;True&lt;/span&gt;:&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-2&quot; data-line-number=&quot;2&quot;&gt;    challenge_hash &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; hashlib.sha256(&lt;span class=&quot;st&quot;&gt;&amp;#39;challenge&amp;#39;&lt;/span&gt;).digest()&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-3&quot; data-line-number=&quot;3&quot;&gt;    app_param_hash &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; hashlib.sha256(&lt;span class=&quot;st&quot;&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;).digest()&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-4&quot; data-line-number=&quot;4&quot;&gt;    status, reply &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; transact(&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;, challenge_hash &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; appid_hash)&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-5&quot; data-line-number=&quot;5&quot;&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; status &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;bn&quot;&gt;0x6985&lt;/span&gt;:&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-6&quot; data-line-number=&quot;6&quot;&gt;        time.sleep(&lt;span class=&quot;fl&quot;&gt;0.5&lt;/span&gt;)&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-7&quot; data-line-number=&quot;7&quot;&gt;        &lt;span class=&quot;cf&quot;&gt;continue&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-8&quot; data-line-number=&quot;8&quot;&gt;    &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;Public key: &amp;#39;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; reply[&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;:&lt;span class=&quot;dv&quot;&gt;66&lt;/span&gt;].encode(&lt;span class=&quot;st&quot;&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;)&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-9&quot; data-line-number=&quot;9&quot;&gt;    key_handle_length &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;ord&lt;/span&gt;(reply[&lt;span class=&quot;dv&quot;&gt;66&lt;/span&gt;])&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-10&quot; data-line-number=&quot;10&quot;&gt;    &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;Key handle: &amp;#39;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; reply[&lt;span class=&quot;dv&quot;&gt;67&lt;/span&gt;:&lt;span class=&quot;dv&quot;&gt;67&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; key_handle_length].encode(&lt;span class=&quot;st&quot;&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;)&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-11&quot; data-line-number=&quot;11&quot;&gt;    reply &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; reply[&lt;span class=&quot;dv&quot;&gt;67&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; key_handle_length:]&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-12&quot; data-line-number=&quot;12&quot;&gt;    &lt;span class=&quot;co&quot;&gt;# This is a fragile way of getting an ASN.1 length;&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-13&quot; data-line-number=&quot;13&quot;&gt;    &lt;span class=&quot;co&quot;&gt;# just to keep the code small.&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-14&quot; data-line-number=&quot;14&quot;&gt;    cert_len &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; struct.unpack(&lt;span class=&quot;st&quot;&gt;&amp;#39;&amp;gt;H&amp;#39;&lt;/span&gt;, reply[&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;:&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;])[&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;]&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-15&quot; data-line-number=&quot;15&quot;&gt;    &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;-----BEGIN CERTIFICATE-----&amp;#39;&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-16&quot; data-line-number=&quot;16&quot;&gt;    &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; reply[:&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;cert_len].encode(&lt;span class=&quot;st&quot;&gt;&amp;#39;base64&amp;#39;&lt;/span&gt;),&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-17&quot; data-line-number=&quot;17&quot;&gt;    &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;-----END CERTIFICATE-----&amp;#39;&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-18&quot; data-line-number=&quot;18&quot;&gt;    &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;Signature: &amp;#39;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; reply[&lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;cert_len:]&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb1-19&quot; data-line-number=&quot;19&quot;&gt;    &lt;span class=&quot;cf&quot;&gt;break&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(The full source &lt;a href=&quot;/binary/ctap1.py&quot;&gt;is available&lt;/a&gt; if you want to play with it, although it’ll only work on Linux.)&lt;/p&gt;
&lt;p&gt;The first thing to note is that the operation runs in a loop. CTAP1 devices require a “user presence” test before performing operations. In practice this means that they’ll have a button or capacitive sensor that you have to press. While the button/sensor isn’t triggered, operations return a specific error code and the host is expected to retry the operation after a brief delay until it succeeds.&lt;/p&gt;
&lt;p&gt;A user-presence requirement ensures that operations cannot happen without a human being physically present. This both stops silent authentication (which could be used to track people) and it stops malware from silently proxying requests to a connected token. (Although it doesn’t stop malware from exploiting a touch that the user believes is authorising a legitimate action.)&lt;/p&gt;
&lt;p&gt;Once the operation is successful, &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-response-message-success&quot;&gt;the response&lt;/a&gt; can be parsed. In the spirit of short example code everywhere, errors aren’t checked, so don’t use this code for real.&lt;/p&gt;
&lt;p&gt;Key generation, of course, produces a public key. For CTAP1 tokens, that key will always be an uncompressed, X9.62-encoded, ECDSA P-256 public key. That encoding happens to always be 65 bytes long.&lt;/p&gt;
&lt;p&gt;After that comes the key handle. This is an opaque value that the token uses to identify this key, and this evinces another important facet of CTAP1: the tokens are nearly stateless in practice.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;theory&lt;/em&gt;, the key handle could be a small identifier for a key which is stored on the device. In practice, however, the key handle is always an encrypted version of the private key itself (or a generating seed). This allows storage of the keys to be offloaded to the relying party, which is important for keeping token costs down.&lt;/p&gt;
&lt;p&gt;This also means that CTAP1 tokens cannot be used without the user entering a username. The relying party has to maintain a database of key handles, and that database has to be indexed by something. This is changing with CTAP2, but I’ll not mention that further until CTAP2 tokens are being commercially produced.&lt;/p&gt;
&lt;p&gt;Lastly, there’s the attestation certificate (just one; no chain) and a signature. As I mentioned above, the signature is sadly not from the newly created key, but from a separate attestation private key contained in the token. This’ll be covered in a later section&lt;/p&gt;
&lt;h4 id=&quot;signing-with-a-key&quot;&gt;Signing with a key&lt;/h4&gt;
&lt;p&gt;Once a key has been created, we can ask the token &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#authentication-messages&quot;&gt;to sign with it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Again, a “challenge” and “application parameter” have to be given, and they have the same meaning and format as when creating a key. The application parameter has to be identical to the value presented when the key was created otherwise the token will return an error.&lt;/p&gt;
&lt;p&gt;The code looks very similar:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb2&quot;&gt;&lt;pre class=&quot;sourceCode python&quot;&gt;&lt;code class=&quot;sourceCode python&quot;&gt;&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-1&quot; data-line-number=&quot;1&quot;&gt;&lt;span class=&quot;cf&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;True&lt;/span&gt;:&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-2&quot; data-line-number=&quot;2&quot;&gt;    challenge_hash &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; hashlib.sha256(&lt;span class=&quot;st&quot;&gt;&amp;#39;challenge&amp;#39;&lt;/span&gt;).digest()&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-3&quot; data-line-number=&quot;3&quot;&gt;    appid_hash &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; hashlib.sha256(&lt;span class=&quot;st&quot;&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;).digest()&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-4&quot; data-line-number=&quot;4&quot;&gt;    status, reply &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; transact(&lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;, challenge_hash &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; appid_hash &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-5&quot; data-line-number=&quot;5&quot;&gt;                                      &lt;span class=&quot;bu&quot;&gt;chr&lt;/span&gt;(&lt;span class=&quot;bu&quot;&gt;len&lt;/span&gt;(key_handle)) &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; key_handle)&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-6&quot; data-line-number=&quot;6&quot;&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; status &lt;span class=&quot;op&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;bn&quot;&gt;0x6985&lt;/span&gt;:&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-7&quot; data-line-number=&quot;7&quot;&gt;        time.sleep(&lt;span class=&quot;fl&quot;&gt;0.5&lt;/span&gt;)&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-8&quot; data-line-number=&quot;8&quot;&gt;        &lt;span class=&quot;cf&quot;&gt;continue&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-9&quot; data-line-number=&quot;9&quot;&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; status &lt;span class=&quot;op&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;bn&quot;&gt;0x9000&lt;/span&gt;:&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-10&quot; data-line-number=&quot;10&quot;&gt;        &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;bu&quot;&gt;hex&lt;/span&gt;(status)&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-11&quot; data-line-number=&quot;11&quot;&gt;        os.exit(&lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;)&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-12&quot; data-line-number=&quot;12&quot;&gt;    (flags, counter) &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; struct.unpack(&lt;span class=&quot;st&quot;&gt;&amp;#39;&amp;gt;BI&amp;#39;&lt;/span&gt;, reply[:&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;])&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-13&quot; data-line-number=&quot;13&quot;&gt;    &lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; flags &lt;span class=&quot;op&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;:&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-14&quot; data-line-number=&quot;14&quot;&gt;        &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;User-presence tested&amp;#39;&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-15&quot; data-line-number=&quot;15&quot;&gt;    &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;Counter: &lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;st&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;%&lt;/span&gt; counter&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-16&quot; data-line-number=&quot;16&quot;&gt;    &lt;span class=&quot;bu&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;Signature: &amp;#39;&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;+&lt;/span&gt; reply[&lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;:].encode(&lt;span class=&quot;st&quot;&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;)&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb2-17&quot; data-line-number=&quot;17&quot;&gt;    &lt;span class=&quot;cf&quot;&gt;break&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The same pattern for waiting for a button press is used: the token is polled and returns an error until the button/sensor is pressed.&lt;/p&gt;
&lt;p&gt;Three values are returned: a flag confirming that the button was pressed, a signature counter, and the signature itself—which signs over the challenge, application parameter, flags, and counter.&lt;/p&gt;
&lt;p&gt;In the web context, the challenge parameter will be the hash of a JSON structure again, and that includes a nonce from the relying party. Therefore, the relying party can be convinced that the signature has been freshly generated.&lt;/p&gt;
&lt;p&gt;The signature counter is a strictly monotonic counter and the intent is that a relying party can record the values and so notice if a private key has been duplicated, as the strictly-monotonic property will eventually be violated if multiple, independent copies of the key are used.&lt;/p&gt;
&lt;p&gt;There are numerous problems with this, however. Firstly, recall that CTAP1 tokens have very little state in order to keep costs down. Because of that, all tokens that I’m aware of have a single, global counter shared by all keys created by the device. (The only exception I’ve seen is the &lt;a href=&quot;https://bluink.ca/key&quot;&gt;Bluink key&lt;/a&gt; because it keeps state on a phone.) This means that the value and growth rate of the counter is a trackable signal that’s transmitted to all sites that the token is used to login with. For example, the token that I’m using right now has a counter of 431 and I probably use it far more often than most because I’m doing things like writing example Python code to trigger signature generation. I’m probably pretty identifiable because of that.&lt;/p&gt;
&lt;p&gt;A signature counter is also not a very effective defense, especially if it’s per-token, not per-key. Security Keys are generally used to bless long-term logins, and an attacker is likely to be able to login once with a cloned key. In fact, the login that violates the monotonicity of the counter will probably be a &lt;em&gt;legitimate&lt;/em&gt; login so relying parties that strictly enforce the requirement are likely to lock the real user out after a compromise.&lt;/p&gt;
&lt;p&gt;Since the counter is almost universally per-token, that means that it’ll commonly jump several values between logins to the same site because the token will have been used to login elsewhere in-between. That makes the counter less effective at detecting cloning. If login sessions are long-lived, then the attacker may only need to sign once and quite possibly never be detected. If an attacker is able to observe the evolution of the counter, say by having the user login to an attacker-controlled site periodically, they can avoid ever triggering a counter regression on a victim site.&lt;/p&gt;
&lt;p&gt;Finally, signature counters move the threat model from one that deals with phishing and password reuse, to one where attackers are capable of extracting key material from hardware tokens. That’s quite a change and the signature counter is not optional in the protocol.&lt;/p&gt;
&lt;h4 id=&quot;attestation&quot;&gt;Attestation&lt;/h4&gt;
&lt;p&gt;When creating a key we observed that the token returned a certificate, and a signature over the newly created key by that certificate. Here’s the certificate from the token that I happen to be using as I write this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 95815033 (0x5b60579)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = Yubico U2F Root CA Serial 457200631
        Validity
            Not Before: Aug  1 00:00:00 2014 GMT
            Not After : Sep  4 00:00:00 2050 GMT
        Subject: CN = Yubico U2F EE Serial 95815033
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:fd:b8:de:b3:a1:ed:70:eb:63:6c:06:6e:b6:00:
                    69:96:a5:f9:70:fc:b5:db:88:fc:3b:30:5d:41:e5:
                    96:6f:0c:1b:54:b8:52:fe:f0:a0:90:7e:d1:7f:3b:
                    ff:c2:9d:4d:32:1b:9c:f8:a8:4a:2c:ea:a0:38:ca:
                    bd:35:d5:98:de
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            1.3.6.1.4.1.41482.2:
                1.3.6.1.4.1.41482.1.1
    Signature Algorithm: sha256WithRSAEncryption&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clearly, it identifies the manufacturer and the unknown extension in there identifies the exact model of the key.&lt;/p&gt;
&lt;p&gt;The certificate, despite the 32-bit serial number, &lt;em&gt;doesn’t&lt;/em&gt; uniquely identify the device. The FIDO rules say that at least 100 000 other devices should share the same certificate. (Some devices mistakenly shipped with uniquely identifying attestation certifications. These will be recognised &lt;a href=&quot;https://www.chromium.org/security-keys&quot;&gt;and suppressed&lt;/a&gt; in Chrome 67.) This device happens to be a special, GitHub-branded one. I don’t know whether this attestation certificate is specific to that run of devices, but the same model of device purchased on Amazon around the same time (but unbranded) had a different certificate serial number, so maybe.&lt;/p&gt;
&lt;p&gt;But the practical upshot is that a relying party can determine, with some confidence, that a newly created key is stored in a Yubico 4&lt;sup&gt;th&lt;/sup&gt;-gen U2F device by checking the attestation certificate and signature. That fact should cause people to pause; it has weighty ramifications.&lt;/p&gt;
&lt;p&gt;Traditionally, anyone who implemented the various specifications that make up a web browser or server has been an equal participant in the web. There’s never been any permission needed to create a new browser or server and, although the specifications on the client side are now so complex that implementing them is a major effort, it’s possible to leverage existing efforts and use WebKit, Firefox, or Chromium as a base.&lt;/p&gt;
&lt;p&gt;(The DRM in &lt;a href=&quot;https://www.w3.org/TR/encrypted-media/&quot;&gt;Encrypted Media Extensions&lt;/a&gt; might be an exception, and there was an appropriately large fight over that. I’m not making any judgment about the result of that here though.)&lt;/p&gt;
&lt;p&gt;But with attestation, it’s quite possible for a site to require that you have particular hardware if you want to use webauthn. The concerns about that vary depending on the context: for an internal, corporate site to demand employees use particular hardware seems unobjectionable; a large public site raises many more concerns. There appear to be two, main ways in which this could develop in an unhealthy direction:&lt;/p&gt;
&lt;p&gt;Firstly, as we’ve experienced with User-Agent headers, sites are not always as responsive as we would like. User-Agent headers have layers upon layers of browsers spoofing other browsers—the history of browser development is written in there—all because of this. Spoofing was necessary because sites would implement workarounds or degraded experiences for some browsers but fail to update things as the browser landscape changed. In order to be viable, each new browser entrant had to spoof the identity of the currently dominant one.&lt;/p&gt;
&lt;p&gt;But attestation is not spoofable. Therefore, if sites launch webauthn support and accept attestations from the current set of token vendors, future vendors may be locked out of the market: Their devices won’t work because their attestations aren’t trusted, and they won’t be able to get sites to update because they won’t have enough market presence to matter.&lt;/p&gt;
&lt;p&gt;If things get really bad, we may see a market develop where attestation certificates are traded between companies to overcome this. The costs of that are ultimately borne by increased token prices, which users have to pay.&lt;/p&gt;
&lt;p&gt;The second concern is that, if different sites adopt different policies, users can have no confidence that a given token will work on a given site. They may be forced to have multiple tokens to span the set of sites that they use, and to remember in each case which token goes with which site. This would substantially degrade the user experience.&lt;/p&gt;
&lt;p&gt;FIDO does not dismiss these worries and their answer, for the moment, is the &lt;a href=&quot;https://fidoalliance.org/mds/&quot;&gt;metadata service&lt;/a&gt; (MDS). Essentially this is a unified root store that all sites checking attestation are supposed to use and update from. That would solve the problem of site stagnation by creating a single place for new vendors to submit their roots which would, in theory, then auto-update everywhere else. It would also help with the problem of divergent policies because it includes a FIDO-specified security-level for each type of token, which would at least reduce the variety of possible policies and make them more understandable—if used.&lt;/p&gt;
&lt;p&gt;The challenge at the moment is that major vendors are not even included in the MDS, and using the MDS properly is harder for sites than throwing together a quick hack that’ll be “good enough for now”.&lt;/p&gt;
&lt;p&gt;Thus my advice is for sites to ignore attestation if you’re serving the public. As we’ll see when we cover the webauthn API, attestation information is not even provided by default. Sites newly supporting webauthn are probably just using passwords, or maybe SMS OTP, and thus Security Keys offer a clear improvement. Worrying about whether the Security Key is a physical piece of hardware, and what certifications it has, is a distraction.&lt;/p&gt;
&lt;h3 id=&quot;webauthn&quot;&gt;webauthn&lt;/h3&gt;
&lt;p&gt;Now that we understand the underlying protocol, here’s how to actually use it. As mentioned above, there’s an older, “U2F” API but that’ll disappear in time and so it’s not covered here. Rather, the future is the &lt;a href=&quot;https://www.w3.org/TR/webauthn/&quot;&gt;W3C Web Authentication API&lt;/a&gt;, which builds on the &lt;a href=&quot;https://www.w3.org/TR/credential-management-1/&quot;&gt;Credential Management API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Right now, if you want to experiment, you can use Firefox Nightly, Chrome Canary, or Edge 14291+. In Firefox Nightly, things should be enabled by default. For Chrome Canary, run with &lt;tt&gt;–enable-features=WebAuthentication –enable-experimental-web-platform-features&lt;/tt&gt;. For Edge, I believe that you have to enable it in about:flags, but I’m just going off documentation.&lt;/p&gt;
&lt;h4 id=&quot;testing-for-support&quot;&gt;Testing for support&lt;/h4&gt;
&lt;p&gt;Before trying to use webauthn, you should use feature detection to ensure that it’s supported by a given browser:&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb4&quot;&gt;&lt;pre class=&quot;sourceCode js&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;a class=&quot;sourceLine&quot; id=&quot;cb4-1&quot; data-line-number=&quot;1&quot;&gt;&lt;span class=&quot;cf&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;op&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;va&quot;&gt;window&lt;/span&gt;.&lt;span class=&quot;at&quot;&gt;PublicKeyCredential&lt;/span&gt;) &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb4-2&quot; data-line-number=&quot;2&quot;&gt;    &lt;span class=&quot;co&quot;&gt;// webauthn is not supported.&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb4-3&quot; data-line-number=&quot;3&quot;&gt;&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id=&quot;creating-a-new-key-1&quot;&gt;Creating a new key&lt;/h4&gt;
&lt;p&gt;The following are partial snippets of Javascript for creating a key. In-between the snippets is discussion so you would need to concatenate all the snippets in this section to get a complete example.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb5&quot;&gt;&lt;pre class=&quot;sourceCode js&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;a class=&quot;sourceLine&quot; id=&quot;cb5-1&quot; data-line-number=&quot;1&quot;&gt;&lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; makePublicKey &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb5-2&quot; data-line-number=&quot;2&quot;&gt;    &lt;span class=&quot;co&quot;&gt;// rp specifies things about the &amp;quot;relying party&amp;quot;, i.e. the website.&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb5-3&quot; data-line-number=&quot;3&quot;&gt;    &lt;span class=&quot;dt&quot;&gt;rp&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb5-4&quot; data-line-number=&quot;4&quot;&gt;        &lt;span class=&quot;co&quot;&gt;// A friendly display name for the site.&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb5-5&quot; data-line-number=&quot;5&quot;&gt;        &lt;span class=&quot;dt&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;ACME Widgets&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb5-6&quot; data-line-number=&quot;6&quot;&gt;        &lt;span class=&quot;co&quot;&gt;// Optional: RP ID for the key.&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb5-7&quot; data-line-number=&quot;7&quot;&gt;        &lt;span class=&quot;dt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;www.example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb5-8&quot; data-line-number=&quot;8&quot;&gt;    &lt;span class=&quot;op&quot;&gt;},&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; field is required, but currently discarded. In the future it’s intended that CTAP2 tokens will be able to store this and so it could be used in an account chooser interface.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; field is optional and it sets the &lt;a href=&quot;https://w3c.github.io/webauthn/#rp-id&quot;&gt;relying party ID&lt;/a&gt; (RP ID) of the credential. This is the domain name associated with the key and it defaults to the domain that’s creating the key. It can only be overridden to set it within the eTLD+1 of the current domain—like a cookie.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb6&quot;&gt;&lt;pre class=&quot;sourceCode js&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;a class=&quot;sourceLine&quot; id=&quot;cb6-1&quot; data-line-number=&quot;1&quot;&gt;    user&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb6-2&quot; data-line-number=&quot;2&quot;&gt;        &lt;span class=&quot;co&quot;&gt;// id is a opaque user-id for this account.&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb6-3&quot; data-line-number=&quot;3&quot;&gt;        &lt;span class=&quot;dt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kw&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;Uint8Array&lt;/span&gt;([&lt;span class=&quot;dv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;7&lt;/span&gt;])&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb6-4&quot; data-line-number=&quot;4&quot;&gt;        &lt;span class=&quot;co&quot;&gt;// name is an account identifier. Doesn&amp;#39;t have to be an&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb6-5&quot; data-line-number=&quot;5&quot;&gt;        &lt;span class=&quot;co&quot;&gt;// email-like string, just whatever your site uses.&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb6-6&quot; data-line-number=&quot;6&quot;&gt;        &lt;span class=&quot;dt&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;jsmith@example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb6-7&quot; data-line-number=&quot;7&quot;&gt;        &lt;span class=&quot;co&quot;&gt;// displayName is a more friendly version of |name|.&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb6-8&quot; data-line-number=&quot;8&quot;&gt;        &lt;span class=&quot;dt&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;Joe Smith&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb6-9&quot; data-line-number=&quot;9&quot;&gt;    &lt;span class=&quot;op&quot;&gt;},&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All these fields are required. However, like the previous chunk, they’re currently discarded and intended for forthcoming CTAP2 tokens.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; identifies an account. A given CTAP2 token should not store two keys for the same RP ID and user ID. However, it’s possible that CTAP2 keys will allow blind enumeration of user IDs given physical possession of the token. (We have to see how that part of the CTAP2 spec is implemented in practice.) Therefore, you don’t want to store a username in the &lt;code&gt;id&lt;/code&gt; field. Instead you could do something like HMAC-SHA256(key = server-side-secret, input = username)[:16]. (Although you’ll need a reverse index in the future if you want to use CTAP2 tokens in 1&lt;sup&gt;st&lt;/sup&gt;-factor mode.)&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;displayName&lt;/code&gt; are again strings intended for a future account chooser UI that doesn’t currently exist.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb7&quot;&gt;&lt;pre class=&quot;sourceCode js&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;a class=&quot;sourceLine&quot; id=&quot;cb7-1&quot; data-line-number=&quot;1&quot;&gt;    &lt;span class=&quot;co&quot;&gt;// challenge is an ArrayBuffer containing the nonce.&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb7-2&quot; data-line-number=&quot;2&quot;&gt;    challenge&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;challenge&lt;/code&gt; field for a new key is a little complex. The webauthn spec is &lt;a href=&quot;https://w3c.github.io/webauthn/#cryptographic-challenges&quot;&gt;very clear&lt;/a&gt; that this must be a strong, server-generated nonce and, for the assertion request which we’ll get to next, that’s correct. Also, if you’re checking attestation then this challenge is your only assurance of freshness, so you’ll want it in that case too.&lt;/p&gt;
&lt;p&gt;However, as I mentioned above, it’s far from clear how well attestation will work outside of a controlled environment and I recommend that you ignore it in the general case. Given that, the utility of the challenge when creating a key is questionable. Generated U2F keys don’t sign over it and, while CTAP2 keys have the option of covering it with a self-signature, it remains to be seen whether any will actually do that.&lt;/p&gt;
&lt;p&gt;One advantage that it does bring is that it stops CSRF attacks from registering a new key. But, if you don’t have a solid, general solution to CSRF already then you have far larger security issues.&lt;/p&gt;
&lt;p&gt;Thus, since it’s easy and you’ll need it for assertions anyway, I still recommend that you generate a 16- or 32-byte nonce on the server as the spec suggests. I just thought that you should be aware that the benefit is a little fuzzier than you might imagine.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb8&quot;&gt;&lt;pre class=&quot;sourceCode js&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;a class=&quot;sourceLine&quot; id=&quot;cb8-1&quot; data-line-number=&quot;1&quot;&gt;    pubKeyCredParams&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; [&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb8-2&quot; data-line-number=&quot;2&quot;&gt;        &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;#39;public-key&amp;#39;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dt&quot;&gt;alg&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;-7&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;},&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb8-3&quot; data-line-number=&quot;3&quot;&gt;    ]&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This enumerates the types of public keys that the server can process. The &lt;code&gt;type&lt;/code&gt; field is always &lt;code&gt;public-key&lt;/code&gt; and the &lt;code&gt;alg&lt;/code&gt; comes from &lt;a href=&quot;https://www.iana.org/assignments/cose/cose.xhtml#algorithms&quot;&gt;the IANA COSE list&lt;/a&gt;. The value -7 means ECDSA with P-256, which is effectively mandatory since it’s what all U2F tokens implement. At the moment, that’s the only value that makes sense although there might be some TPM-based implementations in the future that use RSA.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb9&quot;&gt;&lt;pre class=&quot;sourceCode js&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;a class=&quot;sourceLine&quot; id=&quot;cb9-1&quot; data-line-number=&quot;1&quot;&gt;    timeout&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb9-2&quot; data-line-number=&quot;2&quot;&gt;    excludeCredentials&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; []&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb9-3&quot; data-line-number=&quot;3&quot;&gt;}&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb9-4&quot; data-line-number=&quot;4&quot;&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb9-5&quot; data-line-number=&quot;5&quot;&gt;&lt;span class=&quot;kw&quot;&gt;let&lt;/span&gt; credPromise &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;navigator&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;credentials&lt;/span&gt;.&lt;span class=&quot;at&quot;&gt;create&lt;/span&gt;(&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb9-6&quot; data-line-number=&quot;6&quot;&gt;    &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; makePublicKey&lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb9-7&quot; data-line-number=&quot;7&quot;&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;timeout&lt;/code&gt; specifies how many milliseconds to wait for the user to select a token before returning an error.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;excludeCredentials&lt;/code&gt; is something that can be ignored while you get something working, but which you’ll have to circle back and &lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-excludecredentials&quot;&gt;read the spec&lt;/a&gt; on before deploying anything real. It allows you to exclude tokens that the user has already created a key on when adding new keys.&lt;/p&gt;
&lt;p&gt;The promise will, if everything goes well, resolve to a &lt;a href=&quot;https://w3c.github.io/webauthn/#iface-pkcredential&quot;&gt;PublicKeyCredential&lt;/a&gt;, the &lt;code&gt;response&lt;/code&gt; member of which is an &lt;a href=&quot;https://w3c.github.io/webauthn/#iface-authenticatorattestationresponse&quot;&gt;AuthenticatorAttestationResponse&lt;/a&gt;. I’m not going to pointlessly rewrite all the &lt;a href=&quot;https://w3c.github.io/webauthn/#registering-a-new-credential&quot;&gt;server-side processing steps&lt;/a&gt; from the spec here but I will note a couple of things:&lt;/p&gt;
&lt;p&gt;Firstly, if you don’t know what token-binding is, that’s fine: ignore it. Same goes for extensions unless you previously supported the U2F API, in which case see the section below. I also suggest that you ignore the parts dealing with attestation (see above), which eliminates 95% of the complexity. Lastly, while I recommend following the remaining steps, see the bit above about the &lt;code&gt;challenge&lt;/code&gt; parameter and don’t erroneously believe that checking, say, the &lt;code&gt;origin&lt;/code&gt; member of the JSON is more meaningful than it is.&lt;/p&gt;
&lt;p&gt;I’ll also mention something about all the different formats in play here: In order to process webauthn, you’ll end up dealing with JSON, ASN.1, bespoke binary formats, and CBOR. You may not have even heard of the last of those but &lt;a href=&quot;https://tools.ietf.org/html/rfc7049&quot;&gt;CBOR&lt;/a&gt; is yet another serialisation format, joining Protocol Buffers, Msgpack, Thrift, Cap’n Proto, JSON, ASN.1, Avro, BSON, …. Whatever you might think of the IETF defining another format rather than using any of the numerous existing ones, you will have to deal with it to support webauthn, and you’ll have to deal with &lt;a href=&quot;https://tools.ietf.org/html/rfc8152&quot;&gt;COSE&lt;/a&gt;, the CBOR translation of &lt;a href=&quot;https://datatracker.ietf.org/wg/jose/documents/&quot;&gt;JOSE&lt;/a&gt;/&lt;a href=&quot;https://jwt.io/&quot;&gt;JWT&lt;/a&gt;. You don’t have to support tags or indefinite lengths in CBOR though because the &lt;a href=&quot;https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#message-encoding&quot;&gt;CTAP2 canonicalisation format&lt;/a&gt; forbids them.&lt;/p&gt;
&lt;p&gt;The problem is that there’s going to be a lot of people having to implement converters from COSE key format to something that their crypto library accepts. Maybe I should start a GitHub repo of sample code for that in various libraries. But, short of that, here’s a quick reference to help you navigate all the different formats in play:&lt;/p&gt;
&lt;h5 id=&quot;cose-key&quot;&gt;COSE Key&lt;/h5&gt;
&lt;p&gt;&lt;em&gt;Used in&lt;/em&gt;: the public key in the &lt;a href=&quot;https://w3c.github.io/webauthn/#attested-credential-data&quot;&gt;attested credential data&lt;/a&gt; when creating a key. You have to parse this because you need the public key in order to check assertions.&lt;br /&gt;
&lt;em&gt;Format&lt;/em&gt;: a CBOR map, defined &lt;a href=&quot;https://tools.ietf.org/html/rfc8152#section-7&quot;&gt;here&lt;/a&gt;. However, you’ll struggle to figure out, concretely, what the keys in that map are from the RFC so, for reference, if you’re decoding a P-256 key you should expect these entries in the map: 1 (key type) = 2 (elliptic curve, x&amp;amp;y), 3 (algorithm) = -7 (ECDSA with SHA-256), -1 (curve) = 1 (P-256), and then x and y coordinates are 32-byte values with keys -2 and -3, respectively.&lt;br /&gt;
&lt;em&gt;How to recognise&lt;/em&gt;: the first nibble is 0xa, for a small CBOR map.&lt;/p&gt;
&lt;h5 id=&quot;x9.62-key&quot;&gt;X9.62 key&lt;/h5&gt;
&lt;p&gt;&lt;em&gt;Used in&lt;/em&gt;: lots of things, this is the standard format for EC public keys. Contained within the SPKI format, which is used by Web Crypto and X.509.&lt;br /&gt;
&lt;em&gt;Format&lt;/em&gt;: a type byte (0x04 for standard, uncompressed keys), followed by x and y values.&lt;br /&gt;
&lt;em&gt;How to recognise&lt;/em&gt;: for P-256, it’s 65 bytes long and start with 0x04. (There’s also a compressed version of X9.62 but it’s exceedingly rare.)&lt;/p&gt;
&lt;h5 id=&quot;spki&quot;&gt;SPKI&lt;/h5&gt;
&lt;p&gt;&lt;em&gt;Used in&lt;/em&gt;: X.509 and Web Crypto.&lt;br /&gt;
&lt;em&gt;Format&lt;/em&gt;: an ASN.1 structure called &lt;a href=&quot;https://tools.ietf.org/html/rfc5280#section-4.1&quot;&gt;SubjectPublicKeyInfo&lt;/a&gt;: an algorithm identifier followed by a lump of bytes in an algorithm-specific format, which is X9.62 for elliptic-curve keys.&lt;br /&gt;
&lt;em&gt;How to recognise&lt;/em&gt;: starts with 0x30.&lt;/p&gt;
&lt;h5 id=&quot;asn.1-signatures&quot;&gt;ASN.1 signatures&lt;/h5&gt;
&lt;p&gt;&lt;em&gt;Used in&lt;/em&gt;: nearly everything that deals with ECDSA signatures.&lt;br /&gt;
&lt;em&gt;Format&lt;/em&gt;: an ASN.1 SEQUENCE containing two INTEGER values for ECDSA’s &lt;em&gt;r&lt;/em&gt; and &lt;em&gt;s&lt;/em&gt; values.&lt;br /&gt;
&lt;em&gt;How to recognise&lt;/em&gt;: starts with 0x30 and you’re expecting a signature, not a key.&lt;/p&gt;
&lt;h5 id=&quot;raw-signatures&quot;&gt;“Raw” signatures&lt;/h5&gt;
&lt;p&gt;&lt;em&gt;Used in&lt;/em&gt;: Web Crypto.&lt;br /&gt;
&lt;em&gt;Format&lt;/em&gt;: a pair of 32-byte values (for P-256).&lt;br /&gt;
&lt;em&gt;How to recognise&lt;/em&gt;: 64 bytes long.&lt;/p&gt;
&lt;h4 id=&quot;getting-assertions&quot;&gt;Getting assertions&lt;/h4&gt;
&lt;p&gt;Once you have one (or more) keys registered for a user you can challenge them for a signature. Typically this is done at login time although CTAP2 envisions &lt;em&gt;user verifying&lt;/em&gt; tokens that take a fingerprint or PIN number, so signatures from those devices could replace reauthentication requests. (I.e. those times when a site asks you to re-enter your password before showing particularly sensitive information.)&lt;/p&gt;
&lt;p&gt;When getting an assertion, the &lt;em&gt;challenge&lt;/em&gt; (i.e. nonce) really must be securely generated at the server—there’s none of the equivocation as with generation.&lt;/p&gt;
&lt;div class=&quot;sourceCode&quot; id=&quot;cb10&quot;&gt;&lt;pre class=&quot;sourceCode js&quot;&gt;&lt;code class=&quot;sourceCode javascript&quot;&gt;&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-1&quot; data-line-number=&quot;1&quot;&gt;  &lt;span class=&quot;kw&quot;&gt;var&lt;/span&gt; authPromise &lt;span class=&quot;op&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;navigator&lt;/span&gt;.&lt;span class=&quot;va&quot;&gt;credentials&lt;/span&gt;.&lt;span class=&quot;at&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;dt&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-2&quot; data-line-number=&quot;2&quot;&gt;    // A &lt;span class=&quot;dv&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt; or &lt;span class=&quot;dv&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;byte&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; server&lt;span class=&quot;op&quot;&gt;-&lt;/span&gt;generated&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;nonce&lt;/span&gt;.&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-3&quot; data-line-number=&quot;3&quot;&gt;    challenge&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-4&quot; data-line-number=&quot;4&quot;&gt;    // The number of milliseconds before timing &lt;span class=&quot;va&quot;&gt;out&lt;/span&gt;.&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-5&quot; data-line-number=&quot;5&quot;&gt;    &lt;span class=&quot;dt&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dv&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-6&quot; data-line-number=&quot;6&quot;&gt;    // &lt;span class=&quot;dt&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; the relying party &lt;span class=&quot;va&quot;&gt;ID&lt;/span&gt;. &lt;span class=&quot;at&quot;&gt;Defaults&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;at&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;domain&lt;/span&gt;.&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-7&quot; data-line-number=&quot;7&quot;&gt;    &lt;span class=&quot;dt&quot;&gt;rpId&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;va&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;at&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-8&quot; data-line-number=&quot;8&quot;&gt;    // A list of credentialIDs of registered &lt;span class=&quot;va&quot;&gt;keys&lt;/span&gt;.&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-9&quot; data-line-number=&quot;9&quot;&gt;    &lt;span class=&quot;dt&quot;&gt;allowCredentials&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; [&lt;span class=&quot;op&quot;&gt;{&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-10&quot; data-line-number=&quot;10&quot;&gt;      &lt;span class=&quot;dt&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;st&quot;&gt;&amp;quot;public-key&amp;quot;&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-11&quot; data-line-number=&quot;11&quot;&gt;      &lt;span class=&quot;dt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;op&quot;&gt;:&lt;/span&gt; credentialID&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-12&quot; data-line-number=&quot;12&quot;&gt;    &lt;span class=&quot;op&quot;&gt;}&lt;/span&gt;]&lt;span class=&quot;op&quot;&gt;,&lt;/span&gt;&lt;/a&gt;
&lt;a class=&quot;sourceLine&quot; id=&quot;cb10-13&quot; data-line-number=&quot;13&quot;&gt;  &lt;span class=&quot;op&quot;&gt;}}&lt;/span&gt;)&lt;span class=&quot;op&quot;&gt;;&lt;/span&gt;&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;credentialID&lt;/code&gt; values are those extracted from the &lt;a href=&quot;https://w3c.github.io/webauthn/#sec-attested-credential-data&quot;&gt;attested credential data&lt;/a&gt; from the registration.&lt;/p&gt;
&lt;p&gt;Again, there’s no need for me to reiterate the &lt;a href=&quot;https://w3c.github.io/webauthn/#verifying-assertion&quot;&gt;processing steps&lt;/a&gt; already enumerated in the spec except to repeat that you can ignore token-binding if you don’t know what it is, and to reference the comments above about signature counters. If you implement the signature counter check, you should think through how the user will experience various scenarios and ensure that you’re monitoring metrics for the number of counter failures observed. (I don’t think we know, in practice, how often counter writes will be lost, or counters will be corrupted.)&lt;/p&gt;
&lt;h4 id=&quot;supporting-keys-created-with-the-u2f-api&quot;&gt;Supporting keys created with the U2F API&lt;/h4&gt;
&lt;p&gt;This is just for the handful of sites that supported Security Keys using the older, U2F API. If you have keys that were registered with that API then they aren’t immediately going to work with webauthn because the AppID from U2F is a URL, but the relying party ID in webauthn is just a domain. Thus the same origin is considered to be a different relying party when using U2F and webauthn and the keys won’t be accepted. (Just the same as if you tried to use a credential ID from a different site.)&lt;/p&gt;
&lt;p&gt;However, there is a solution to this: in the &lt;code&gt;publicKey&lt;/code&gt; argument of the &lt;code&gt;get&lt;/code&gt; call add an &lt;a href=&quot;https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-extensions&quot;&gt;extensions&lt;/a&gt; field containing a dict with a key &lt;code&gt;appid&lt;/code&gt; whose value is the AppID of your U2F keys. This can be done uniformly for all keys if you wish since both the relying party ID and AppID will be tried when this is asserted. With this in place, keys registered with U2F should work with webauthn.&lt;/p&gt;
&lt;p&gt;There is no way to create a U2F key with webauthn however. So if you rollout webauthn support, have users create keys with webauthn, and have to roll it back for some reason, those new keys will not work with the U2F API. So complete the transition to webauthn of your login process first, then transition registration.&lt;/p&gt;
&lt;h3 id=&quot;concluding-remarks&quot;&gt;Concluding remarks&lt;/h3&gt;
&lt;p&gt;It’s exciting to see webauthn support coming to most browsers this year. I get to use Security Keys with about the same number of sites as I use SMS OTP with, and I use Security Keys anywhere I can. While I, like everyone technical, &lt;em&gt;assumes&lt;/em&gt; that I’m less likely to get phished than most, I’m still human. So I hope that wide-spread support for webauthn encourages more sites to support Security Keys.&lt;/p&gt;
&lt;p&gt;Challenges remain, though. Probably the most obvious is that NFC is the ideal interface for mobile devices, but it doesn’t work with iOS. Bluetooth works for both Android and iOS, but requires a battery and isn’t as frictionless.&lt;/p&gt;
&lt;p&gt;Security keys will probably remain the domain of the more security conscious in the short-term since, with CTAP1, they can only be an additional authentication step. But I hope to see CTAP2 tokens generally available this year with fingerprint readers or PIN support. It might be that, in a few years time, a significant number of people have a passwordless experience with at least one site that they use regularly. That’ll be exciting.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>TLS 1.3 and Proxies</title>
   <link href="http://www.imperialviolet.org/2018/03/10/tls13.html"/>
   <updated>2018-03-10T00:00:00-05:00</updated>
   <id>http://www.imperialviolet.org/2018/03/10/tls13</id>
   <content type="html">&lt;p&gt;I'll generally ignore the internet froth in a given week as much as possible, but when Her Majesty's Government starts &lt;a href=&quot;https://www.ncsc.gov.uk/blog-post/tls-13-better-individuals-harder-enterprises&quot;&gt;repeating misunderstandings about TLS 1.3&lt;/a&gt; it is necessary to write something, if only to have a pointer ready for when people start citing it as evidence.&lt;/p&gt;

&lt;p&gt;The first misunderstanding in the piece is the claim that it's possible for man-in-the-middle proxies to selectively proxy TLS 1.2 connections, but not TLS 1.3 connections because the latter encrypts certificates.&lt;/p&gt;

&lt;p&gt;The TLS 1.2 proxy behaviour that's presumed here is the following: the proxy forwards the client's ClientHello message to the server and inspects the resulting ServerHello and certificates. Based on the name in the certificate, the proxy may &amp;ldquo;drop out&amp;rdquo; of the connection (i.e. allow the client and server to communicate directly) or may choose to interpose itself, answering the client with an alternative ServerHello and the server with an alternative ClientKeyExchange, negotiating different encrypted sessions with each and forwarding so that it can see the plaintext of the connection. In order to satisfy the client in this case the client must trust the proxy, but that's taken care of in the enterprise setting by installing a root CA on the client. (Or, &lt;a href=&quot;https://www.eff.org/deeplinks/2011/05/syrian-man-middle-against-facebook&quot;&gt;in Syria&lt;/a&gt;, by hoping that users click through the the certificate error.)&lt;/p&gt;

&lt;p&gt;While there do exist products that attempt to do this, they break repeatedly because it's a fundamentally flawed design: by forwarding the ClientHello to the server, the proxy has committed to supporting every feature that the client advertises because, if the server selects a given feature, it's too late for the proxy to change its mind. Therefore, with every new cipher suite, new curve, and new extension introduced, a proxy that does this finds that it cannot understand the connection that it's trying to interpose.&lt;/p&gt;

&lt;p&gt;One option that some proxies take is to try and heuristically detect when it can't support a connection and fail open. However, if you believe that your proxy is a strong defense against something then failing open is a bit of problem.&lt;/p&gt;

&lt;p&gt;Thus another avenue that some proxies have tried is to use the same heuristics to detect unsupported connections, discard the incomplete, outgoing connection, and start another by sending a ClientHello that only includes features that the proxy supports. That's unfortunate for the server because it doubles its handshaking cost, but gives the proxy a usable connection.&lt;/p&gt;

&lt;p&gt;However, both those tricks only slow down the rate at which customers lurch from outage to outage. The heuristics are necessarily imprecise because TLS extensions can change anything about a connection after the ClientHello and some additions to TLS have memorably broken them, leading to confused proxies cutting enterprises off from the internet.&lt;/p&gt;

&lt;p&gt;So the idea that selective proxying based on the server certificate ever functioned is false. A proxy can, with all versions of TLS, examine a ClientHello and decide to proxy the connection or not but, if it does so, it must craft a fresh ClientHello to send to the server containing only features that it supports. Making assumptions about any TLS message after a ClientHello that you didn't craft is invalid. Since, in practice, this has not been as obvious as the designers of TLS had imagined, the 1.3 draft &lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-tls-tls13-26#section-9.3&quot;&gt;has a section&lt;/a&gt; laying out these requirements.&lt;/p&gt;

&lt;p&gt;Sadly, it's precisely this sort of proxy misbehaviour that has delayed TLS 1.3 for over a year while my colleagues (David Benjamin and Steven Valdez) repeatedly deployed experiments and measured success rates of different serialisations. In the end we found that making TLS 1.3 &lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-tls-tls13-26#appendix-D.4&quot;&gt;look like a TLS 1.2 resumption&lt;/a&gt; solved a huge number of problems, suggesting that many proxies blindly pass through such connections. (Which should, again, make one wonder about what security properties they're providing.)&lt;/p&gt;

&lt;p&gt;But, given all that, you might ponder why we bothered encrypting certificates? Partly it's one component of an effort to make browsing more private but, more concretely, it's because anything not encrypted suffers these problems. TLS 1.3 was difficult to deploy because TLS's handshake is, perforce, exposed to the network. The idea that we should make TLS a little more efficient by &lt;i&gt;compressing&lt;/i&gt; certificates has been bouncing around for many years. But it's only with TLS 1.3 that we might &lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-tls-certificate-compression-02&quot;&gt;make it happen&lt;/a&gt; because everyone expected to hit another swamp of proxy issues if we tried it without encrypting certificates first.&lt;/p&gt;

&lt;p&gt;It's also worth examining the assumption behind waiting for the server certificate before making an interception decision: that the client might be malicious and attempt to fool the proxy but (to quote the article) the certificate is &amp;ldquo;tightly bound to the server we’re actually interacting with&amp;rdquo;. The problem here is that a certificate for any given site, and a valid signature over a ServerKeyExchange from that certificate, is easily available: just connect to the server and it'll send it to you. Therefore if you're worried about malware, how is it that the malware C&amp;amp;C server won't just reply with a certificate for a reputable site? The malware client, after all, can be crafted to compensate for any such trickery. Unless the proxy is interposing and performing the cryptographic checks, then the server certificate isn't tightly bound to anything at all and the whole reason for the design seems flawed.&lt;/p&gt;

&lt;p&gt;On that subject, I'll briefly mention the fact that HTTPS proxies &lt;a href=&quot;https://jhalderm.com/pub/papers/interception-ndss17.pdf&quot;&gt;aren't always so great at performing cryptographic checks&lt;/a&gt;. (We recently notified a major proxy vendor that their product didn't appear to validate certificates at all. We were informed that they &lt;i&gt;can&lt;/i&gt; validate certificates, it's just disabled by default. It's unclear what fraction of their customers are aware of that.)&lt;/p&gt;

&lt;p&gt;Onto the second claim of the article: that TLS 1.3 is incompatible with PCI-DSS (credit card standards) and HIPAA (US healthcare regulation). No reasoning is given for the claim, so let's take a look:&lt;/p&gt;

&lt;p&gt;Many PCI-DSS compliant systems use TLS 1.2, primarily stemming from &lt;a href=&quot;https://www.pcisecuritystandards.org/document_library?category=pcidss&amp;document=pci_dss&quot;&gt;requirement 4.1&lt;/a&gt;: &amp;ldquo;use strong cryptography and security protocols to safeguard sensitive cardholder data during transmission over open, public networks, including a) only trusted keys and certificates are accepted, b) the protocol in use only supports secure versions or configurations, and c) the encryption strength is appropriate for the encryption methodology in use&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;As you can see, the PCI-DSS requirements are general enough to adapt to new versions of TLS and, if TLS 1.2 is sufficient, then TLS 1.3 is better. (Even those misunderstanding aspects of TLS 1.3 are saying it's stronger than 1.2.)&lt;/p&gt;

&lt;p&gt;HIPAA is likewise, &lt;a href=&quot;https://www.law.cornell.edu/cfr/text/45/164.312&quot;&gt;requiring&lt;/a&gt; that one must &amp;ldquo;implement technical security measures to guard against unauthorized access to electronic protected health information that is being transmitted over an electronic communications network&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;TLS 1.3 is enabled in Chrome 65, which is rolling out now. It is a major improvement in TLS and lets us eliminate &lt;a href=&quot;https://jhalderm.com/pub/papers/forward-secrecy-imc16.pdf&quot;&gt;session-ticket encryption keys&lt;/a&gt; as a mass-decryption threat, which both PCI-DSS- and HIPAA-compliance experts should take great interest in. It does not require special measures by proxies&amp;mdash;they need only implement TLS 1.2 correctly.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Testing Security Keys</title>
   <link href="http://www.imperialviolet.org/2017/10/08/securitykeytest.html"/>
   <updated>2017-10-08T00:00:00-04:00</updated>
   <id>http://www.imperialviolet.org/2017/10/08/securitykeytest</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.imperialviolet.org/2017/08/13/securitykeys.html&quot;&gt;Last time&lt;/a&gt; I reviewed various security keys at a fairly superficial level: basic function, physical characteristics etc. This post considers lower-level behaviour.&lt;/p&gt;

&lt;p&gt;Security Keys implement the FIDO &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html&quot;&gt;U2F spec&lt;/a&gt;, which borrows a lot from ISO 7816-4. Each possible transport (i.e. USB, NFC, or Bluetooth) has its own spec for how to encapsulate the U2F messages over that transport (e.g. &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-hid-protocol-v1.2-ps-20170411.html&quot;&gt;here's the USB one&lt;/a&gt;). FIDO is working on much more complex (and more capable) second versions of these specs, but currently all security keys implement the basic ones.&lt;/p&gt;

&lt;p&gt;In essence, the U2F spec only contains three functions: Register, Authenticate, and Check. Register creates a new key-pair. Authenticate signs with an existing key-pair, after the user confirms physical presence, and Check confirms whether or not a key-pair is known to a security key.&lt;/p&gt;

&lt;p&gt;In more detail, Register takes a 32-byte challenge and a 32-byte appID. These are intended to be SHA-256 hashes, but are opaque and can be anything. The challenge acts as a nonce, while the appID is bound to the resulting key and represents the context of the key. For web browsers, the appID is the hash of a URL in the origin of the login page.&lt;/p&gt;

&lt;p&gt;Register returns a P-256 public key, an opaque key handle, the security key's batch certificate, and a signature, by the public key in the certificate, of the challenge, appID, key handle, and public key. Since the security keys are small devices with limited storage, it's universally the case in the ones that I've looked at that the key handle is actually an encrypted private key, i.e. the token offloads storage of private keys. However, in theory, the key handle could just be an integer that indexes storage within the token.&lt;/p&gt;

&lt;p&gt;Authenticate takes a challenge, an appID, and a key handle, verifies that the appID matches the value given to Register, and returns a signature, from the public key associated with that key handle, over the challenge and appID.&lt;/p&gt;

&lt;p&gt;Check takes a key handle and an appID and returns a positive result if the key handle came from this security key and the appID matches.&lt;/p&gt;

&lt;p&gt;Given that, there are a number of properties that should hold. Some of the most critical:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;The key handle should be encrypted; i.e. we shouldn't be able to find an ECDSA private key in there.&lt;/li&gt;
	&lt;li&gt;A key handle from one security key should not work with another, even of the same type.&lt;/li&gt;
	&lt;li&gt;If a security key is asked to generate hundreds of key-pairs, they should all be distinct.&lt;/li&gt;
	&lt;li&gt;All the signatures should have unique nonces, otherwise you have the &lt;a href=&quot;https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Security&quot;&gt;PlayStation bug&lt;/a&gt; and can extract private keys.&lt;/li&gt;
	&lt;li&gt;The appID should actually be checked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But there are a number of other things that would be nice to test:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Does the key handle have patterns? Ideally it would be indistinguishable from random to outside observers.&lt;/li&gt;
	&lt;li&gt;Is the key handle mutable? Really the whole thing should be authenticated.&lt;/li&gt;
	&lt;li&gt;Are the signatures correctly encoded? It's a very simple structure, but it's ASN.1 so there are corner-cases.&lt;/li&gt;
	&lt;li&gt;The USB protocol transmits 64-byte packets, the padding bytes at the end should all be zero, not random bits of memory. Are they?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So given all those desirable properties, how do various security keys manage?&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Yubico&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Easy one first: I can find no flaws in Yubico's U2F Security Key.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;VASCO SecureClick&lt;/b&gt;&lt;/p&gt;

&lt;img style=&quot;float: left; margin-right: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkJCQkLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwv/wQARCAEMAZADABEAAREAAhEA/8QAswAAAQUBAQAAAAAAAAAAAAAAAgABAwQFBgcBAQEAAwEBAAAAAAAAAAAAAAABAgMEBQYQAAEDAgIFBgkGCwcCBwEAAAEAAgMEERIhBTFBUWETIjJScfAGFCNCYoGRobEzcoKywdEVJDRDU2NzkqLC4VSDk7PS4vF0wxYlRJSjtMXyEQEAAgECBAUDAgYCAwEAAAAAAQIDERIEEyExIjJBUWEUcYFCUgUjM2Kx0aHBQ1OR8P/aAAwDAAABEQIRAD8A9AOpa2SRo1e8IDOpAA4IDBNwNnfMoHKINpACKdEMVQ6ikUQ9skU1kQginRDXKKdA6BkQSoayikgZAlQkDoBRCRToEiEgFFOoDQMSiEgQCKdAyBWQJAgiCRSIsb3QOgJASKSBICQZOpVikANrnvkoHHxRSACAigcb0D2QOgex1oHQJASBIBQGEDWQCgcKhIh0DqKZAyoSIZFOiEgSKSBroEohKhKKdAkDnUga6B0CQOgFA4QGgFAw7SgkG5ASKSISBkGfa6Sgwge3q76kDgXRR2sUCtfJAVkCQIIhyEUNkBIEgZASBIGIQJAJKIdUOikoGVCRDIEiilpK18Qkp3Rh4dfk5QbStt0ceuMnY63asToqxVbcfIzMdTVH6KXzv2b+jI35vsVFqyoFEJAyKZA6gJAsiEAoHCAkDoGQNmgIIpIh0BIHRTlEPZAkFCyB0BIE0IJLIFZA90DoBAQGgZAyBIEgSB0BIBQBZVDoHRSUDKhIEgtUsHKOxeY33+ioNa23YsUVammpqtvJzxNkZv8AOaesx3Sb9FRWJJR11F8kXVtN1HflUTfRd+eVDwVMFQCY3asnMcMMjD6bDzgshKqGQAgSB7ohkU91AggJAkCJQNi2IDQMUDoo0CRC1oogiGuiqZ7hEFkgfYgYoJGnJAWSBkDoHQJAkAoHCBIEgSBIEqBRDoH1IpIGRDIExr5HYWDP7O/2KK2IHRkYGZYBZzXCzwb7Rx62risddRM/qhSwbmt2rFTh7d4VRn1mi6ap8pzoajzZ4uZJ9LrqjHldV0f5YzlIf7XA3m/30XSjVVLy0WDlcbOSwl/KYuZhHnYlkjCovCbRFbK6GKfBJiLWcs3k+V9KLrfWWSNzNQEgbggVlFEgdAigZAwte6CS6BIGBRRlEK5RSBzRBIEgrFASAkD4UDhqB0CsgdAKBIHOpAO1AaBIBQOgSoZEDtQEgZAropkDZkgDMk2AG2+oBBrxQGJmEW5R/SO7K9geAGrtKwtr29ZI/wCIGMMJ52rU1+sAenldufnZrHyqkxkWyLha5c3OwJy1ZkHbb1BVicNY7biRdwXRi2WXZ7VjMLFvc7HGyAjYjeDsRHkHhtWUsEzqCgLoi8f+YNidaJ3nMiwdHlP0y2Y0s85c1p2f04jj2LcwdHovwo0lQ4Y3uNZTjLk5XeVY39XNb+F+Jqm1dXo+jNOaP0k38XltLbnU8lmTN+j549KPEsVa+d1FPcIpIC2KB0DIGQOEBIGQGboEilbNAaIYlBGQEQrBFEEBIHQDtQGgEoBQJAaBEIBQJAyB0DqhrohIBQJAKKYojRoIo3NM2JrzdzRhOLC5p52L0vR81Bohutx1rEBbFe+Q+zv6lgoBK1pIYy++2XwBTcu0AkY5xAPJyfwuN9TtV03CcON8LhZ1strXdiqGazCPWoOf8JNOM0TRl7beNTYmUrPS86V/oRIPA5pHyvdI9xe97nOe5xJc5zjdziTc3O8rpa0CoSIry1ZgwvYTyjXcwtPOxf7VFej+CPhc6veKCuIFVbyE36cNHQf+t3O8/wCesWT0FYqdFGgbaoCQIoFdAggRQEHZcUD3QP60UmlA6CO39UQ6AkBBAkCsgdAyASECCAkAuOVkAhUGFA9kDIGVQyKZEJAkUCAXORHHVT6rRla+oopTByzuUc3N9PP1mzRb/wBZ8osVdZorwro6wsgqx4lVam43fi837Gb/ALUmF6o6ywKrEOHLLJYqozU7Wsv52LitbNM0yNs/CH3aMX6Qdl+kPR+ssmKCsr4aaGWpe5nIwML5b3D+DB+sd5rHdJyg8F07piXSFVLVTHA3oxx/oYc8Ef8AM7010Uq1y5Xxk35R12xDottz5Ds/49qoQqSLl4F3DmRttfWOcTuttNhuuMy1DPldhu44TrsPNbxvnc7sk1NGXJKXOv7B32/aoOi8GNH1FRpGndCcDo5Gy4/0bWc7H9yivfuUasWQwgPJFCgQUBEhA2e9UOgbNAJUEo1XQDfNBJdFEiAugTc9eSA0DIHCB0DIEgFA6B0EZQIBUGoEgZUMiGQIIEgYlFRElBVkcUGDpODxhtnX5vRzzCg5GaKWK7Xt5SI68rj6Q38R2qGre0P4T11BhZidWUn6CV/l4v8Ap5v+1Kg9N0ZpjR+ko8dLLzm/KQv5k0X7SNZsWi5oWKmWseP+GGnvHJvE4H/itO/Nzfz87b4n/s4vzfpLZiolnmtUHPszZe5/rwHSP3rcwUHZEvte3Njae+3pO7becsVEG8m3lH5yOF8/j/pG7j0aqjNKTt7e/BQDTxOkeMttgg9O0JH4kwW+UfYyH+XvtWKu4paovsg143qKsDiikgSgFA4Koe6gG6oe6gIZ5ICtZFJAQKgDJVBICQI5IECga6AkCQJAyB0CVCUDoGVAkhECinQLJEMgElABF0ED28EFGWJBk1FHryUVzlVo4tOKPm5/RQUGTSxSteHyU9SzoTRuwv7MX5xm9jlB3eivDd0eGHS7ObqbXwt5n9/H+b+eqjR8KfCGGGkENFM2SWrj+VicPJU/X+fJ0I1iPG3uxE7tg3W2X2/auhrVJBe9hc5D1X1cL7UFV8bcWdsMebjsd1v33/wLFkzKifG45oIvF3OAIIJJIw53yOfAZoOm0NRc0TOGQ6AO/a7PcdXG+5SVdlTRHJQdPRxEAdiDZiaoq2inQJA3BQLWgSodAyAwLKB0CRTnVkgFEOgIFALrlAkBBASBIEgVkDoHKAc1QygVlQBCISKSIZA6ASqgVFC5VELmIqs+PggzZqcblBiVdAx4PNQc9PFUUwdhaZmYTzfOU0GLBWQPYWM5rr3ex3NcHbctw2cFsYgcc1URE8fiqjLqqjC10TfOdid/p+t7VFZDjmorotD0vKlQdtBDqACiuhpafVkg6CGP4KKvMAsgNASgZFMge/D1oFdA9wgLJA6B0D3CBII1Q4KgdAgUB2RCVUrqB0BIh0U2aB1QJRCQJAN0CKAED5IGVQyBIBQCqIi1QVZGIKUkKKy6imbuUHk+mWmKumbLC6IYvJSN+ss2KrHWSMHlPKM/SN2fPGu6IKatZbmlUY73lxJO1RU1LA6WQAC+Y799iiPRKCjbDGGCxcc3kbTbUOA1BRk6Skp7kGyDo4IVBosYiplArIEgSB7hA21AkUtiA2oDQMgSB0EJugdgN+CCQ5IhCyKNAkCw9/sQGEBoEgSByFUAikgEoBRCQAgSoRRAoIJqmngGKaVkY9N3wCzrSzC2SlFNumtFvOEVcd+Ie36zcK2fT5v2NX1XD/8AsXg5rgHNcHNIyc0gj2rU3koqNyCq/aoKMrUHPaU0fT1bC2WMfOQebV+hailcXwXkj/iVRhFrXXywPGzzf6KoiDXYsNs7oO10NQBjBK4Zno/6u+xRXX00WYUV01JDw72UGxGxBYCinRDoGw3UDKhWRRZIGQMM0BC6KIoCCBkA7dfxQAgIIH7/APKB0BBAYQEgJAiUHJaY8K4dHvdFHBJUSN6WYYxp+dhdi/dUFCh8MJ6kG9HK0DayB0v8T6inUsq7J4WwwEcpE/5tsH+W+qRVun8LNFTAYnOh+fh/mwSv/wAJVG3TV9FVfk9RFKeq13P/AMPp/BVFgqiMohIAVDIhIMrS2kW0FMZcnSPOCJu93+1bsOLmWaOIzcqm55bU1dVVSkkvmmdc69Q9dmsaN5IC9SZx4q/teLplz3/daVBtVE2QMme/XzuTjc63YXYMR/h9Jc1+Or+110/h1v12dfo2tqaZzHUNPpKppTfl+WpuTgw9aPC6Xk3/AE1yfUc3zu6nD8jyeN1n4a0d+nZi9JzGf5jlpdKpP4R6IhPlaj6sn+TyiInp9J6OrHYaaojkfa/J85klv2cjWOt81BJKxUUJYtagxKml15IOWrtBxTk4RhegoxaCc17OVvhYd2sbr7lUdRDFqAFgBlluCit+jg1IOhiZqUHM6a0/VUFVhjjL4Yo3Yx0W8pJGcD5JP1XTbEorLh8Oqp8scXicfm+U58z9XU5SBEbU3hXyLMToJv8A2gZ/+gtbNB/4xhnaGMIpXHIumZKXE21MEcc7B2ueFjkm+nga7Vtp4bQov0sXOH40Hk6sM7X/AFXa/R6S4rY8/wDc474s7Qo9NTxkXeZWXsWvJJG8AnnA+7eFKZ8lJ6zrDGua9Z69fiXY080c8bZYzcO9oPVPEf1Xo0vuh21tFo1TLJmSoFAQRToD2IBJQMigRDgIDCBIHQSoCCoe6IrTPwtd2LBk8Y0u8mreJ2Ok5znOdd3N53Rwt+t7liqak8Xe+JkDp42uc35OpnGu182PwoOxl0FSzN/L9Jav7W6T/MWSMGr0DJG3B43TPj83xqEQf/NTuYg5ifRVdRycqzo3+VpKhs4b+67Gs2L0Lwa05WSmKmq3GcSAtjmscVxsLrBxttDxiU9VdyqgVQJRA3QAXKjz3wuqcVRDFfKKLEfnSH7gvR4Ovhs8nj7eOtXB+Nsimk5d8jYsI5kRs+U7i++TRtw+1Y8VXcz4LbVlu0g0Sl8Zkg53Mw9Jv0hzv5lx8t372u2rM2CapfLWOtfDPPIA67SBfPELEh2wmxG1dH0sWxxs6W79Z9HL9ZNclov1pGsRpHr/ANjZUMBv4jQfSkrf5Kha/osn9rZ9fiU6uobI4htNTxWOZg8acTrFvLzygA+rUtPL2927mbo1jSW54OS/jsLWun+UYTHdr2D19JhU2sqvWnNRkrvjQUn0/BQVzQZ6vcgc0Qt0UEbNHC6DXhgDBsUFxrmWRXBeE1DK6QzxF0sJJdJG25c11hzsAIJwWywkXCwSXFUktNTzY3wOfn0oJ54X/WxM+ksN7B0slTo2qgtT1GlI5sua6tlkjbntx61ryXTJk6KMjZIY3uFTythiIqoaep/jmY57fouWrnNVeJs5qeaCV+LDTt/ZvkZ9fl2fyrqbuZDp6SpLBC1xbI1zbNkB5wy6EgzN27HXtuXJnirRn2y7HQ+kORkwE+Tlt9F/mu/l/wD5WHD5NtmvBfa7JrgvRdx0DKqJAjfLNA90UyBIGCA2op0QkDhUHZA6B1BBK3JYjmNI6EgqiXG7H9dlr+w5Edqm1lqyItBNpXF7AXP65sD7B/yoLBFTx96Kq1vKT0s0Ti9rrY2OabOD2ZixINiRcall3RyDHSWsXVLvpsb/ACfciOj0C6SklZK917Bwte98Wq/zRt1rLRHoUOkI5LLJFrlGuQK4RETnKiJ7slUeV+EEvKV9Rn0S2P8AdavV4f8Ap1eJxVv5tnL1EDJekMxqI1+1Z3pFoY48lqT0Z50eL+c5aORDp+pHgm4rZo161OOV4qsUguRZwvnxU5dbei8y1f1NzRukqmi+Rihw/Ms79+6x+lx/LL6zJV2VH4TxOsKhroj1umz/AFLRfg7ujH/EMXy6mCeOZofG9sjN7SFy7XbvWMLVizPgCgWBqgjLUAG6grvZI7/lYilUU0paexQcXW6Ble4vEjGnsWLFkmCWmxMc7G6+bhf2Z7ly5e7ly26qz5ZCC03sQQVg1sY6PlxXYMQvlc/eujmtvMhsUFLLGbvcTnq12WnJdrvd00LiuZpdtoytMsYa489gsb63DY7ibZHjmu/Bk3Vd2HJurp6x/wDtW0166G9IqHRToEimKBkDoqRp3e5EGgEIDAQGqESAoIHTt3qCs+qbvCCE1Me8e1AQfE7cgLkYdwQRu0fC/wA0IM2TQsbSbMDm+9ZIqv0bB5gKoCOKSNw1qjYhlciLrXIBcqK8sjWAucQGtFyTqVY2eR1TzNPLJe+OV7gd4LjY+yy9ulNK1jtpEPnMl91rTHrM/wCVfA1ZMUT3tbrIHsWM6M67lKSrp263ArTbJT3dFcWSfTVWNdT9wsOfj92z6fJ+0TK2n3q86icjJ8r0VREei8LdW9XNbHf5Wg4FbYmPdpmvwuUtZUUrxJBIWG9y292Otsew80j1X3ELDJjpkjS0a/PrH2lliy5MU60tMe8ek/eHeaJ09BWWiltDUdXzJN/Jnf6HsK83Nw1sb2eH4yuXpPhu6VcrsJRQKAbBYhZKCvKclEc7VytaS3WVoyZq1ab5a1YDqXFcnWTr7Vw7+rimyE0MaIbxeLcipWxxKCZvJqIuQTPicHMdY/EK1vaq1tavq36XS7chM36Tftb37F1Y+K/e6acQ6CKWOVofG4ObvBC7K2rZ01tuWFWRlVMgSKVroEiiaAL2yvmfv7UBIg2jJAWSCvLUNZfP2qDFqdLMbcNNysVYU+k5nE86yKypq93nSn95FUzpMbHyFESR6alYcnP9afkbVJ4RsuOVKDrKWujmaHMcHetVGk1wsskVpoQqirgCyRI2MIDDSgCZ7Y2Oe9waxou5xWTF5zpfTD6txjjJZTtOTdsnpP4bm7Nq9Xh8HL7+d4nFcVOSdtfI517w0E7F0TLkissiev1tj1rly8Q7sPC7mc50jzz3nsXDfNez0cfD46+gcDdy1N/4GLbgoBIG4KgcLdY5p3g2/orFpjtOiTSs66xEp4qqaK2eJq6MfEuTLwlWxBVMlGRXfjy7nmZcNqarYdqIJBBvcb1taHfaA0/y+GlqneWA8lIfzo6rv1n1l5vE8Pt8VfK9fhOL3+C/mdYuJ6BlBGsRE99szkAMyTq4lYzOkTOqTLAqq8vJZEbNvYv2ns3DiuDNxEzrWk6R7/6ceXP3is9Pf/TLLguRzKskwG0BZaLEMqfScLL54itnLs2bJZkml3ea1bOV8s+Wh/C03V96vKXYnj0wfPYseUxacGkopLc5YbJYtRk4NswtbHRfpqyWB2OJ5ado813aNX2rKt7U8q1vavZ19DpGKqbh6Eo6TL6/SZ9y9DFmrd3Y8sXaPvW9tOinVUkDIHBzQSIHxDYoKVTUtjaTeyiuVq658hOZwqKxJ6hrM3HsG9QZUlRLJq5jdw1ntP3LLRFYs33J3oHEZ2BUGIZOqoH8Xk6qouUk1XSPDo8VupfmqK9C0ZpFlTGCMnec06wUJbV8lkxUphhOJZMUrHCyyB5Ijz7wk0ty0hpIXeRiPlD+kkHm/NZ9ZelwuHb43kcbxH/jce+QAEldergrWWDU1TpXFrTZo1n7AuDPn71rPV6nDcNHS1o6ekKuS4no6LlJQVdW7DBEX+l5iiujZ4NQQtx11ayP0WW/m/lQQOj8GYvzkkv0nOQV3nwbd/aWfvIKr6Cik/Ja6Nx/Rzgxn97ooMiRro3uY62JpsbEH3oBa9zCHNNuGw/1WymS1J1iWrJjreJiY/LcpqkStHWXqYcu942fDOOey617mkOaSHNIIIOYI233grdLlrM1l6ZoXSnjsAxkcvFZso35ZP7Hj3rx8+Ll2+Hv8Nn5tP7m3dc7oM5Yjma+tMrjEw+TB5xHnH/SPevP4jNr4auLNl/TDNc6y5HOy6qsZEDiOewbVnWmrZWs+zmqirnmO0N3Lqrih0VxqfJuW3T4bYiPYxZwRQ4EDYCox2waxB1HtCm1rnGvU9dNCRiOJq1Wo1S6alq2StBBzXPavuw0akUrmuDmktcNRvtUSHZaO0j4yzC6wlb0vS9IL0MObe78WTfDUBXQ3DVUJKBiUUmuN0EqiIJ5gxpKg5WsqXSOOeSjJj1EmAb3HUPtPBXQZvIOkcXOzJ933KosMonOtkgvRaKJ2Ki9Hoc7B25ILjdEBusDhkoCOjWjYLoqF+jhuCgiigkppRIz/lB1kEoexp4IxPMOas2LOjmwPLbrNFXTOkvFaN72O8rJ5OLg52tw+YOct+DHvu5+Jy8vG8tc85m995PvJXrdoeDPWe+rFrqg/JtK5OIyvQ4TCztQ7+1eb3+71YjT7N7R2i43s8brXclTN1Bxtyn+36yKmq/CBzRyNAwQRN8+3P8Ao9X6yDn3PqKmTMyTyON/OkdnwzI9lkF5mh9JvH5M9uXnYW/zIBk0RpJgzp3fRLXfzIM1zXNJa9rmu9JqAUDIJIZXRvDhqvY/etuLJNLRPpPdoz4oyVmNOsdnRMeHAEaivXraJjpLwb10mY07NXRdaaOqjkvzHHBL8xx1/Q6S08Rj30b+Fy8vJ93p0dQ22teO9xn6UrcEfJMPPl/hZt9buiFy8Rk21aM2TbVz+oLzXEpVM2BvE5AfasqUm0xDZWszLBNO+Vxe+5JPf1LurSKuutdEoouC2MxigO5VdBjRT9yLoL8EO3e5F0I6LO73KG1C7R9tnuWLHRVko+HuUYWqphssDw9hIsdWdjvBHFaLR6S5rVmJdLRVbZmA/vLnYNeCd8T2yMPOaUrbbK1t1dvS1LZo2yNOThmNx2tPEFepS0WrFo9Xo0tFoiY9V3EFmyAdYCaqYdqoLigIHK6gxdIT+YsVYTyGguOzPt3BUZwYXuL1RfhptSqNuCjFgSPUqNSOBotYe5QXWMG5FEWhBA5vBBXLAVFQuiB2IiSmGAliguv1LKGLm9IP5M4+K2tbi9NVrp5mMvzYmfxPzd8G+xejw1dKvK42+t9v7XPSvwtJ4LotOkS5KV1mHOPficXXvc5Lyclt1pl7uKkVpEfC/o6njke6af8AJoBjk9LqxrW2m0hpGSsf1IWfJRea3t4oLGj9F8u01FQ/kKVvnnIv+ZwQaTtPUtGzkdG0zP20g7u/fUGRPprSc3/qX/3fk/qqir4/W/2mb/Ecgjnq6ifDy0hkwXwl1r52vc2udQ1oK6BroGKI2aCXEzD1V6XC38LyeNx6WaB1Lqee7HRmkS6nZiN3NGA7zhyBPEgAntXi567b29v9vc4fJux1n2jSfwF0xmldIc7mzeDRkPbr7SV4ua260z6OfJbdaZ9PQnnJaYYwp8kXuxO9Q3LvxY9sOzHXSIWGQAbFvblyKmxWy9yrJqw0DeqFVXm0ceWXuRR+KM3fBBXlpG7h7FBmT0o3D2LEZktMNwWLHRlVFILFa7Nd69GREXU01/NJs4evX2hc1vVxz0l00b8gtLFvaIqsD3Qk81/Ob84a7doXVw1+u108PfrNdXVMffWu52J8lVQYiqGBzHHWFBJI7mnsUHNzuxPJ4qKzKk3IYO0/YFkJoIdSqNynpsgqNaOMC3YgsNFlASBkAORUJQAgVswePxUkWDqVYuW027DE/sW6jVd5tI8lxJ2m/tXrUjStY9oeHltra0+8yzK59oysM9vA2cLTx/lhgryntJTPJyXI38njx4bDN1tu9FS0ccUko5Z4ZE0Y5LkZtb5jfScgnr9IyVTg1vk6eP5KHZ9L0kCoNGzVhJBEULT5Sd/Rb2Z847/eg05GeDtMMGKesk6zHcz/ALbfrqDOnl0S9ruSgqIn25p5QOF/Sa9zslRlIEgZAyC/o91pSN4/5+xdXC20vMfDi4yutIn2lt3Xpejx09LO5hLL9I/FeRx3TV6HD2/l2dHDq9S+eQRzIG8rLHXxQ2Y6+KFhreC9F3QtwxXKyiGUNiCAbQsmTSjYEVJhQJADmXUGfLFkpIy5o7G9tixkZ0kYusGMsHSFNY4gMiubLGkxPu5M1dJifdLQSEx2Otpt7FoaWpHIWPY8a2uB9hzHrFx60rO20T8rWdJifl2sEgcAb5WXrPShoMdfaqyQEqhR9LapKlUGzD2KDAOtBSw4pHHishrUsWpVG1G0Cw+CCy1QPcoHBugdFCiIiEAIFrt2j4qCZ2pBx/hC/wDF5Oxb8TRlec3XsPCZWkDzB2j4rm4ry/l18F5/wyF5z1iQJArjK+q+dreu19utBoVVe6VjYIgYqaMANiv0vTk6zkGegk5Ca3yUlvmOQRG4yIz9fwQMgSBkFuh+XHYfiFv4f+pDm4r+lb8N4r1Hi+qOB341EPnfBeR/EfK6sPls66M5L5/1lsTMzcPWtvD+Zvw+b8LbRey74dcNWmjGWWffWsmUNmJmSrJPZAVkAoGO1RUDo9aIzp2a1iMmRlr2WLGWZWR4onLRl8stOXyyyaI4ZHN2HP7FyS42oSorqNHSF0MRvqGH924zXpYZ/l1ehi8lW2xy2tpErINGecVA9R0CorEAzKIhhZnfidnFZDapmbdqo0mtFkBgIolEMgdAyCMoIyCgIDV2qSCkNgUHC+EcnkXi+vL3rdj7/lpydvw4G69erw7wz9IC8d92fsIJ+C08T5HTwc/zPxLGXmvWJAkDILdFRz1lRFTQNL5ZXIO0NRoXQPkaeCHSmkmDy1VPz6OCTqQRfn/2nyaKzZPC7TOK/LQM/V+I0PJ//XRDs0lo7SjhDpSCGmkf0dI0sfJYP+op2czk/wBlgQYWltF1GjKp9LPhdkHxysOKOaJ45ksbvOY8IMxAkF7Rzbyk7h8V0cNHjcnGT/L7tolelLyEEDvxyIX81/vA+5eP/EJ1iHZijwWn5h18RyXg2Vbh6XqK3cP5m/AvxNz9a73W24ALKs4aDFVShA90DZoplEAdqClM1QZMrcysEZ07bsePRPwWq/ln7Nd+0/ZgU/yx7FwuBpqDc0W/yXY9y9HhvI7sHl/LoInfBdDoG5UMx3O9SxVM/nNPYoMgN557VQ1PHZxvsJHvWUI24W6lRaQHsQMoGQEgZBGUAICZrvu7lQV6l/NKDzjwhn5pHFbGtyIK9XHbWIn0mHjZq6WtHtIJ2h8bhwWWSu6tvsmG229XOastoNj6jYryp6PajqSikgSDc0fUuoqWaoj5s8wMET9rGPvyjmHrYcTMX6xBkF+snMoAxIGxIOjnqxXaFiZL+U6Nm5OOTrUsox8n/dPUVzKqGQbWjo8MZefOOXZqC7+Fr03PM42+sxXXt3XHnJdNnFWFGF/44w/R9y8bjP1PQx1/lO0p35DsXitbQhIxDtt7Vlht42zFPiasI5116LthsxNssma8xFSoHugG6BjtQAdSCtINakjImG1YSjPnNo3/ADfsWrJPhn7Nd50rP2c9TC8zjwXC4F8qDa0Z8l2ucffZejw/kd2Dy/lvRHUuh0JZNiyEeLC5pWKr7TkoM+WPDIgJjLSE7HC47doWUI04lROgJAKgdAkDoI0AFAR1LEYekKiwIv33KwPNdMTY3hvrPfvqWbFi6l38Nbo83i6eLUY7+tdjhYVbCY5L25rl5uenietw2TdRTWh0kgdBce4mli9F77+soKSgG6oSDQp3FtJVdV+Bo+dn96i+kqCqJIYzK9rB6+xZUruswyX2VmzowAxoYNTQvWrXbEPEvabWmVeV2S15LM8dVFgIeH+ldePk8W56m3ww6+kluB2fFeXkjrLktGktdhWrtMfDGOkx8Nqmfex39yvSx23Viff/AC76W1iJbcZyC2ti4xGQ0DXQOgSACgqylYjKnzWMsWRXuDIiL9LL2ayubNbSunrLRmnSumvdl0zMLS7rfBcjkhI45KwreohhijG0i/tzXqYo0pX7PQx+Wv2bUJ1LY2rD9SyFV21QXqaXEBv1H1LFU0seNqCNjb23hVFyILITICQFsQCoHQMVQCgSiqNTOGNOag4/SFV0jfJVHETlz5C4rJiTqZzoiWjnNz7d4W/FfbZpzY99VBrl6VXkWqUsTZmFpGdsj2aiOIUyY4vDLDknHbX/AOudkjdG4tdkRqO8bCF5lqzWZiY6w9el4tETE6xIFizOirNPIyzopOhJ/C7v8ERXmhfCTi1dfze/vQQoJIonyuDWDtOxvE9ii6LdRIwNZBEbsjzc7rvOsjeAdSR7k+kR6KjQ5xAAJJNgBtViJnSI6yxmYjWZnSIb1LTCBnO+UcvRwYnlcTn39Er3LfaznrVWtjPxXBxGR3cPj7CEedlxO1rU5dHYHVbL1a1x5q9Zn3c2Suk9uktuKS4C42iWvRygODXHI/HvrW3Bk2tuK7o4Su92L7SqySKqFA6B0EZPBRFOTXdYjOkIzKwmWMy5mskM8uBp5oy9Q1lcOS+60+0dnFltut8QI2aANwt7Fra0bWmSRrBtOfYMz7gVtx13WiGyldZiPd0sQ1L1HoNOLYqyTP1IKxQBHKYn8CfZw9axlW1FIHAIJCwXxBBYjAWUCfAiGwqh8KBYUDWQMVBGbKCpPO1o1qK5itrS4nNRXL1chky2fb/RZQxZgixH1rJGrBDqyVRhaTozTyco0eSkN9XQccyDuDtY43C7MOT09XDxGHSd0R0/wz2uXbEvPmugZ4I5259LYVhkxVu24c1sbCmp5YTzhl1he3C/HtXn3x2q9PHlpeI0QLW2kgtQ1ksWWT29V4DhZRdQmWnv8gPagZ9S/DgYBGzc3b2lBHFDJKbMaTx2D7FnWlrNd71pHWW5T0jIBc2dJvXfiwRV5mfibX8P6Uzn71vmdHPEaq4xSODWi5Jy+88AufJfSJdOLHrMdGh4uGNA9vFeda256dK7YPHDzh32rBWi+nJZl0hmPu7Ctd66sb16BglIOexcF6uK1e7Wjk4rTLB0VBWNdaOQgHU12/c0n4FdOHN2raftP/ToxZe0T+Jb7Nma64l1JrrJSQJAioInFEUZXLFHP19WBeKPNx1/d96482Vz5cn6WYxmAEnNx1ndwC53Mje8KquUEWuU63ZN7N/rK7+Hx/qdeGn6vduRDVmup0tSEIp3HYgruQQOzuO/qUUdPVGN2F59axVtxTtcBY3CqLbXDYUFpsnfJUSY4+90B3j6w9qoAlm9BG6QbvWoK7pLazf2KChPVtZe596iucq64uvmgwpZi69j6/sVRUIvkFkiaGnz1dyskaTI8IsgGenZKxzHtBDhYg/G6RMxMTHeEmsTExMaxLhayjkpZCMzHfmu+wrtxZnn5sHVXa9dW5x2p8JcQcOcAVl4WOtqqkuj4H9A4OxaLcNR004y6m7Rk3mua73LR9Nd0V4zGj/B1Tub+9/tWP0+T2Z/VYf3JG6MnOtzW7tZvvN8rKxw2Se+kMZ4zFHbWfwtx6Nhb8o7Ge1bq8LVovxlv0rYLGDCxob7F0+Fybr2QukU3FaohieQ1oJJ1ALRfJEaunHjmdOjcpKMRtueme9lxXu9DHj2rLoSclrbViGm4LEWhHsssZGZVwFjsbfWtGSjRkoCGoXI5bVakc2pamDdo9KPjs2TnsGXpDsO0cD7QttM1q6RPWP+YbaZZjpPWHSw1EEwvHICeqTZw4Fpz9YuOK665K27T+PV1VvWe0rFlnqyPZUCWqClUTRxA43hqwtkqx3Odqq50l2Rc1vXPSP9CuS+bc575WVzWkkZk6ydftWhoQvk4rKAEEbp37mNPOO/gOJXTixbp+PV0Yse6evaHQRtsAALACw9Wxd0RppHpDs7L0LSslaUd8u9kUTrIK5QQOG7v2IKsrBY67981FRRVskJGIqK26fSLHWuRqQaTKpu8Iibl270Bcu1FRmqaNoUFaWuY3zh6kGRU6UGeagwqiuc6/OQZb53PyFwNpzufuCy0QI3BZItwQE2NlRtQ02WpUS8lwUEL2oMyrpmyMcCAqkw4uqoXxElgJG7b6t66KZnJkweygHkHNdVcjktiSCTitm9pnHIxLxWe5jtPyp3puTaYy8U3GxGZFjN/llGP4ROkWvmNvLHFBJKdR7VovldNMLfpKNsQ47zbvZc1rbnVSm1pNjOwLBsX4abggtGn4bFiqB0djqWIrTRhwOSiMCohdG64Wm+NpvjDFUEbVy7HNarRjqBvWra16LbKg71EaVPpapiybISNzrPHqDs/YQsq5L19WdcloWvw7Vb2f4YWXPyfDLnXRy6ZqpBblMI9Bob9l1Jy5PdObb3Zr58Ru4lx9Ja2CB0yIrPmCy2stAwxSTuv0WDW47eA3n4Lox4Zt17Q3Y8cz9m7DG1jQ1osB39pXdWujriI0XWNzCyVqRM1ZfBGS8xtu/xQRHVkgiIOd/sQROGu10EDmoqjPDiByUGS8zQnmEqB2aVezpEt9qirjdM6gHD2j7U6r0GdLO3+9QQv0q7O7gO0j70FGTSbT+cv83P3oim6te7JgI4uz9gV0NQc5xu4k9vwA2K6MUzQTkFkNCCnJIyVG5T0+WpBotjtr17ggJ0YtqQUpI9yClJHkgyaimDwckRzVVo/WQPYsotMdpY2pE94Yz4HNW3nNM4IQ85bOc1cj4LE5XnJyJNzipzl5HwlbC9yx5zPkfhfgoxcXFytc3tPq21x1j01lswwtaBvWDYvxxncoNOnpkGtHCAMh/W6ipzHl3uoqhNDwUGdJHrURnzQhw1KaJow56dzScIWFqMLUVBK5p3dq02xtFsfwtMqitLXs+FhtWFhsY7UgqRvU2/DHafxkb02/BtA6qG9XYy2o+VkeeaD34rZXEyjHK5T0ZcQ6TPbbZ6ztXRTDEaa9/ZvriiO/VtMaAALZLfo3rLGrIaMMaK0WahkoqzsQV3ZKgctqBkETmcEVA+NBSkpw4Za+KgyKihOeSgyZaKQXyQUnUz9x9iAfF3jYiJWQu3FUW2QnqlBdjpJHWyVGvT0BFjZUa8NLhANlBeZG1BLluVAmyCFzdeSCnJEgpvg7lBTmo8Q1KDHqNF8PcqjHl0TINQyurqit+DH9UoJG6Pd1T7EFyOjf1fcgvx0ruqgvxUT8skGvBRWtkorTZTgDUO+5FWGsCgchBXewIKEsA3KDMkgOeSgz5qe+pEY9RR32LFGXJTyMOV1NrHbCC8vcLHlseXAg+TqqcuE5cLEccrtics5cL8VITbFms9jLZDUhpw22QWbJosZbIKqstYVReiitYoq+wakVZaoJgUFMnvu4KhXQNdAWSBjhQBybUAGnaggfQsJUVXdo5m74IgPwYzqoo26NZuRFhuj4suaqLLKaNuz3BBYDW7kCJQEHDcgLGgFA19eSCLCgHk+CBjG3cgB0DTs/qqANCw6wgA0EW4IiPxBm4e5AQoGDZ37UFhlJH1QipxCwBQELIDQPfJAKACL70AOYggfCDs2KClJS3KCo+jvsQVJNH+ioio/RTeqgAaL9FETM0fwVFltIdyCwylfuQW46V271oq7HThBYwgC1kUTQdg1IJggNUUrlA6KcIEiEqDCgSBkDXzRT3KBXKCVEJFAb3REZJRRN3d9SBgbO9aAyiENR7fggY60Dg3QEUAoDQPZACB0DoEgDJA1ygNqB0A7UDoIT39qBWUBYRuQC5jbakAYG21BAJjbu73QLk2bkQXJs3ICwtCKK3BA21BIiELop+/sQMSb69iqv/Z&quot;&gt;

&lt;p&gt;I've acquired one of these since the round-up of security keys that I did &lt;a href=&quot;/2017/08/13/securitykeys.html&quot;&gt;last time&lt;/a&gt; so I'll give a full introduction here. (See also &lt;a href=&quot;https://github.com/hillbrad/U2FReviews#secureclick&quot;&gt;Brad's review&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;This is a Bluetooth Low-Energy (BLE) token, which means that it works with both Android and iOS devices. For non-mobile devices, it includes a USB-A BLE dongle. The SecureClick uses a Chrome extension for configuring and pairing the dongle, which works across platforms. The dongle appears as a normal USB device until it sees a BLE signal from the token, at which point it “disconnects” and reconnects as a different device for actually doing the U2F operation. Once an operation that requires user-presence (i.e. a Register or Authenticate) has completed, the token powers down and the dongle disconnects and reconnects as the original USB device again.&lt;/p&gt;

&lt;p&gt;If you're using Linux and you configure udev to grant access to the vendor ID &amp;amp; product ID of the token as it appears normally, nothing will work because the vendor ID and product ID are different when it's active. The Chrome extension will get very confused about this.&lt;/p&gt;

&lt;p&gt;However, once I'd figured that out, everything else worked well. The problem, as is inherent with BLE devices, is that the token needs a battery that will run out eventually. (It takes a CR2012 and can be replaced.) VASCO claims that it can be used 10 times a day for two years, which seems plausible. I did run the battery out during testing, but testing involves a lot of operations. Like the Yubico, I did not find any problems with this token.&lt;/p&gt;

&lt;p&gt;I did have it working with iOS, but it didn't work when I tried to check the battery level just now, and I'm not sure what changed. (Perhaps iOS 11?)&lt;/p&gt;

&lt;p style=&quot;clear: both&quot;&gt;&lt;b&gt;Feitian ePass&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;ASN.1 DER is designed to be a “distinguished” encoding, i.e. there should be a unique serialisation for a given value and all other representations are invalid. As such, numbers are supposed to be encoded minimally, with no leading zeros (unless necessary to make a number positive). Feitian doesn't get that right with this security key: numbers that start with 9 leading zero bits have an invalid zero byte at the beginning. Presumably, numbers starting with 17 zero bits have two invalid zero bytes at the beginning and so on, but I wasn't able to press the button enough times to get such an example. Thus something like one in 256 signatures produced by this security key are invalid.&lt;/p&gt;

&lt;p&gt;Also, the final eight bytes of the key handle seem to be superfluous: you can change them to whatever value you like and the security key doesn't care. That is not immediately a problem, but it does beg the question: if they're not being used, what are they?&lt;/p&gt;

&lt;p&gt;Lastly, the padding data in USB packets isn't zeroed. However, it's obviously just the previous contents of the transmit buffer, so there's nothing sensitive getting leaked.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Thetis&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;With this device, I can't test things like key handle mutability and whether the appID is being checked because of some odd behaviour. The response to the first Check is invalid, according to the spec: it returns status 0x9000 (“NO_ERROR”), when it should be 0x6985 or 0x6a80. After that, it starts rejecting all key handles (even valid ones) with 0x6a80 until it's unplugged and reinserted.&lt;/p&gt;

&lt;p&gt;This device has the same non-minimal signature encoding issue as the Feitian ePass. Also, if you click too fast, this security key gets upset and rejects a few requests with status 0x6ffe.&lt;/p&gt;

&lt;p&gt;USB padding bytes aren't zeroed, but appear to be parts of the request message and thus nothing interesting.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;U2F Zero&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;A 1KiB ping message crashes this device (i.e. it stops responding to USB messages and needs to be unplugged and reinserted). Testing a corrupted key handle also crashes it and thus I wasn't able to run many tests.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;KEY-ID / HyperFIDO&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The Key-ID (and HyperFIDO devices, which have the same firmware, I think) have the same non-minimal encoding issue as the Feitian ePass, but also have a second ASN.1 flaw. In ASN.1 DER, if the most-significant bit of a number is set, that number is negative. If it's not supposed to be negative, then a zero pad byte is needed. I think what happened here is that, when testing the most-significant bit, the security key checks whether the first byte is &amp;gt; 0x80, but it should be checking whether it's &amp;gt;= 0x80. The upshot is the sometimes it produces signatures that contain negative numbers and are thus invalid.&lt;/p&gt;

&lt;p&gt;USB padding bytes aren't zeroed, and include data that was not part of the request or response. It's unlikely to be material, but it does beg the question of where it comes from.&lt;/p&gt;

&lt;p&gt;The wrapped keys also have some unfortunate properties. Firstly, bytes 16 through 31 are a function of the device and the appID, thus a given site can passively identify the same token when used by different accounts. Bytes 48 through 79 are unauthenticated and, when altered, everything still works except the signatures are wrong. That suggests that these bytes are the encrypted private key (or the encrypted seed to generate it). It's not obvious that there's any vulnerability from being able to tweak the private key like this, but all bytes of the key handle should be authenticated as a matter of best practice. Lastly, bytes 32 through 47 can't be arbitrarily manipulated, but can be substituted with the same bytes from a different key handle, which causes the signatures to be incorrect. I don't know what's going on there.&lt;/p&gt;

&lt;p&gt;Overall, the key handle structure is sufficiently far from the obvious construction to cause worry, but not an obvious vulnerability.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Security Keys</title>
   <link href="http://www.imperialviolet.org/2017/08/13/securitykeys.html"/>
   <updated>2017-08-13T00:00:00-04:00</updated>
   <id>http://www.imperialviolet.org/2017/08/13/securitykeys</id>
   <content type="html">&lt;p&gt;Security Keys are (generally) USB-connected hardware fobs that are capable of key generation and oracle signing. Websites can “enroll” a security key by asking it to generate a public key bound to an “appId” (which is limited by the browser based on the site's origin). Later, when a user wants to log in, the website can send a challenge to the security key, which signs it to prove possession of the corresponding private key. By having a physical button, which must be pressed to enroll or sign, operations can't happen without user involvement. By having the security keys encrypt state and hand it to the website to store, they can be stateless(*) and robust.&lt;/p&gt;

&lt;p&gt;(* well, they can &lt;i&gt;almost&lt;/i&gt; be stateless, but there's a signature counter in the spec. Hopefully it'll go away in a future revision for that and other reasons.)&lt;/p&gt;

&lt;p&gt;The point is that security keys are unphishable: a phisher can only get a signature for their appId which, because it's based on the origin, has to be invalid for the real site. Indeed, a user cannot be socially engineered into compromising themselves with a security key, short of them physically giving it to the attacker. This is a step up from app- or SMS-based two-factor authentication, which only solves password reuse. (And SMS has &lt;a href=&quot;https://medium.com/@CodyBrown/how-to-lose-8k-worth-of-bitcoin-in-15-minutes-with-verizon-and-coinbase-com-ba75fb8d0bac&quot;&gt;other issues&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;The W3C standard for security keys is still a &lt;a href=&quot;https://www.w3.org/TR/webauthn/&quot;&gt;work in progress&lt;/a&gt;, but sites can use them via the &lt;a href=&quot;https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-javascript-api.html&quot;&gt;FIDO API&lt;/a&gt; today. In Chrome you can load &lt;a href=&quot;https://github.com/google/u2f-ref-code/blob/master/u2f-gae-demo/war/js/u2f-api.js&quot;&gt;an implementation&lt;/a&gt; of that API which forwards requests to an &lt;a href=&quot;https://cs.chromium.org/chromium/src/chrome/browser/resources/cryptotoken/&quot;&gt;internal extension&lt;/a&gt; that handles the USB communication. If you do that, then there's a &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/u2f-support-add-on/&quot;&gt;Firefox extension&lt;/a&gt; that implements the same API by running a local binary to handle it. (Although the Firefox extension appears to stop working with Firefox 57, based on reports.)&lt;/p&gt;

&lt;p&gt;Google, GitHub, Facebook and Dropbox (and others) all support security keys this way. If you administer a G Suite domain, you can &lt;a href=&quot;https://security.googleblog.com/2017/02/better-and-more-usable-protection-from.html&quot;&gt;require security keys&lt;/a&gt; for your users. (“G Suite” is the new name for Gmail etc on a custom domain.)&lt;/p&gt;

&lt;p&gt;But, to get all this, you need an actual security key, and probably two of them if you want a backup. (And a backup is a good idea, especially if you plan on dropping your phone number for account recovery.) So I did a search on Amazon for “U2F security key” and bought everything on the first page of results that was under $20 and available to ship now.&lt;/p&gt;

&lt;p&gt;(&lt;b&gt;Update&lt;/b&gt;: Brad Hill setup a &lt;a href=&quot;https://github.com/hillbrad/U2FReviews&quot;&gt;page on GitHub&lt;/a&gt; that includes these reviews and his own.)&lt;/p&gt;

&lt;h4 style=&quot;clear: both&quot;&gt;Yubico Security Key&lt;/h4&gt;

&lt;img style=&quot;float: left; margin-right: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQn/wQARCAE6AZADABEAAREAAhEA/8QAxgAAAwADAQEBAAAAAAAAAAAAAAECAwQFBwYIAQEBAAMBAQAAAAAAAAAAAAAAAQIDBAUGEAABAwICAwcNDAUKBAcBAAAAAQIDBBEFEhMhMQYiQVFSYZEUFTJCU1RicYGSk6HTFiMzVXKClKKxwtLwo7LB0dRDREVjZHODpMPhJDSE8SU1ZbPi4+TyEQEAAQIEAgUJBgUEAwAAAAAAAQIDBBESExRSISIxUVMjMjNBQmFikaFDY3GSotEFcoGCwTSj4fAVJFT/2gAMAwAAARECEQA/APVDBTAAEAAMBXAdwAAAAJAChhCAYAAAAAAwEUBBQAAigIAoYAAwGAAADKAgYAAwGAwAAAdwABgVmAYQBQBomKgCdYCuAXALgAFAAQgAoYCAAAAAAABlAQMoQAAAFwAAAAGAwACgAAAAGAwABgICgKAQAEMKYQBTAYDA0TFTAkCQABFDIC4DARUADCkEAAAwABFAAwAAAYCAAABgADACguQMAAYDAAGBQAAAAAA7gUAAMAAYDAANG6GKncCQEUIgZRJAgC4BcqGAZtQCuA7gFwDMUFwDMAAFwGAFAQBQwAAALgFwABkAUPMA8wDuA8wDIAoYAAACqQVcBlDIGEFwqrhAFMDnGKlmALgAAAgAoAJCAAClcInMAtIFTpQFpkAem5wIkqWRRvle7KyNjnvdxNamv7Co88rd1OITyu6lf1NAiqjERjHSOS+pz3Pa5EcqdqyyJsu7avqWsJbinOuNUz29MxH9Mv8ALjrvVZ5U9ENRN0eMp/PXeig9kbuFscjDeuc30Wm6bGe+08sMHsycJY5DeuczIm6nGE2zRu8cEf3UaODs8s/mld+53x8oZU3W4r/ZXf4Lvak4Kz8Rv1+5kTdhiXcqNf8ADm9uY8Da7614iv4WRN2Vdw01KviSVP8AUUnA2+as4iv4WRN2dVw0dP58iE4CjnqXial+7SbvCL07/ZjgPvF4n4Vpu0dw4e36Uv8ADk4D7w4n4PqyJu0j7ageniqUd9sLTHgJ8SPy/wDK8THL9f8AhlTdnS9tRzp4nxr9uUk4Cv1V0/1iY/deJjln5sqbsaHhpqv9D7UnA3Oaj6nEU8tX0V7scP7hV+ZF7YnA3fgXiKPiWm6/DO51fo4/bE4G78BxDK3dZhK8NQ3xwr91xOCvLxFtmbupwfviRvjp5vwE4O+u/bZG7psF78/QVHsicJf5P1G9b5mRu6PBlXVWt8scyfbGThb/AIc/OP3Xet80fX9mRN0GDr/Pofr/AICcNe8Nd23zMiY7hHxhTeeThzcWmM4T8Y0fp4ybF7wzdo52RMXwv4xovpMP4ybN03KFpiWHr2NfRr4qqFfvk2rnh1/ln9l1081Pzj92eOqppV96qIJP7uVj/vE0KzmKqIGFFwKCGAAcy5gzIoWYCc4BnAecBo9AEr0COViWNUeFommVz5nNzRwR9m7wndqxnhO+bmN1qzXdYV3KaHz3uzb3g76SnsDq4H7xp4j4Vpuzg7ahlT/Hav8AptJwNXOcRHL9Vpuwo+2palPEsS/fHBV868RT3LTdbhztsVY3xxxL9k5jwV3moN+juq+R+6jDOOob/hf/ADJwd74WW/QF3R4Z3Z/oZDHg7679s03QYX3z+hn9mThL/Iu9a5lpjmGOTVWM8rJW/axCcLfj7Nd63zQ0sTxWkkoKpkNVE974siMzb52ZTO1Yu7no2FdyjmfBIuo9imOiHDV2gyYi4BcoLgFwAB3AVwC4DuUFwguTIFyh3ALkDuFGYAAdwC5AXALgVcGa2PVqo5qq1yKioqKqKipsVFTWipwKhMjN6juYxSavpZIqhyyS0ytRJHdk+N18ufjc3L2XbajzMbYptzTXR9o68PcmvVTV7L6g4XUZEMKdwKuAXA5aGDIlAxlGNSKxq9SCNIoUtIvGAtKpUeV4nUrVV9XMq3vM9rPkRro2fVah7WHp026Hn3autLROhqIIChXALlBcB3KC5AFQFAEIoLgK4DuVBcAAFUAuAXAdwFcILlFEAFFwHcAuAyBAO4AAwqrhH2G4+fJXvivqmheludqtenqa458bTqw/98NuHnK7/a9NPEegYFAMimAAcswZJAxKoVjcpFYXKBjIpFRqVdQkEE03c43v8e9M6GLyu6rrXaq3Xxqe7TGUPNq7SM2JXKguArlBcoLhAAXKC4DAMxULMArlCuEO5QwC5AKUK4QXALgO4DuA7gFwHcACggLgFwAIYU7kFXA7WBT6DE6R97e/MYq+DIujd9Vykrp12btPwStPVuUfzPZU2HgPTUYqZAAUQAHKMGZBWJQMTiKwuAgghylHz+PzLHQSon8orI/OdvvqZjpw1PlWm95j4G57EOBJkhFCKgACgCAoAC4DuETcoLlAEABcoLgO4BcBBAUBAwGAXKC4FX1ECuAXAAM0ELp3o1vlVV2GdNDGajqX01PvI36ZybXIm8vxIq7fGmpeAlWmntyhaYmrs6XMWqdc5qr1Pqb4tSyx1KOXWIuJNtuItzZE5sGxA/JIx3E5PtNlHawq7HudNKk0EMvdImP+qh4F3z3p0Ng0yzMimABQQcm5gzIgxuUKxLYDCpFQpRicoR8dulmVepob9s+RU+SmVv6zj0MFT57mxHqfKnpONKlQihFAEBQXARUADAAEVAUAQFAAgC4AAwAqAAAAGAAAAAXIoCOlSRLMqR5sjF1yP3upvznMb5z2N5b2MJjMTThbNLLDWZvXKvhZK2mwhkiMbJm3qZmunbHld/ebzSfRoT57i8VcevsWXPXDaaXM6nmSyJsR6PS/ErkV9vI2667c2EYm7TPXj5xl+zLZoq82frm5s1NLTu36fOOyzf1ue5a0timetj0LdTjrpbzV2eM309rTPY9i3PTJNhdKt9bWujX5jlt9XKeXjKfL1/F1nZh/RO7c4nQoxUBTACDkGtmm4GNwVicBiIqVUDC4sI89xyXSV70v8ExjP9T7562E9G4b/nuMdjQRRJUBQBAUACAZUAAAioAAqAoAEAwABgBQggAAABgAAAEAFbdPNIxHRMlWFJLNc9vZZd9sdtb2RzYyzxFunntNuHubVc8txvswRj2/7HjanpaWtPg74VzROcx6bHN1etBrNLHEj6h3U0/wmtGqjU3+rozXyt815qq8n12zz2kkWjmkbyXZV8bUsvrPZw3TRRV7nm3vOlsodbnel7jpkfSTw31xytf5Hty/6Zx/xCn0VbfhvbfaoeY7DMZVRABTCOSamxjUKxKBjcRWMCFQo15NSKWEl5dUypNUTypsfK9yfJVy5fUe3ajTRT/LDzq5zqa5tayKEVCKAAKgKAAACoYCKAICgACgCEAAMBgAQFAFBEMoAGFIiAKAOlSYpVUiI1rmyx9zlRXInyVRUc3zsvgnNewtq96uu3W79y36+q6EmORyts6kVq80yKn/ALSHF/4+fF/TLp4v4HKfVv0yTQtSF7UcjXanuTM1W3aqtREdbsXWux2/bvjZTgaPtOuwqxVXsdVrJ9u3jXnU7op0uWZzWVH2e46ZG1kkKrqkiXKnG9jkcn1cxpxkarETyVM8POV2fij6w9MPGegoxVRAwADkuapqbEKgViVAMTiKxgQUalRrYqcpFKjyaVH08skT9rHubzb1bauY9m3W8+qlGmQ35tadMnEXMyGmaVBpmgGmZxlQ9KzjKDSs4wHpGcaFQaRnGBSORdgzgUVCACgKhprAAAACAAKABgAAAwAAKAgYC/Zdb8ya1XmRE1gJHNcl2qjk2XRUVL8Woi9nad0RLqqIicKrZPWENFRUuioqcCprRee6faRVIAyCgO7ufnSDFKV3A6RGel97+8S5TqsXf5Snq3KPxexIeFL01mCmQMKYHONbNBBKsQowOiIuaFhcBhdGvOFaM7HcRkxfEYvhjnSOmiS2ZbvYvK4XNXwuFPKdNq7paa6HzT4XNXW23T+xFOuL1PM06J7mFWJzev8AcXep5k0T3IypzIXep54NE8qVRvGnSXdjmTRPcmzeNOlBu/EaPhQvk85v7y7vxQaPcX52ov7Rve80e5Cu8Y3qjQxqrl4/JdSblU+tdEQ6sKWjb4jro7GiplM2AACgKjG5iq9+VzkRHuyuSRyIll2aNbtVLc5J/wArHZ/QPyq6znqxLJls/JdF7a/ba78aN2WKgTMjY3uutsyOTVZ1+wVyce912XlEiVmP8BEeitY5znLmRyu1a2K1FRq6k7ZV2IlrIlyxnnEevP6E5ZTPuyj8Uor821+XNxw5f1dJYIb1eivs5yIi2RbRqxPlXs9Odb2EzlmRHYblfdMt+x15Uauu66985urxFSDVX2Yl0RVRbq5vDZODP+3yhTart8jrKrXObdEVEW2xcqqttutLrrvrFM5z/XImMumOyYzQ98jVfly2aq2RWPVFam28iOytW11urbJxaxM5Z+6SIzy98Miuci3tmYqJZWrrzcCO2oiO4HIi2st0UTOX+Px7iIz/AB9f4KRVsl7Xtrte1+GwhJQ/MipIiuy6kezgTVtTV87zhV6iFKt5EVHLlbqVqZbLtS97Ztt1Rb7ERNgic68o7IXsp6e2STMkj2q5XJfUi5Uy2VUVEyomrZtuSPOmJ7yfNiY9YYrtI5quumpERUalr3RUSyJdNabbr4y0zMzVE++CqIyiY9xNat3o1ct3It7Iq3VEThultXCl+cxp6YmI7Vq6OmewNVyo9q5Vc1NTralRV1KqIu3Ut0vbYuxbIic4qz9RMZTHvXGtmXciarpZqZUvd1ltdbJZLrwrzEierqJjrZFeRbK1WZVtdFat7LxLm4tetFHTOWR0RnnmyuVb5W2Rba1ciqnkRFb036CzMZ6fWkR0Zhr3I7I9EuvYubfKvDay60W2tNaouvZYwz6cpjKWWXRnDepXrHNG/kua71myj1sKnt8D0lijk5bGv85Dwa3pNg1s1GIaAFwrm3NbMiBFAAwJVCjXkjTiQI5dRSI++8QyRwqjCGuXsE9Rmxc92DJr97aXUNd2CJ3Io1JME/qlINR+Cu7m8K11weS/YP8ANUDC7CZOS/zVGoyYXYXL4XmmWv3pp9zVfQys1rfVr2cRsor61P4sKqeiWWKVLZdR6dFTjqZ8zeM2tYzJxlBmTjQAunGVDui8IBq/d/sAFABKtYq3Vrb8eVAKsmu/Dt578fGBKsa6yK1Fts1JqAMjbI22rgApEREtsAStRVVeH5TkKh2RUROBFRUTxbOjoHq+p7zAOBedNXTt+3/tcsz1Zgy6YSiWTXtXWphTGSz0m5qOVF4U4WqrV9Rl609R2s7Mm3p4UXx8HGSOiZnOc5WemMu4Zd9mRVReZdS7bauNLrZdQ7OzoO3t6QiWVV40VF8qKnqv+0kdGfv7Vnpy9xtS102oq3svk/7+VSR0Rl2wTPTn60oxURUa9zU16rNW1+JVS/i16uAdnZJnn2rVuay3Vrk4dXQoF2VXIq7U1JZOa32GMxnOcmeUZMzVsrV4lQypnKYY1R0S9jwSdZ8NpHL2sWj9Eqx/Y08rF06L9z8zusVeTpdpDkb1X8pAXIoXpA5hqZmAFCAoBFEKBic29wjVfEUYtFzFVOg5gIdTJxAYX0erYRWq6jdySKwrS8wGB1Nt1AcWrp7o9Ldkjk6UNlLB8RLGrXrtRUVftPQorclVKd9xnRuNWgXdxmW4mgXdxl3U0C7+Mu6aDzP4y7qaDzScY3TQM8nGo3YTRJ55OMu4aD0knGXcNB6STjG4mg9LIXWaD0shdcGk9NINcJpk9M/8oXVAemfxF1QmRpM7iGqA9M7iGqDpPS8wzD0q8kdCdJ6bwRmDS8w6A9L4I6FVpU5PrIGkiAUkjecC0kbxKQbtK1k8jWK7IirrVdiJwmVMevuYzPQ9WwCJYaGNuuz3Pey/IVUy+R3ZHl42ry39rtw3o3fOF0qQxC1r+f2eUKfMBzTU2ABBDuAFAAgJKJWwEZQDKAZSgygGVOICFiZyQMTqSN3AqLzAzcmowzUu+9RUfJV+5yd71lhcz5O+N9u411UuO7Aq9NrWqvFmW/2W9Z0xep7padEsa4NXXtkRb7LOXX6tVr8Ntirs1l3afemmSXBsQRLaJFTUtkcnk4tmvxay7tPvNMpXCK9NWh4E2OTh8pd2lNEjrTX97u6WF3KTTKVwuut/yztvgDcTSXWyt1/8K/n3jdX7vzzl3Ke80ynrdWd7SeYXcNI6gq9adTS22qiMcur7dWy+3XZV12Vrp74TTPclaGpTbTzeY79xlrp5oTTJLST97y+Y8a6QdTy9wkT5jy66TKS0Enc3+Y4upD0L0teN/la5L/nmLqjvj5wZT3SWjXku/PkGoyGj+V+fmlQ0YnP+fIX+qHkTn5+Bfs/YXMPKnP0/7BBlQB5Utz+Lg6RmDIMxWRADIgDypxIM57zJkRic3iGfvMnewbD3VU7Gom91OkdbsGcKqttvA1OFebWZVXItUTVM/gxiia6oiI/F6tA1rGMYxERrERjfktQ8et30ttDUzVcxUXAS8FiDm3NTYRQrgFwHmAdwFcBayokBAMBgADKGEIKRUa7404ijCsPMhUYlhS+xChpC3XdE6EGoCwR8hvmlQJTs5DfNAfU0fIZ5pUPqaLVvG9AC6lh5CflC6zSOpIu5px8WvyfbtGqTTB9SRKq7xODj4i600pWih17zX/sNZpguoYde84ET19A1mmFJQQp2mzZs22t0l1mkdb4NW8T8+QazSTcMprao2t29q3ti7iaS6209uw4eJn4RuGiC610y/wAm1UTVra1bdKca+PXcu5JohjXCadV7BmzL2Cc+0biaELg9J3KPh/k2/uLusdsnYLR6veY/RtLum2jrHSW+Bh9GXdNtC4DRqvwMfB2vFzDeqNtjXAKPuUfmrxl3jbS7c9R6vemfW5+cb9XNKbaF3O0l/g08SOcn7rc9i79XNJtR7mRm56kRURYmrrReyevk1qmrV5bk4irvk2od6kpI6ZmSJjWNvsa1EuvKW3kTXrsljCu7NXbLKmiKeyMnTjbb88P7zTMs4hsIYslEDAS7CDk5jU2pzBCzhRnAedAFnQD5bH90fW1epaVGvq3NzPe5MzIGu7He330i9lvt63wjKmGFUvhJcfxiRyvXEapqrwRyuiYniZHlankQzyjuY5z3oTHsYT+kqvyzOd9txkZz3sibo8ab/SE36P70YF+6jHO/3ehpvYjIV7qsd7+/y9J7AB+6zHe/G/RqX2IGRu6/HO+IXf8ATQ/hAyN3aY0nDSO+VTr92QDKm7jF02w4evjgnT7KpBlBqlfu5xTvXD/8yA/dziPelB5tR/EAHu4ru8qTpm/GUUm7ip+L6f00n4QLTdxNw4ZEviqnpf8Ay6jIz9y/d1/6V/nv/wAgGVN3UfxW/wCmJ/DAZE3c0/xdN9Ij9kUX7t6HvGr8+Egv3b4b3pXdFP7Yov3b4X3rX+ZTfxIFpu2wjuGIehg/iQMrd2mC8mtb/gM9sEZk3Y4F3Wo+iyBWVu67AO+5PnUtT7IDL7q9z/f/APlaz2BRSbqNz/xg30FV7ACvdLgHxlF6Of2QGRN0WBbOuVN9f8IRv0tZRVyL1JV09Tl7LQyse4o28gCRgDyAGTaQTkANGA9GA0j8QGRrdeogzIFZCCtRAIoABxjU2pIJAQCCpVwHjeJ1C1OIVk1+znky/Izbz6huaXOUqJIFcqgIRAigAAC4CAAAAAYAAAAAAgAAuUABcIYAAXCmEO5Rnhnmp5WTwSvhmjXMySN2VzQPb8DxFcUwynq5Eakyo6KdG7NNGuVzk5n/AAmXtc5FdkigAsAWAQFAGXUBSIgFIQVxcYDAYBcDjmptSQQAgqVIOdiFR1PSVMt/g4ZHfVMkeOKt1VePWbWpARJQiKAEEIKAhFUEQBTCAKAABgACACgIhFAAAAAAAMAAq5RSKEeq7hpv/DJ4+RWOt8+KL8IV9wi85iqrgVcAAfB+fUBPEFWEGwKZAwGihAAwOMam0iKhQJAhwHy+6afR4a9qLZZnxxp4r514eJll8ZnT2saux5qbGtCgIIkKQCAQAAAAAAwGAEDAlXonOBjWReIZidI7iCqSXjTyhFo5OMoYCAAAoAgAYAAwGB28LxytwlkkdLobSuR79Kxz+xTtd+wDst3bYv3Oh9DN/EEyV26HdxGsTuuNM9Js29dRtRWOb4TJpszPPeB0G7tsJ7nXehi/iCDL7tMH/tnoP/tAypuywXulR9HeUZU3X4F3xN9Gn/ABl91mA9+r9GqfYhWRN1GBd/t9DU+xCMzd0WC/GNP+k/AB04aiCobpKeeOZmzPFI2Rn1SDOBQBw+QK4pqbUgIggDG5QPgt1k++pYL8uX7psoa63ximbFCgSBKuTjQBZk40AAABAAAAwGAyC2NVy2RL/s8ZBeie96RRtdJI5URrWNzOv5DGqtlFL6ag3GYhVIklSqUrF7XU+X8LThuY+j2HVRhavafSw7hcPYnvsk0vzjl4+438LQzO3EYXbsZPPUx466vDW3IrNwiWXqSoX5MiG+jHtdWGfF1+C1+HOXTwuRt9T23czp4PLbxndbxNu52T0909rmrs109OXR7nOa/tXbfztOiJaZhkKiQAAACoYAAwHcgpCirkG9RUk9fMlNTNR8z0VzWue1nYJvt8813Lu0zoo1uwu5fHE/mifSKb2pz8dh+f9Lbwt7lL3NY33ivknpvbF43D+IcNe5PrBe53Gu8JPSQe1LxeH8ROHvcg9z+NfF8/6P8AGXi7HipsXeRC4Hi7f6OqvRKZcTY8VNm7yMa4Tijf6Orfo0peIs+Km1c5Erh2It/mFb9Fn/AZb9rxLabdzkqVS1dbhdSksLpKeaNUzRvRzUd4EsTuyavhGzNg9qw6tZX0VPVst7/G1zm8l/bs+a8it64Utf58oHFuam0XIJCocEYXrqUDy7dBNpsSl1/BNZF6s33ja1OEZIhQNd7nXsnQOwbEeGV0zUe2BzW8qRUjT65p37bbs3FOwjEGorkgWRqJddE5slk+YqqTiLSzYudzRRz2OVkiKipqVHIqORU5lN0Tm1THezXCGUIBgBBQDQg6lHTy1MkdLTMV88zrInAicLnL2rGJrVTVduU26ZqqnohnRRNdUUx2y9XwbAaXC40WyS1Tk98ncn1Wchh4d/EV3XqWrVNt9EjTlbTAYE2QDWnp4qiN0czGva5O2RDZTWxyeV7pdzC0earpGqsF7uYifB32W8H7D1cLis+pc7f+/VyX7EZaqfk+KYqrqXah6bhmFhCKAAAAAIApgUm0CyDv7mpNHjdAvKe+P0kMjP2nNjP9Pcb8P6aj/vqexv4D596pGSGBka5eNCoLv5TekCkc7jQqH75x/YVHmO6+HJiaSavfqeN6qmpFVqujX9VL+M9jA1Z2cuWqY+eU/wCXBioyrie+mPp0PqNxtQj8MfDdL09Q9NvayIkn2ucdkuZ9eRVgcQ1NqApASoRrTPysXxKB4/Vy6apqJe6Sv/WNzS1VKE1HSPbHGm/e5GtIrtuip8IY10iNlqnJrdbNl8CL7zzj69919Sy5smIVkyrkTJ49+7y5vwm6LFDVN6tEdXXxuR6P3yc2X9QbVs3bne6r2x43SzXjbHidLEsrHMbbqqNnZsdbspLdi45+thq/uW2ry9H3lL5qPsTvcawAAIGBSAU3aY+pYep7j8MbBSLiErffqq6RKqa2U7V4P7x2/wDk5Dxcde1XNvkelhrfV18z7Zp57qaGLYtDhEEM80UkrZZ0htGrczbse/PvtvYbDdZs1Xqmq5ci35xUWNYdiFup6lmfuMvvUvmu7L5guWLtsouUV+06xqZpCsfHt6AMMsTJ43xPRHMcitcZI8NxzDlwvEpYLe93zxf3bvz6j38Ld3bTy79vRW5Z1NBAIoAAAAYDAE2gZCDcoXObWUuSR0L+qIffW9lHme3fmu76Otnb8+l651uxS3/n1Rs7akpnHhb1n/5/1vV27ni/pR1Bi3x276BTfiLu2fA/3E27ni/oV1Fjfx1H87Dofxjcw/gf7pou+IaUuPfGtL86gb+MbmG8FNN7np/IEp90Hf2Hu/6V/wCIasN4dw8tz/pVo90XfGFeiqB/6v3x5b7to4hX49hkHVMyYbJHnaz3ptR23ynG+zbw97xWq5Xet8j4rFcXlxVYnTxRRvhRzUWJHIio5UXfZ3u2LsPSsWKbOelxXLs3Ms4d7cXUZKmrp7/CRsl9H/8A2dDW9LauoxU8wHINTakipKMbiDkYtNoKKpkv2MT7fKtvTJjU8oNzUheEDqYFGiz1M6oi9TU0sjM3dLZWO+acuJ9h0WPaqUylfWSunnVVV671vJabKeow851YsOj7mgVndhcaIuq5NS6So6dlLVtntkZEyV0nyNE/Mab/AKNttee+GTh4Lqq24r8B2Q5J9ZlQEAAwGQZImLJKyNFRFe5GoqrZNa21rxc5hXOUSyph79SwpT01PA3ZDDHGltm8Yjb+VUufNV1aqqquaqZ+czL2qY00xHdER8obTTFWnieF02KwNgqFlakb9JG+JyNc1+VW9s1zXanck22btVmpquW6bj4mr3H1sW/o6iOo8F/vEvs/rxno0Y639o46sNX7DQp8axnCZHU8kqyaJcjoKldKjbcDX5syfMeZ1Yexe6zHeu2+q+po911DPZtXG+kk5fwsP4/qnHcwVx00Ymh9NHNFPG2WCVksbuxfG5HN6Tkqpml0RJmKvON3lOl6KpRNa54l/WQ9T+HVekpceLjopl54es4CUqJKAAAAABgMCyDLG7K9juS9ruhUMalh761c8bHcpjXaudqKfMT2vcgwgsVFEGTf+CZILu4mgcfH4tPhFY3L2Eel9G46ML6ehqvejrePKe9Dync3Nz6DFqZb6pc8TvnNVU+sjTL1D19qmDJlbYo45qbSIJUoxuIPld1E2Sh0d/hZGN8ib9f1TZQwreeGxrSB0cHnZDVuildliq4nQOeuxrndg5V4EzbTnxFM6dXI3WaozmmfafVw0ixO0bksqLbmXwkXhRdpIqiqGWnS7ENOmUiszoW24NhFfEY1iMaJJR0zkc5+8nkat2oxFusbV4VdZM6p2u9M6KNVWqphXVlGmHyp0NAARAwACkIMkS5ZWO8JDGplD9AU8iSwQytW6SRRvTxOYjv2ny9UZVVR3TMfKcntUznET3xE/NsEVwd0OMzYTFTdTxxukqFk30ubeZEadeGsbzmv3dt8StfjmLuVjZKmfX8HA3LF+j3nnnobeHsuTcvXHRpdydfPZ9VJHStVdbV9+m81q5Nf94a68bbp8xnTha/ab9TuNj0f/CVbtL/aG7x3o/g/0hq4/wCBnwvxO3gNFPh+HpTVLWtl08zt67O3K529d5TlxNzcuuizRoodg0Nzz3d5KmSgg1Zs0svk3rT0/wCHfaOLF+y84PXcCVKhAIoAAAAZAwKAsxV65huHdUYdRT9ccUbpaaJ+VtW7K3ecnKeDeu+VueTtPWt0dRvphb/jXFfpJr3WWhXWyb43xLz6f2Bdz7m2n5y631fxxXeZS+xG5R4J1j634j8c1P0el9mXct+CDqLFPjd/0SnHkk67FPh+LSwyxddWObJG9mXqOLk/KM6Llrwf9xjor8T9DyaRixvex3ZNcrfK1bHu09jy5ZaWXQ1MEvcpo3+a4yR7fC/M1rvBQxZM4HLNTakCHAYnLqA+C3VTZpqeHktdIbaGut8kpmwQBJB2aXHaymY2J+SoiZbIkt87eZsib63MaZsU+y3Rdn2us6furka2zaNl+eVyp+qNqrm+huRy/Vyq3Ha+sRWOkSKJdscKZEVOJztbnJ41sZxbiGE1zLimbAgABAADAYFGMrD2HcniLa3DWQucmmpPe3JfXk7R33TwcZZ27r1MPXqtvqTidDWqaGjrXRPqoGTrBn0aSXcxM+XNdnYO7FOyRTbRdrt56KmFVFNWWqltsYyJiMiYyNnIY1GGIoikRUqFSqoxqvcqI1qKqquxETaqmSS8V3RYkmJYlLKz4GL3mD5DO2+ce9hLO1aeXiLmutwFOtoIqJAAAAKABkABSAWSVezbmJNNglH4DXx+ZI4+exn+oeth/RO7ZTnbhbxlCsQWVB5DJBfWEeOY1DocTrI/696+dvj38P6Kh5d70lTlnQ0vYsHqNPh9JJ/Us+wjJ2WqQcs1NpASBgetkXm4wPL8dmWXEptd0jRsaeRLr63KbqeyGmrtlxjJEgSAgEQIBFAQIAAAGAAVcg6mE4nNhVWyph1t7GWO+9kjXsmrz21ovAutDnxFmm9RNM9E+zPdLdauTbqz7Y7Jjvh7Rh+IU2JU7KimejmuTfMvv43cl6HgXLVVqrTW9WiuK41N81sjALgAEuVGornKjWol1VVsiFHnO6bdK2Vr8Pw9+81tqJ2r2X9XH4PKcerhMJ9rccN+/wCxQ8+U9RwoKEVCAAAAAAABgNALQivRdylDBWYfI+R9S18dQ9nvVTNE22VruwY9reE8jHXKqLv9j0MLTqt/3PqEweDtanEG/wDWz/iOPd+C06dHxV/mV1pb3/if0x5d5NBdan/GeJ/SBumgdbJ/jbEvSReyG59zbFdbar43r/0HshuGkut1f8c1XoacvURyavcktZKs82ISvlf2TtCz7p1W8Zo+zc9eH1+2+LxjC3YVVdTrIsrXMa9r1blVUXbdLrsXUejYvb1GpyXbW3Vlm+z3Jz58PWLuMr/tNzW+vQjJzTU2ADGoGpUORrHKvAir0Fgl5HUyaWomkXt5Xu8iuW3qsb47GiWuoEkCKJIEAigIEAFAQAAAwGQMK3qLEKvD5UlpJnRO4bLvX8z27HGq7Zou+e2UXK7fmy+8od3DFajcQpnI7VeWCyovOsa/sPMufw6r7Op2UYuPbh9FFunwWVEtWJHzSscw5pwl/wANu3rfOyu3RYKxP+fi+bm/CY8Nf8Jd63z0uTV7tMNhRUpo5al/BvdGzpdrt4kOijAXavO00NVWJtx31PiMU3SYjiV2Ok0EHcYd757u3O+zhLdpy3MRXW+eudbnSUSEIoAAAAAAAAAKTYBRB6RuGlTRV8OZPhIpNvKbl+6eT/Evs3oYP233yeQ8x2qy8xUFiKLKZMS1mSFrAd3cZUfCbsoddJUcz4vvHp4Cpx4pq7kZvf6iHwWvPRccPRGqRk0DU2JKMbiK42LzaGjnf/Vu9aGVLGp5YbmlJBIEgIBAACAAEUBAAADAAGQMKYDuQO4BcBXKEAgEVCAAAAACgIABgF0Aq6cYGaOR7NbHub8lytMdMLmzpVVKa0qJk8Ur/wARjt0ctPyZa6+afnLIlfWd9T+mkJs2+RdyvmZExKu77qPTSE2LXhru3OdkTFcR78qfTPJsWvDN25zsiYxiff1T6VxOHs+Gu9c52RuN4q3+f1HpFHDWfDN65zsiY/i/f8/nE4Wyb91gqsTra1rWVVQ+ZrVzNR1tS8ew2W7Nu35lLGu5XX51TobnZXR4nFbWj2vY7xWza/K02z2NfreqNcqrzGDNqGtsSBicoV8nummy0aM7pI1vmmyhrrfAmxrSBJAgJAAEUACAAAAACBAMBgADAAoCAgAAokBgIAAAAoCAKGAwIVqquoA0bgMlntbk17QF75zkDu/n6AH74BV38/QA8z/ygFI5/EvQA8z+L1FGRqu4l6APt9zVG9qdUyMyoiro1cm+cuxV5kTYnHrXhQkyRD72NdSGDNqmtsQFQ4D4LdS9c9OmvLv18uo20NVb5NVTjMmCVVAJKFdCCQEAANLX1qqJzbQJAAAAKAgAAAAYAAAAAAAAAAAIAAAABgADKKA38Po0q5HsW+9aipwbVCfg7bcBRU2r0kzZZSv3P+E7pAnrAvKd0gJcCk5TvqgyHWGXlO9QAuBy8pwC6yS8buhAF1ln5S+aENuDT32/VKOlR4JlcjpnKuvsUS1/GRcn2EESNRrEbla1NRiyydNhFaprZpCsT11KUfLY3SdVU7tW/j3zTJhV0vPnwvaqm1rYsjgIyOCJVjgFkdzgLK7nAWV3OAZXc4Cyu5wDf84C3/OAb/nAN/zgPf8AOAb/AJwDf85AXfzgF385QZn85A8z+coM7yAzuKDO4gM7/wAoUGdwBpHflADSO5gDSO4kAekUA0i8QD0nMA9JzesC0kVVsjfKMh9ngMCe+Som9s1hJWH1sUfMYNjZSK/B5AHoW8RAaFOIB6HmKDQgToE2fsAegQINDzAZmxgbLEAztA1zW2EBiel0Uo5s0a69WpSsXyWIYZncr4965dapwKvHzGUVZJNObgvoZ7rvTJgxLSS8QzMpT1JNyQF1JNyShdSTclQZF1JNyVAOpJuSAupZuQAupZuSoB1NLyVBkXU0vIUBdTy8hegA6nl5ChC0EvIUBaCTkL0APQSchQFoZOQvQAaGTkgGhfyV6AFon8hQDRO5CgLRu5K9BUGjdyFIpaN3IXoKg0a8n1ECyLyfUUGj8EAyeCAZPBAMicQDyJxAblLRyVEiNjYutdbram+Nf2bftGZk9Fw+mZTwsianBr8fGYM3ZjaYsmdGgVlArKA8oBkAWUIMoDygPKUW1CDIUa5rZgKxOAwPS6AaMkScQVpOp28n1AYVp28DU6BnJlA6mbyU6Cg6mbyU6EJnIfUzOQnQAdSx8hOhCh9Sx8hOhCIXUsXIToQLkOpIu5t6CoOo4uQ3oGZkXUcXc2+aAuooe5p0AHUMPc2g6C6hh5CdA1JpJaCHuaFB1BByLA0l1vg5AB1ug5AQut0HIAXW2Hk/aXVJpglw2G/YqNUmmC62Q8kJpHWuDkg0F1rh5JTQhcKh4gaC61QcS+r9w1mgLhUPF6gaC60w/loNCVwmPm6C6k0DrRHzdA1GhbcIivr1p4kGo0OpBRMiRMiJ0EXS6cUViLk3WtAyoEWBQABQEhAAwCxRYDA1jWzAVIGJyAYnNCsDouYDHok4gDRIAtEAJEA9EA9EhAaIqHogo0WsBaIA0XMEGiCjRIEPRcwC0NwHouYBaIA0IC0RQaIINGAaMKWjANEBKx8wBoioejCjRhD0QDSNPH5AMzWBGw1AMgFoBkKigGAAAQwGAAPxAFwMBg2EEAVAGOwCVAIVoE5QHlAMoFZUAMqEBlQoMpAWKDKAZeYAygGUB5UAdgJsVBlAVgDLzAGUAyALKUGQgMoBlAWUoeVADIBWRAhZQqgi0QCwiwGAwKAChhAAAAFAJVAxGDYQABACsArAKwCsAWAVgGAWAdgEAwCwAAAAQwoCCyFBYCbAVYBWAACwEawHYAsAWAZQANCBWKhkFAMoesIsCgEAAMBlDCGAKFTciMRizMKSgIKAhASAgAIAGABTCEFADAAgUKQRSBSKgARAygARUMgQUkAAABgIBBABRQwGQMoYFBDAAEAwKKAIYUEElH//2Q==&quot;&gt;

&lt;p&gt;&lt;b&gt;Brand&lt;/b&gt;: Yubico, &lt;b&gt;Firmware&lt;/b&gt;: Yubico, &lt;b&gt;Chip&lt;/b&gt;: NXP, &lt;b&gt;Price&lt;/b&gt;: $17.99, &lt;b&gt;Connection&lt;/b&gt;: USB-A&lt;/p&gt;

&lt;p&gt;Yubico is the leader in this space and their devices are the most common. They have a number of more expensive and more capable devices that some people might be familiar with, but this one only does U2F. The sensor is a capacitive so a light touch is sufficient to trigger it. You'll have no problems with this key, but it is the most expensive of the under $20 set.&lt;/p&gt;

&lt;h4 style=&quot;clear: both; padding-top: 1.5em;&quot;&gt;Thetis U2F Security Key&lt;/h4&gt;

&lt;img style=&quot;float: right; margin-left: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,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&quot;&gt;

&lt;p&gt;&lt;b&gt;Brand&lt;/b&gt;: Thetis, &lt;b&gt;Firmware&lt;/b&gt;: Excelsecu, &lt;b&gt;Chip&lt;/b&gt;: ?, &lt;b&gt;Price&lt;/b&gt;: $13.95, &lt;b&gt;Connection&lt;/b&gt;: USB-A&lt;/p&gt;

&lt;p&gt;This security key is fashioned more like a USB thumb drive. The plastic inner part rotates within the outer metal shell and so the USB connector can be protected by it. The button is in the axis and is clicky, rather than capacitive, but doesn't require too much force to press. If you'll be throwing your security key in bags and worry about damaging them then perhaps this one will work well for you.&lt;/p&gt;

&lt;p&gt;A minor nit is that the attestation certificate is signed with SHA-1. That doesn't really matter, but it suggests that the firmware writers aren't paying as much attention as one would hope. (I.e. it's a &lt;a href=&quot;http://www.snopes.com/music/artists/vanhalen.asp&quot;&gt;brown M&amp;amp;M&lt;/a&gt;.)

&lt;h4 style=&quot;clear: both; padding-top: 1.5em;&quot;&gt;Feitian ePass&lt;/h4&gt;

&lt;img style=&quot;float: left; margin-right: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAcHBwcHBwcHBwcHBwcJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQn/wQARCAD8AZADABEAAREAAhEA/8QAtQAAAgIDAQEAAAAAAAAAAAAAAQIAAwQFBgcIAQEBAQEBAQEAAAAAAAAAAAAAAQIDBQQGEAABAwEDBQkKCAoIBgMBAAAAAQIDBAUREgYTITFRFCIyQVJTYZGSIzNCVGJxcoGCkwcVFkNVc9LTRGSDlKGisbLBwiQ0Y6PR4vDxF8PU4ePkNUWksxEBAAIBBAEBBwIHAQAAAAAAAAIDEgEEERMUUwUhIiMxM1IyQxVBQmFxkrHR/9oADAMAAAERAhEAPwD3M5tCAAIAADeAACASBSghEAgAAAVADeAAAAQCBCiAQCAQCBAAIDAAAAEohAQCBACAQCAQiAECFBxEExAEAgQAgYRGkAgEAAVAhrwABLyCFBvAAACFvAIVAIBAIBCiEEKIAQgBUCIBAIAQABAIBCgkDAQAgMAQIAAhgqAQIYBgIA4BA15GgAgEAl4UQiAACEBAAEAhQAIBAIBAAUEIAVAghUCFAl4UbwiXgAAgQAgACAG8AgEAhBAYKgACGAYAgEAgEBrwCBriNIAQAAQoBEvAgAICBAABAIBCiXgQBQAAQIBMQAxATEAABiAGMBXSNY1XPe1jeU5cIGrqMobEpe/2rQ+/Y/8AcKjUy5dZNxfhsk31dPN/OxhUa1/wk2P4paD/AGYfvijDk+Eyl+asqd/pzsZ/IEYjvhNl+hmfnbv+mAq/4m1f0TT/AJxJ92ED/ibV/RdN7+T7AVY34TqjwrIg/On/AHIF7PhOT5yx/wD9f/rgZsfwmWf85Z1X7MkT/sAZ0PwjWF85FaEH5KN3/NA2kWW2Tcv/ANjg9OCo+6IraQW/YlTdmbVoH/l4/tAbZkscje5yMk9ppA4UxUMQECI4BgCUEDAMNIFS8oGIAYiCAS8CYgBiCBiAOIKgFMs8UDHSzyxwx8t7sDQNT8pbA+mKD3zSoPyisL6Zs385iCLfj2xPpizPzuD7wKs+N7K+k7P/ADqD7wosbaFD47Se/iILN1U/jEHvGFDpNHzsfbaQHON5TesAZzpQKGMCtZiDV1Nv2VSS5iptClhl5D5W4ioxvlRYf0rQ++aFam0MuLHo4nZmo3dPdvI4Udhv8uW7A1vad5BUeQWpbVda87p62dz71VWR3rmok5MbL7moiaL+Eutyqt6m9Pc5866tWr7+PWAXK5qoipvlW5E0Kt+y5L9ugcgLjRFVUW5FVFVNKXpr0po/gBGSOZK3eK5yLdh0333aPWmhfVsHIsWolVz0wbVwonBS9U863atP8QEWoe1rm4VaulFXTo0p0ez7QASoW+/BqR3620HBmz3KqrHoW9V0X37eJNCavN67xwZtTEmHuaqmnZfq/wASKrfMj3PwphRXKqJ0X6ELygZxdoDpKEWJL0gXxVL43Yo5Hxu2tcrV69AG8pspbbpnNzVqVnovldKzsS42AdrY/wAIVQ17IbXjZLCq/wBYibgkZ5T403kifV4HemRXrMU8c8bJontkikaj2PYqYXtcZaWAMAwDFBA15hsNIEAAUt4C4ggesBc4FLnSBM+AN0f6vAbdDRycPC8r7bltO1J4myqtHTPWKFiLvMTN7JJ0uc/FvuQdYuUnI4lKhcQAxkExlAxgTGAc55wIkq7V6wDnnct3WA26prk7tLcmhN+7Rx7dGkCLVz89L23faApWVVW9VVV2qoC5zpARZAFxgLnAo59/E67XqRE1pcvru4yBUnkbhRr1bdfdct3CuxedFuS9F0ATPvxY1W96OR16omlybdH6NQA3Q/ovV+cVbtbtaX7Wot6onSoEWd3RrV3HrVUvXX0ARZ3XSat+qftv0ANul2+S65rkalzVVMKM0ojV06NKqu1dIF27n5xJMDL0TCieDdjx6tv+4EZVo1G71+9VVTf8eJVTFcm+w36E0acSgWbuRURqo/Cl11ytS5UfixJc3Dfdfoc1bnb4CuWdsitVqK1Ebdp0uXpc6+9y9K3cSIgCI8CxH9IRc15RkMkKj0/IXKXMSssWsf3CVy7ke5e9yu+Z0+BKve9km905wzqr2Ay0cAoA4BA15lsQEAUBQEClVykFWJQKHvIrEc9TKq8ShWste0NwWfVVOLgRrg+sdwCsvCnvVyq5VvVVVes+hwV3kUl4CYgFV/SAMYAxgTGAMYExgDGAMYAxADEAMQC4gABLyAXlAAAEAl5BCiXkBKDiAOIBsXSBlSxT08ccs8MsMcidzdIxzM55TMXCQqKW1UXKAy4pmv4LkUDMjkVqorVVrkVFRyKqKi8SlR9E5K20ltWTDNI7+lw9xqfrG6pPNK3f+njObbpwprwGCCBrzLYXgABQFAW8ilAqcpFYkjiKxiKqcRXnuWtfvKagY7WqzSebgx/zHWDlY85VTo5q7wK1UBLwK1vXRfel6+q//ZOoA71LsN/Tft8xACgAS8AXkAvAgAvAF4AvCoEAohFAIhVS8IBBAIBCgkECiEI96x4Xtdc7Fo2p5ScV/n9RRXUVL6p6SSK9z8KNc+SR8sj7uU56/u4W9BUUFFrXOat7VVPMBvKWbOx3rrTQvnIj0TIK01o7ZbSufhgrWZp2n51t7oV9LhR/lAr3dphs4QQpgjXGWwIEAAAvCgBWoVS8gw5HaTKqSNKHuS4o8Rtqt3faNVUX7zHhj+rYd3ztMqlRWpBWoCgKFAIAUAIAAAEQAAAoBBAIFAIIACoUQggECAAdHT/r1gQKIAc1HJcoQsNFJMqo2WnZ9ZJm/wB5MP6xRlSWNaMTce51kZyo1xhWCjH34cDsWy7T/wBio21IxY2Ki8JVv82jUEbWlqH01RBUMXfxSsk7FxUfUVNMk8MMvORsk7bTk2yQpyhwjWmG0AACAKFVuUBCKokcRWE4ypLwrn8oqp9LZFdPHw81h947N/zmmf5PE86zXiO7grV7doFauTahAuLpQKXEm0AXhChQAAEAF4EvAl5QLyCXpx3rr1Ldp4uJePr1aNYQAoAQBXuwpejVd/r1r1Iq9AQiTM3qX6XbEVUS/atyaOLo4wpkkaqNXTc5bmrdrVb/AF8XGiFQElYvGuq/Uuq9dejoIJnWKl6LfrS5EW9bkvXRdfqXXqCpnEwNdhXTh0Il6pi2p0cdwESRi6nJqv4048OpU136Ltd921AhwogQAgEoIRY1btS3AWtAyGhGSmoqPpPJ6fO2LZj/AMVi/VZh/lMNt+1dBFOhQ4RrzLYgKQQoW4iqnMAqc1SKxJL9hFYxFVOIrmso75LKrmXL3tHdl7XL+g3FibwuVu+U7uLGcgFWnaAi37VAS921QoXv5SgLifyl6yIGOTlOCpnJeUETOy8oomdm5RBM9NygHbUPbwgH3Z5AUUq27FAyGSNk4K/4kDAQBXqy7umHD0hC3x3pwdCoiaNS8SIvVcFDFCi+BpuXVr06Fvu26l9aKA6ZtHI1Va29F893m2X9a6E0hEwt0b1NHQmgCXNuuW65P4dPQFTC1cKoiLdeqevj9e3jAYCKqIl66ETbqTzgQIIUQGKhwLWgZDCoyE4KhH0bk43N2PZrPxeP9hlp0d+sy0t2FD9YGtMNoBAJiKDeQAA6AEexuxAMZ1MwKxZKTpIrT1VHKqLvU4yo8xtbJfurnwQvi06WtVMHqTwTo5ubfk7V828qMd2T1bzUhRUuT9dzMvZIKnWFW8zJ2QK3WHWt+Yl7C9YFK2RV8xP7twFTrMq2fg82vm1AxZKdWLvmSR9DmL+jVovApwALh6QAAoC6NgREuCma9zH3t2aUAzG1EbuMgtRzdqdYAc1r7kdpuVF6tvQEJmmImFL8KreqX6F0Xee5PPxBRSNt6Kt7lRES91y6EW9L9CX6UTqv16QI6NHKi3qipxpoXXfr1/w6OMBVgbe7Su+QCZll96aNLtWjQ5LlTzcadI5QUjVqoqPXQiIi8bbkuvYt+9VdehF06QoJDdreulWqt2hFuW+9Uv1rxr5luAOaW5G4t7vt7p4/XxAHNuv4a60Xj4kuXj1KAc2t3C47799p8++AOB6rfjVPNsuuRLtV6LpvS5V49OkoZGO3lzl0a9K6f4+pVuCL0CrmhF7CozoYJp1jzcT3Mc9rcdy4L79WLUEfSVnRpFTU0fgxxRM9TWoZabhpGlgDgau8w2gExAACYgJiAmMKmIIgCgUS3XXuuuTWq6ijnqutsiLFn66h9qeIqNBLb+TUf4Yz2Ip/uyo1kuVeT8fzNZLp8CJn88xUYL8sbJ8Gzap/pvj/AM4GO/LWk8CxnfnX/rhGK/LTkWTD7VQ77ooodllN9G0nbkAT5YTfRtHd6Uv2giLlcj07rY9FJ7bwcKHW/Y8nfsmqX3zf+lCq1tDJiTvmT7o/q5Wf+MgocuSUv4HXwepn35FYE1nWFJ/VrRfD9ZBKPiX4WM3J/O96tKgk/KM+8CJLkxaMbcTc3J6IXFp3001O5zZo3Md5v2FRgubpUrIb7aVViSycpSIsSokCn3X5ID7qbyVAfdMfSA26IiIbPR8oA5yPltCjnI+W0A5yPltAmdj5bQJnY9v6FKgpM3yuoCxH+SBaj3+T1FRmU7nI5L8LtOpzUwhHZ2XJV2lV0kEj3SXOa2Nngxs8LCzgtTaVHuMSXInmQw6NgwirtgDgai8w6Bf0kEAAAAmJABnGhS55oHG25lrS2Y99NRxpWVbVudpuhiXY5U0vdta3tm8WMnntZlhb9XiTd7qdnIp2th/X77/eGmHP1FdV1P8AWKqon+tlfIVGHiARVAQilUBQFIAACgAAAAQBQIAzJZYu9SSR+g4Bpp5qhqNmkdJdqxaXdrhEXnVgvh6ENIoWNujW3/XSVC5sAYCCYPJAXB0ATCFTCEHAFHAA2AIbAA+BALWsQouazzgXNYoRkNjA2dHSTzvTMQyzeg0o9dyWsV9C1amoYiVDmo1G6L42rrvXlO6OIi6O9iQyrNahGloDhGmOboAC4lClVwFTpSCnPKRSLIpFcflRlAtnwrR0r/6ZK3fOTXDGvhdEjvA2Je7k39IR59+v0/65zlx7tPq8lc5VVVXSq612nVyVYgExAIRSgAggAAACgL6wBenR1gQAAAAFEAUCAQDp7Dt2lo41orVoY6+gVb2qrGOlhvvVyNx6HsVdOBXNVqqqo7U0o6Z7Pg9rW+BTexUQf/zA1s1hZFv/AKvbkkOjlYv+SUJS5EUto4/iy3YarBwu5cH0u6b0IST4O7X+bqKV/vGfyAYjshLdb4NK/wDKqn7zGkFC5FW/4pH72MoRcjbd8Rb7yL7QA+R9ueIt95F9ogtbkbbnicfvIyjIZkTbfNUzPyn+QDMiyDte/vlKz3n3YGfH8H1X4ddH7MLvtgbCn+D6L52tn7DGAbiDISy2d8bPN6Urv5M2BuoMl7KgRP6FTdjGBuoKCNiphaxrU2NMtNhHEjVuIM2NulLv9+kKyQHQB/8AsEaW85ugBSEFL3EViucRSEGrta047Lo5KmS5X8GJnLkVFwp5k1u8lFNR05Zlri8UqqqWrnlqJ3q+WR2Jx9DjyxFUIS8KQgCgKQQAgTj0EEVj+SoFDo5FciafM28ir2WNaUydyoax/wCRkOXkU+q69Nvpo6wLX+ja33TieTR6q9Fvpya+Wmqqbv0U8H1jHs/eQ65sYSIk728JEcaZXMlY/jKycAFAAAEAIEAIGRT1VTSPWSlqJqeTDhxxSPjdh9gDZ/KG2/pSt984B/lJbv0rWe8Af5TW/wDStUB3tDl7R7lp920tU+qwNzz42w4M57wy0z/l1Y3itd7uH70C5uW9i81We6j+8Au+Wth/jXuf8wFjcs7B52o9w4C35ZZP+MTfm8gFjcr8n/GpPcSgWplbk/49/cz/AHYFzcqcn/pBnu5vuyjKZlHYL1/+Sg/W+yBuaaopqpmcpp4qj6t7QM1pBcnrAcobQBozm6AQVOcFYz3kVUQJiTSQeP5S2stpVzmMd/RoFVkexy+HJ7XF5J9EXCUuXMqppFL5EbpUgxlqWgHPs2gWI5HaUW8gIUCCX6Qjd2dRS1DkipollnXYn7V8ExZbCqPzG4Vzsl8Dt6LI1jrpLQlVy81EuFvtP4XZwnkX+05fsvSq2Ef3XXUlj0NGxNz0sMfsJiPOnfa+zrg2SRaG6uo5N+5bh0AUy00M7HMmhZL6TUNI4+1cg7Ir2u3I34vqf7PvXuuCfbT7QufNZtK3j1tWDaFh1Gaq49Cr3KZnepPRdyvJPao3Fd7zLqZ1asGGXGh9DguAUCFAAgEAIBAIDEBA9OyPseyLRs1JaukbNUNlkY5yvk24m71HXcE8je7i6q16O1qrnX+l2K2DY8e9ZZ1L7tD4PKv9Wb7Omr04D8U2Z4hSe6YXvu9Q6q/wVrY9meIUvuml77vVOqr01a2LZXiFN7svk3eqnRV6ZHWFZPiFP2TXlXp49KpbAsjxKP8AWNeXez49JFydsnxRO3J9s15e4Z8an8CLk5ZPi7veyGvMvTxqS/Juy+ak96835l6eLS5J8tVYdpTbkmkidE/eeWzy+UetTZ2VvNth12Pb7FtJtqWbTVrURqvbv28mRu9ena/QaZbciiENiKNMcnVW4Kx5HEVjKZUmIDmsprT3DZz2Ru7vP3Nnr4bjcGJ/R5C53Gd3FjOlbrcEYE0mNyhWOAoF0D3YzI2ICudoIrYWRZtRalXHS07d85b3O8GNnhPccb7uiGbpVV2zxe4WZZNNZdO2CnYmL5yXw5HeUfm7753ze3VVCqLZuWOFjpJXI1jdKqv+ta7DlGOTprJhSVUz+9pmdHBw453N9DgRflDv1uTB3TPTTNqM9JPDwJocTpnYXL3xuFuba6PyTpgw6WNWva2SNyOY9Ec1U1Kh8urssMqXARWutWy6a1qOWjq2I5j2rhdxsf4L29LVOtNsqZ5sWQjZHGWj5xr7OlsyvnpJeHC9W38putrvaafqKre2Gbw7Idc5QVHVyKACgAQCAEAhBIpgGIPTchZanclVHDFC/u/hyOZwmegeP7QensneOfW+Lwe+d90ed8t9vxK85W+Kxe//APGaQM7V+KN9837JoKs1V4n/AHrAE3RUeJv95GEKtRN4nN2o/tFRFqZPE6j+7+2X/VC7q/FKrs/5zQoqLThpY87PDVRsRbr1j/zG4VZyYlZho4S262lraplRTY+BhfiTDwT19rCdcHm7icLJ/C7v4Pa7HDWUDlTePbMz2+EfS4PSjLRwCBpMRzdVTnEVivUiqlIKrwPJcqa7ddpvjavcqdM230vDU7wcJ/qcpKu9Nsta5VW8IqCikMr+DG93qUiisE6J3t3UA8LFx4lS7D/gQZpBU8g9iyHsttLZi1z++1S6PqmLc3tHge0bc7Xr7OvCt3TWnnvsaOtnxVFQ67FHRpE1jPBdVT8BzvQPrrcJld3PPs0yZp8Ub9P9YqZsPfP7NhUay0LQzMrqdsOfdHvX5xXNi9iNh3ppfPbezrNrF3PDPAx0MTZ2U8lPe58Ts4vDh5s5XVu1U3WnwvpMETCRXi3wi0rY7WpZmol8sG+9h3+Y932bL5TzN7H44/4cAeo88hQChQiBUAIBAJAQHIPR8gJd9aEP1T/3jyfaf7T0dj/W9QuPGekQ2hTTJShChSoUAGka61oN02dVRf2bndk7UfdcrftyeSn6B4zpskq3cVt02neTI6F3tFR71i0IZbMQOUc8cnVS9xFYyqRVblIMKsnSmpp57+9xu/YVHh80jpJHyOXfPcrj6XzsZ2oDFSBznoxt2+W5L9XrUcjrKCwoY2tkmRJpF26WpfsTj9Zz1lrq6aR00b1tHCxt8mbiZ04UT9JhvhorQraCHEynRk8nmvYnTfx+o1HTVmUouXc5XOVy3Iqret2hDfDnyiKArjKvfsnVb8SWbguw5hp+Z3P37Xu1fbrdFsPndHNVkOCqq4nuzbK5InxS+C2qg4DHekfZB8/5AqrK6feb6XBumn4M0csad/g5xpRRIxlVM1mZhrKne4r0kgkw8ubwDWbOGf8AS6CnoEjzecwdz73HGnc2HzzsdsGyODoYghF4eJ5dVjKu1sLFxNgjSJPSvvfd67vWi7EP0Hs+vWFWnPu1lrz/AOPJ3ktJWcaa+7TThwinpPiIVClAIAUQIIVAGICA5B2ORccc1pSxyY+8q5ML3N1OTknwb/7b7Nn+t6olBDyp/fSfaPEeoO4IucqPfSGkTcLOfqvfONIVaH8YqvelFe4/xqq7YQNySeOVPW0qF3LN47P+oUBaWo8el7DCnvItLVXKm7XXXL82w1kjyyugdS1c8Dl4D3ftPdplnW8i2OM1MMroZY5b99G9rzq5PoqzaptXSU9QxeHG0y02eIinKOcOLsxnuW8iqwKnActlTUZqy5W36ZVazX0m4MWPKFO7grIpALG1M7E3k0jfM5SBHzzScOV/aUCooBAQJeRXqeQ9sMzDrLncmJrldDeutF1tPC9o0fF2vW2dvw4PSceo8p9wTQxVEbopmNew2y1clmS3YGSslj8DPtxPj9CXhnftcsGwoqOKjiSNl733b6Ry3ucYnNpmnNpCKhFczlFlBBZNM9rHtdUvTC1L9R9e02vc+e+/ri8KqZ3VEr5XquJyqq+tT9HCGEXjSllqxTbBSgAKBCgAECAEIYimA6bJOpZS2zC+Rd46N7PXoX+U+LfQ+S+rafdevpaVJzn6jjw+l62ZvjGj579UdSZD8Y0fPtL1gbvo/GIyom7aPxiLtFwA3ZS8/F2iAbpp+KeLtoUHdEHPR9pACk0POx9ppUec5UwtZXpKxW3SMTUqa0PX2M/lvO3cfjc0fc+N7JkRXZ+y2wYt/A9zArumuMqs4gOce45OzGxayNECKHEHB5Yzdxp47/nF/dOtblY8+OrmrAQBAABAAQQCAZNPUSU0jZYnK17VRUuU5WQzdITwep2LlnBM2OC0FzciIndOJTxdxsJ/tvVp3cXdw1UUzUdDKyRvkuQ83WMovs9zIxEBCGIMWpr6SjYr6ieOP2kOkKppm4O2MuomI+GzW43XL3U9Lb+zvVfDdvPTeY1dZPWSumnkdI9yrxnsQrwebOebDVToyUqFABQAiBUAgEAIBAYg3eTrkbbND6a/uOPm3f2Ju+2+9F7lhTkpdxaD87lrz9XtcaGRjOS3qQ0Jgj5DeovKFWKLm2dlAK1p4Oaj7JUVLTU/Mx9lBmY6FWkpuYj7KFQq0VLzEfUazQu4KTmGAxUTWRZ87e6U7Dp3MdbjsorKgokglpmYGLvXHo7O+Vj4d1TGDNyIrcxaMlM5d7Mz9Zp9+v0fG9kaZaWBXOv1HJ2YxApFUPXQoHm+Vz9/S+2dnGxxZ0cyKBWAoAAAAAgEICFG8hyzqa0q2k7xUSx+0cp0V/g6Rts/JvIcsLai/CM56TUPm8Ch38y1l/Li2buHD2DH8OoXzbWFPlZbU6Liq1Z6B0hsqGPKuaKarqKhyummkkd5Tj6etwzY95tkt5QLyoUAAAogEAABAgFaysTWunzADPMAOeYBnWfVsp6ymqOFmpGvu9ZythnW3XLCb1hmW1nujRu55Dx/4dY9Pza/7rEyxs7kSk8C5fLqP8r7M2TdQ8G48uoyZW2Xtk7Kk8K9fKqH5U2Xzj+yTw7jyqjfKayudd2R4ly+TV+QplHZfPk8W5fIqWJlBZfjKDxrjvqN8e2Z4ywePcd1X5nS2bO8Zj6x0WnbW1NuVVFWWfIxk8bnt3zdJ9O2jZ2uG4lDrcZZdS6ltClnReDI39Y9h5j6Cp5c7GyTyUMNMwK5tzjk7KSKrIMaV2hSo83ytXf0vtnatym4425kAQBQFAAEIAUQghRCAgQAgQgN4UAiFAABQQABALUiasL5FkRHJwW3awjXux36yqXf8oC6BzmOvXTo4wFe3fKAuDoAmHoAZqadQGQlQ/kmQ+638kKbdj+SQPuxeQAd2eQMTk27PIAO7PJIH3WzkuKG3WzY4Bt1s8oB91M8oqNpRQNq1TA/uiuRGNu/1oNI97s1FZTQtdwmsQ5ttpeRXOnJ3VEFTgMWZdC+Yo4LKeFZYGOuvRjtK7LzpDXjVyno89vczRrQ7OSZ1CCZxu0KhEAoAAAgEAhBAIBAIAQIUQghQAIAQJo2oBYyPGxzkc3R+kqK7l0gUq0AYSqujjxORES9V1IEZLqCr8Xl7IC7hq/F5eyBNxVSfg8vZAG46nmJeyFDctRzMvYIgbnm5qTsgRYJObf2VChmn8h3Uv8AgBM2/kOAmFdi9QEw9H6AJh6AGu6AGwoEWNZeqJdfeB6RkpZSsduuVit0by8ivUYHaGnNtntcFabAc3VU5hBjvQKw5+CoHPV8KTRPjcnEppl5hV07oZXs2KdnBr3MKKVaAlztoExvAOedsIJnugA55vSgDZ1gQc43lIAcbeUBMTdqFExN2kExJ0dZRMbdpAM4zaUDOs2gLnm9IAz/AEADOvKBiftANy7QMqFqhHVWfk/JXNbI92bh/eCt43JKi0cLrUKsTI6mv4Lu0TJcGzoclqOkekmbTGDBvEoI+QnURTJZ8PIQmWq4p8X0/IQBVs+DkIEJ8Vw8hOoonxXT8hOoBVsqn5tvZCEdZNPyG9lAFWx6bm2dkGKt1i0vNM7JQi2HTc1H2SBPiKl5mPsgItg0fMx9lAJ8nqPmI+oIyoLCpIlTDBH2UC4t9Twqy5GomHUZabmJmogymga05upFArVEAxZI2gampptZRxtqWOs6q9qb80zrFyFRZ1VCq4onHRzxa58bm8Jq9RWeFWEBMICKwBVaAuAAYQgYAqYQiYQJhCphAmAqDgAOAA4AGwANhAbCBYjb10JevRpA6KyLGqKyViuY5kKKl6rovTYn8SHD1empEhibG1E0Ihl0Z8cBlpkZsirEZ0ANmwhs0lwUubAmbCGzQC5oAZoAZkCZviRCoXNXgDMgTMgTMdAU7YUAfNhF8bAMprdGsgtKNacnQAFUChyFGO5iEGHLAi8ReVa2WjZyU6ijVzWRDJfvG9RUxambJyB9+9NM4NXLky/TgeprNnBrZbBq2cQZYD7MrGfMuNHDHdSz80/qDKpYn8h3UAmBeSoAw9AAwhEwhRw9BUTD0AMjF5KgOkMujubuoC9lFVX94k7IGfFYdoSfNAbODJWqf3x6NIrcU+ScDe+q95M1wb6lsCkiu7g3qI06CCkbHdhajUMttiyIgyGtIp8JUPgAbCAcAAwgTCEQCAEAYQEwBBwhTYQBgAfAEDCAzWlFmEgtAJRqzk6IAAECqsIFTmgUOjCqnQ9AFeZTYBXmOgCpaVuwpwrWij5KdQFLrMg5tpUY77Gp1v3idRc0wULYFNyG9RexMFDsnKXkfoCdatcmqbm2lTrD5NU3NoDrOmTdNzTQda1MnqXmm9QXBlR2FTJ80zqGeqYaMtlkwc2zqJmuDJZZ0LdTU6kC4splIzkkF7adiakJyvC3NN2AWtj6CovbGBe1oFmEBsIQSggQAAECXBEAgAAgAAZoDAAIIBAcBgIBqTm6mCFCoAoCYSBMJQMIUuDoAXNgDAAM2AM0AMyBM0AM0BM0Ac0EHNgHNdBRZmgC2MofNhD5sA4ADhILGMKLkaEOUMAQCAQCEIoAKGIiAAogAAIDAQAAMEQAgEAgak5uokEKAQEohApVAghUS4gAEwhUwgPhKiYAFwEAwFEwEDIwobCAcIQ2EobCAcIBwlBwkDFQwBAJRACBMQExBAAgEvAgECJeBCggMAAAEECBTBEAcg1Bh1QCBUICAQAAACUAgYCBBAYAlAAgEAIBCDcA4BAJQACEQBiggQAAMUIQQAlBIhSiBBAUAgMBCggQIAVCIYoYBuID/9k=&quot;&gt;

&lt;p&gt;&lt;b&gt;Brand&lt;/b&gt;: Feitian, &lt;b&gt;Firmware&lt;/b&gt;: Feitian, &lt;b&gt;Chip&lt;/b&gt;: NXP, &lt;b&gt;Price&lt;/b&gt;: $16.99, &lt;b&gt;Connection&lt;/b&gt;: USB-A, NFC&lt;/p&gt;

&lt;p&gt;This one is very much like the Yubico, just a little fatter around the middle. Otherwise, it's also a sealed plastic body and capacitive touch sensor. The differences are a dollar and NFC support&amp;mdash;which should let it work with Android. However, I haven't tested this feature.

&lt;p&gt;I don't know what the opposite of a brown M&amp;amp;M is, but this security key is the only one here that has its metadata correctly registered with the &lt;a href=&quot;https://fidoalliance.org/mds/&quot;&gt;FIDO Metadata Service&lt;/a&gt;.&lt;/p&gt;

&lt;h4 style=&quot;clear: both; padding-top: 1.5em;&quot;&gt;U2F Zero&lt;/h4&gt;

&lt;img style=&quot;float: right; margin-left: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,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&quot;&gt;

&lt;p&gt;&lt;b&gt;Brand&lt;/b&gt;: U2F Zero, &lt;b&gt;Firmware&lt;/b&gt;: Conor Patrick, &lt;b&gt;Chip&lt;/b&gt;: Atmel, &lt;b&gt;Price&lt;/b&gt;: $8.99, &lt;b&gt;Connection&lt;/b&gt;: USB-A&lt;/p&gt;

&lt;p&gt;I did bend the rules a little to include this one: it wasn't immediately available when I did the main order from Amazon. But it's the only token on Amazon that has &lt;a href=&quot;https://github.com/conorpp/u2f-zero&quot;&gt;open source firmware&lt;/a&gt; (and hardware designs), and that was worth waiting for. It's also the cheapest of all the options here.&lt;/p&gt;

&lt;p&gt;Sadly, I have to report that I can't quite recommend it because, in my laptop (a Chromebook Pixel), it's not thick enough to sit in the USB port correctly: Since it only has the “tongue” of a USB connector, it can move around in the port a fair bit. That's true of the other tokens too, but with the U2F Zero, unless I hold it just right, it fails to make proper contact. Since operating it requires pressing the button, it's almost unusable in my laptop.&lt;/p&gt;

&lt;p&gt;However, it's fine with a couple of USB hubs that I have and in my desktop computer, so it might be fine for you. Depends how much you value the coolness factor of it being open-source.&lt;/p&gt;

&lt;h4 style=&quot;clear: both; padding-top: 1.5em;&quot;&gt;KEY-ID FIDO U2F Security Key&lt;/h4&gt;

&lt;img style=&quot;float: left; margin-right: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,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&quot;&gt;

&lt;p&gt;&lt;b&gt;Brand&lt;/b&gt;: KEY-ID, &lt;b&gt;Firmware&lt;/b&gt;: Feitian(?), &lt;b&gt;Chip&lt;/b&gt;: ?, &lt;b&gt;Price&lt;/b&gt;: $12.00, &lt;b&gt;Connection&lt;/b&gt;: USB-A&lt;/p&gt;

&lt;p&gt;I photographed this one while plugged in in order to show the most obvious issue with this device: everyone will know when you're using it! Whenever it's plugged in, the green LED on the end is lit up and, although the saturation in the photo exaggerates the situation a little, it really is too bright. When it's waiting for a touch, it starts flashing too.&lt;/p&gt;

&lt;p&gt;In addition, whenever I remove this from my desktop computer, the computer reboots. That suggests an electrical issue with the device itself&amp;mdash;it's probably shorting something that shouldn't be shorted, like the USB power pin to ground, for example.&lt;/p&gt;

&lt;p&gt;While this device is branded “KEY-ID”, I believe that the firmware is done by Feitian. There are similarities in certificate that match the Feitian device and, if you look up the FIDO certification, you find that Feitian registered a device called “KEY-ID FIDO® U2F Security Key”. Possibly Feitian decided against putting their brand on this.&lt;/p&gt;

&lt;p&gt;(Update: Brad Hill, at least, &lt;a href=&quot;https://twitter.com/hillbrad/status/898262322287792130&quot;&gt;reports&lt;/a&gt; no problems with these when using a MacBook.)&lt;/p&gt;

&lt;h4 style=&quot;clear: both; padding-top: 1.5em;&quot;&gt;HyperFIDO Mini&lt;/h4&gt;

&lt;img style=&quot;float: right; margin-left: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,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&quot;&gt;

&lt;p&gt;&lt;b&gt;Brand&lt;/b&gt;: HyperFIDO, &lt;b&gt;Firmware&lt;/b&gt;: Feitian(?), &lt;b&gt;Chip&lt;/b&gt;: ?, &lt;b&gt;Price&lt;/b&gt;: $13.75, &lt;b&gt;Connection&lt;/b&gt;: USB-A&lt;/p&gt;

&lt;p&gt;By observation, this is physically identical to the KEY-ID device, save for the colour. It has the same green LED too (see above).&lt;/p&gt;

&lt;p&gt;However, it manages to be worse. The KEY-ID device is highlighted in Amazon as a “new 2017 model”, and maybe this an example of the older model. Not only does it cause my computer to reliably reboot when removed (I suffered to bring you this review, dear reader), it also causes all devices on a USB hub to stop working when plugged in. When plugged into my laptop it does work&amp;mdash;as long as you hold it up in the USB socket. The only saving grace is that, when you aren't pressing it upwards, at least the green LED doesn't light up.&lt;/p&gt;

&lt;h4 style=&quot;clear: both; padding-top: 1.5em;&quot;&gt;HyperFIDO U2F Security Key&lt;/h4&gt;

&lt;img style=&quot;float: left; margin-right: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,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&quot;&gt;

&lt;p&gt;&lt;b&gt;Brand&lt;/b&gt;: HyperFIDO, &lt;b&gt;Firmware&lt;/b&gt;: Feitian(?), &lt;b&gt;Chip&lt;/b&gt;: ?, &lt;b&gt;Price&lt;/b&gt;: $9.98, &lt;b&gt;Connection&lt;/b&gt;: USB-A&lt;/p&gt;

&lt;p&gt;This HyperFIDO device is plastic so avoids the electrical issues of the KEY-ID and HyperFIDO Mini, above. It also avoids having an LED that can blind small children.&lt;/p&gt;

&lt;p&gt;However, at least on the one that I received, the plastic USB part is only &lt;i&gt;just&lt;/i&gt; small enough to fit into a USB socket. It takes a fair bit of force to insert and remove it. Also the end cap looks like it should be symmetrical and so able to go on either way around, but it doesn't quite work when upside down.&lt;/p&gt;

&lt;p&gt;Once inserted, pressing the button doesn't take too much force, but it's enough to make the device bend worryingly in the socket. It doesn't actually appear to be a problem, but it adds a touch of anxiety to each use. Overall, it's cheap and you'll know it.&lt;/p&gt;

&lt;div style=&quot;padding-top: 3.5em;&quot;&gt;&lt;/div&gt;

&lt;p&gt;Those are the devices that matched my initial criteria. But, sometimes, $20 isn't going to be enough I'm afraid. These are some other security keys that I've ended up with:&lt;/p&gt;

&lt;h4 style=&quot;clear: both; padding-top: 1.5em;&quot;&gt;Yubikey 4C&lt;/h4&gt;

&lt;img style=&quot;float: right; margin-left: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,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&quot;&gt;

&lt;p&gt;&lt;b&gt;Brand&lt;/b&gt;: Yubico, &lt;b&gt;Firmware&lt;/b&gt;: Yubico, &lt;b&gt;Chip&lt;/b&gt;: NXP?, &lt;b&gt;Price&lt;/b&gt;: $50 (direct from Yubico), &lt;b&gt;Connection&lt;/b&gt;: USB-C&lt;/p&gt;

&lt;p&gt;If you have a laptop that only has USB-C ports then a USB-A device is useless to you. Currently your only option is the Yubikey 4C at $50 a piece. This works well enough: the “button” is capacitive and triggers when you touch either of the contacts on the sides. The visual indicator is an LED that shines through the plastic at the very end.&lt;/p&gt;

&lt;p&gt;Note that, as a full Yubikey, it can do more than just being a security key. Yubico have &lt;a href=&quot;https://developers.yubico.com/&quot;&gt;a site&lt;/a&gt; for that.&lt;/p&gt;

&lt;p&gt;(Update: several people have mentioned in comments that this device wasn't very robust for them and had physical problems after some months. I can't confirm that, but there's always the option of a USB-A to USB-C adaptor. Just be careful to get one that'll work—the adaptor that I have doesn't hold “tongue-only” USB devices well enough.)&lt;/p&gt;

&lt;p&gt;Many people lacking USB-A ports will have a &lt;a href=&quot;https://developer.apple.com/macos/touch-bar/&quot;&gt;Touch Bar&lt;/a&gt;, which includes a fingerprint sensor and secure element. One might spy an alternative (and cheaper solution) there. GitHub have published &lt;a href=&quot;https://github.com/github/SoftU2F&quot;&gt;SoftU2F&lt;/a&gt; which does some of that but, from what I can tell, doesn't actually store keys in the secure element yet. However, in time, there might be a good answer for this.&lt;/p&gt;

&lt;p&gt;(Update: the behaviour of SoftU2F &lt;a href=&quot;https://github.com/github/SoftU2F/commit/4085c78c5c6028dd7b4cf994ba6747cdbfc444fe&quot;&gt;might be changing&lt;/a&gt;.)&lt;/p&gt;

&lt;h4 style=&quot;clear: both; padding-top: 1.5em;&quot;&gt;Yubikey Nano&lt;/h4&gt;

&lt;img style=&quot;float: left; margin-right: 2em; width: 20em;&quot; src=&quot;data:image/jpeg;base64,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&quot;&gt;

&lt;p&gt;&lt;b&gt;Brand&lt;/b&gt;: Yubico, &lt;b&gt;Firmware&lt;/b&gt;: Yubico, &lt;b&gt;Chip&lt;/b&gt;: NXP?, &lt;b&gt;Price&lt;/b&gt;: $50 (direct from Yubico), &lt;b&gt;Connection&lt;/b&gt;: USB-A&lt;/p&gt;

&lt;p&gt;Another $50 security key from Yubico, but I've included it because it's my preferred form-factor: this key is designed to sit semi-permanently inside the USB-A port. The edge is a capacitive touch sensor so you can trigger it by running your finger along it.&lt;/p&gt;

&lt;p&gt;It does mean that you give up a USB port, but it also means that you've never rummaging around to find it.&lt;/p&gt;

&lt;p&gt;(Note: newer Nanos look slightly different. See &lt;a href=&quot;https://www.yubico.com/product/yubikey-4-series/#yubikey-4-nano&quot;&gt;Yubico's page&lt;/a&gt; for a photo of the current design.)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Maybe Skip SHA-3</title>
   <link href="http://www.imperialviolet.org/2017/05/31/skipsha3.html"/>
   <updated>2017-05-31T00:00:00-04:00</updated>
   <id>http://www.imperialviolet.org/2017/05/31/skipsha3</id>
   <content type="html">&lt;p&gt;In 2005 and 2006, a series of significant results were published against SHA-1 [&lt;a href=&quot;https://people.csail.mit.edu/yiqun/SHA1AttackProceedingVersion.pdf&quot;&gt;1&lt;/a&gt;][&lt;a href=&quot;https://www.schneier.com/blog/archives/2005/08/new_cryptanalyt.html&quot;&gt;2&lt;/a&gt;][&lt;a href=&quot;https://link.springer.com/chapter/10.1007%2F11935230_1&quot;&gt;3&lt;/a&gt;]. These repeated break-throughs caused something of a crisis of faith as cryptographers questioned whether we knew how to build hash functions at all. After all, many hash functions from the 1990's had not aged well [&lt;a href=&quot;http://valerieaurora.org/hash.html&quot;&gt;1&lt;/a&gt;][&lt;a href=&quot;https://z.cash/technology/history-of-hash-function-attacks.html&quot;&gt;2&lt;/a&gt;].&lt;/p&gt;

&lt;p&gt;In the wake of this, NIST announced (&lt;a href=&quot;https://web.archive.org/web/20170120013445/http://csrc.nist.gov/groups/ST/hash/documents/FR_Notice_Nov07.pdf&quot;&gt;PDF&lt;/a&gt;) a competition to develop SHA-3 in order to hedge the risk of SHA-2 falling. In 2012, Keccak (pronounced &amp;ldquo;ket-chak&amp;rdquo;, I believe) won (&lt;a href=&quot;https://web.archive.org/web/20170114054411/http://csrc.nist.gov/groups/ST/hash/sha-3/sha-3_selection_announcement.pdf&quot;&gt;PDF&lt;/a&gt;) and became SHA-3. But the competition itself proved that we &lt;i&gt;do&lt;/i&gt; know how to build hash functions: the series of results in 2005 didn't extend to SHA-2 and the SHA-3 process produced a number of hash functions, all of which are secure as far as we can tell. Thus, by the time it existed, it was no longer clear that SHA-3 was needed. Yet there is a natural tendency to assume that SHA-3 must be better than SHA-2 because the number is bigger.&lt;/p&gt;

&lt;p&gt;As I've &lt;a href=&quot;https://www.imperialviolet.org/2016/05/16/agility.html&quot;&gt;mentioned before&lt;/a&gt;, diversity of cryptographic primitives is expensive. It contributes to the exponential number of combinations that need to be tested and hardened; it draws on limited developer resources as multiple platforms typically need separate, optimised code; and it contributes to code-size, which is a worry again in the mobile age. SHA-3 is also &lt;a href=&quot;http://bench.cr.yp.to/results-sha3.html&quot;&gt;slow&lt;/a&gt;, and is even slower than SHA-2 which is already a comparative laggard amongst crypto primitives.&lt;/p&gt;

&lt;p&gt;SHA-3 did introduce something useful: extendable output functions (XOFs), in the form of the SHAKE algorithms. In an XOF, input is hashed and then an (effectively) unlimited amount of output can be produced from it. It's convenient, although the same effect can be produced for a limited amount of output using &lt;a href=&quot;https://tools.ietf.org/html/rfc5869&quot;&gt;HKDF&lt;/a&gt;, or by hashing to a key and running ChaCha20 or AES-CTR.&lt;/p&gt;

&lt;p&gt;Thus I believe that SHA-3 should probably not be used. It offers no compelling advantage over SHA-2 and brings many costs. The only argument that I can credit is that it's nice to have a backup hash function, but both SHA-256 and SHA-512 are commonly supported and have different cores. So we already have two secure hash functions deployed and I don't think we need another.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://blake2.net/&quot;&gt;BLAKE2&lt;/a&gt; is another new, secure hash function, but it at least offers much improved speed over SHA-2. Speed is important. Not only does it mean less CPU time spent on cryptography, it means that cryptography can be economically deployed in places where it couldn't be before. BLAKE2, however, has too many versions: eight at the current count (BLAKE2(X)?[sb](p)?). In response to complaints about speed, the Keccak team now have &lt;a href=&quot;http://keccak.noekeon.org/KangarooTwelve.pdf&quot;&gt;KangarooTwelve and MarsupilamiFourteen&lt;/a&gt;, which have a vector-based design for better performance. (Although a vector-based design can &lt;a href=&quot;https://eprint.iacr.org/2012/476&quot;&gt;also be used to speed up SHA-2&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;So there are some interesting prospects for a future, faster replacement for SHA-2. But SHA-3 itself isn't one of them.&lt;/p&gt;

&lt;div style=&quot;padding-top:0.75cm&quot;&gt;&lt;/div&gt;

&lt;p&gt;Update: two points came up in discussion about this. Firstly, what about length-extension? SHA-2 has the property that simply hashing a secret with some data is not a secure MAC construction, that's why we have HMAC. SHA-3 does not have this problem.&lt;/p&gt;

&lt;p&gt;That is an advantage of SHA-3 because it means that people who don't know they need to use HMAC (with SHA-2) won't be caught out by it. Hopefully, in time, we end up with a hash function that has that property. But SHA-512/256, BLAKE2, K12, M14 and all the other SHA-3 candidates do have this property. In fact, it's implausible that any future hash function wouldn't.&lt;/p&gt;

&lt;p&gt;Overall, I don't feel that solving length-extension is a sufficiently pressing concern that we should all invest in SHA-3 now, rather than a hash function that hopefully comes with more advantages. If it is a major concern for you now, try SHA-512/256&amp;mdash;a member of the SHA-2 family.&lt;/p&gt;

&lt;p&gt;The second point was that SHA-3 is just the first step towards a permutation-based future: SHA-3 has an &lt;a href=&quot;https://en.wikipedia.org/wiki/Sponge_function&quot;&gt;elegant foundation&lt;/a&gt; that is suitable for implementing the full range of symmetric algorithms. In the future, a single optimised permutation function could be the basis of hashes, MACs, and AEADs, thus saving code size / die area and complexity. (E.g. &lt;a href=&quot;https://strobe.sourceforge.io/specs/&quot;&gt;STROBE&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;But skipping SHA-3 doesn't preclude any of that. SHA-3 is the hash standard itself, and even the Keccak team appear to be pushing K12 rather than SHA-3 now. It seems unlikely that a full set of primitives built around the Keccak permutation would choose to use the SHA-3 parameters at this point.&lt;/p&gt;

&lt;p&gt;Indeed, SHA-3 adoption might inhibit that ecosystem by pushing it towards those bad parameters. (There was &lt;a href=&quot;https://en.wikipedia.org/wiki/SHA-3#NIST.27s_Controversial_Decisions_Regarding_Changing_Capacity&quot;&gt;a thing&lt;/a&gt; about NIST tweaking the parameters at the end of the process if you want some background.)&lt;/p&gt;

&lt;p&gt;One might argue that SHA-3 should be supported because you believe that it'll result in hardware implementations of the permutation and you hope that they'll be flexible enough to support what you &lt;i&gt;really&lt;/i&gt; want to do with it. I'm not sure that would be the best approach even if your goal was to move to a permutation-based world. Instead I would nail down the whole family of primitives as you would like to see it and try to push small chips, where area is a major concern, to adopt it. Even then, the hash function in the family probably wouldn't be exactly SHA-3, but more like K12.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>AES-GCM-SIV</title>
   <link href="http://www.imperialviolet.org/2017/05/14/aesgcmsiv.html"/>
   <updated>2017-05-14T00:00:00-04:00</updated>
   <id>http://www.imperialviolet.org/2017/05/14/aesgcmsiv</id>
   <content type="html">&lt;p&gt;AEADs combine encryption and authentication in a way that provides the properties that people generally expect when they “encrypt” something. This is great because, historically, handing people a block cipher and a hash function has resulted in a lot of bad and broken constructions. Standardising AEADs avoids this.&lt;/p&gt;

&lt;p&gt;Common AEADs have a sharp edge though: you must &lt;i&gt;never&lt;/i&gt; encrypt two different messages with the same key and nonce. Doing so generally violates the confidentiality of the two messages and &lt;a href=&quot;https://eprint.iacr.org/2017/239.pdf&quot;&gt;might break much more&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are some situations where obtaining a unique nonce is easy, for example in transport security where a simple counter can be used. (Due to poor design in TLS 1.2, some TLS implementations &lt;a href=&quot;https://eprint.iacr.org/2016/475.pdf&quot;&gt;still managed to duplicate nonces&lt;/a&gt;. The answer there is to do what ChaCha20-Poly1305 does in TLS 1.2, and what everything does in TLS 1.3: make the nonce implicit. That means that any mistakes result in your code not interoperating, which should be noticed.)&lt;/p&gt;

&lt;p&gt;But there are situations where ensuring nonce uniqueness is not trivial, generally where multiple machines are independently encrypting with the same key. A system for distributing nonces is complex and hard to have confidence in. Generating nonces randomly and depending on statistical uniqueness is reasonable, but only if the space of nonces is large enough. XSalsa20-Poly1305 (&lt;a href=&quot;https://cr.yp.to/snuffle/xsalsa-20081128.pdf&quot;&gt;paper&lt;/a&gt;, &lt;a href=&quot;https://download.libsodium.org/doc/secret-key_cryptography/authenticated_encryption.html&quot;&gt;code&lt;/a&gt;) has a 192-bit nonce and good performance across a range of CPUs. In many situations, using that with random nonces is a sound choice.&lt;/p&gt;

&lt;p&gt;However, lots of chips now have hardware support for the AES-GCM AEAD, meaning that its performance and power use is hard to beat. Also, a 192-bit nonce results in a ~40% increase in overhead vs the 96-bit nonce of AES-GCM, which is undesirable in some contexts. (Overhead consists of the nonce and tag, thus the increase from 96- to 192-bit nonces is not 100%.)&lt;/p&gt;

&lt;p&gt;But using random nonces in a 96-bit space isn't that comfortable. NIST recommends a limit of 2&lt;sup&gt;32&lt;/sup&gt; messages when using random nonces with AES-GCM which, while quite large, is often not large enough not to have to worry about. Because of this, Shay Gueron, Yehuda Lindell and I have been working on AES-GCM-SIV (&lt;a href=&quot;https://eprint.iacr.org/2017/168.pdf&quot;&gt;paper&lt;/a&gt;, &lt;a href=&quot;https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-05&quot;&gt;spec&lt;/a&gt;): AES-GCM with some forgiveness. It uses the same primitives as AES-GCM, and thus enjoys the same hardware support, but it doesn't fail catastrophically if you repeat a nonce. Thus you can use random, 96-bit nonces with a far larger number of messages, or withstand a glitch in your nonce distribution scheme. (For precise numbers, see section 5.3 of &lt;a href=&quot;https://eprint.iacr.org/2017/168.pdf&quot;&gt;the paper&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;There is a performance cost: AES-GCM-SIV encryption runs at about 70% the speed of AES-GCM, although &lt;i&gt;de&lt;/i&gt;cryption runs at the same speed. (Measured using current BoringSSL on an Intel Skylake chip with 8KiB messages.) But, in any situation where you don't have a watertight argument for nonce uniqueness, that might be pretty cheap compared to the alternative.&lt;/p&gt;

&lt;p&gt;For example, both TLS and QUIC need to encrypt small messages at the server that can be decrypted by other servers. For TLS, these messages are the session tickets and, in QUIC, they are the source-address tokens. This is an example of a situation where many servers are independently encrypting with the same key and so Google's QUIC implementation is in the process of switching to using AES-GCM-SIV for source-address tokens. (Our TLS implementation may switch too in the future, although that will be more difficult because of existing APIs.)&lt;/p&gt;

&lt;p&gt;AEADs that can withstand nonce duplication are called “nonce-misuse resistant” and that name appears to have caused some people to believe that they are infinitely resistant. I.e. that an unlimited number of messages can be encrypted with a fixed nonce with no loss in security. That is not the case, and the term wasn't defined that way originally by &lt;a href=&quot;https://www.iacr.org/archive/eurocrypt2006/40040377/40040377.pdf&quot;&gt;Rogaway and Shrimpton&lt;/a&gt; (nor does their SIV mode have that property). So it's important to emphasise that AES-GCM-SIV (and nonce-misuse resistant modes in general) are not a magic invulnerability shield. Figure four and section five of the &lt;a href=&quot;https://eprint.iacr.org/2017/168.pdf&quot;&gt;the paper&lt;/a&gt; give precise bounds but, if in doubt, consider AES-GCM-SIV to be a safety net for accidental nonce duplication and otherwise treat it like a traditional AEAD.&lt;/p&gt;

&lt;p&gt;AES-GCM-SIV &lt;a href=&quot;https://commondatastorage.googleapis.com/chromium-boringssl-docs/aead.h.html#EVP_aead_aes_256_gcm_siv&quot;&gt;is supported&lt;/a&gt; in BoringSSL now and, while one may not want to use the whole of BoringSSL, the &lt;a href=&quot;https://boringssl.googlesource.com/boringssl/+/8726d8fe0c2dff7901e32651e994bbd1ab924607/crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl&quot;&gt;core assembly&lt;/a&gt; is ISC licensed. Also, Shay has published reference, assembly and intrinsics &lt;a href=&quot;https://github.com/Shay-Gueron/AES-GCM-SIV&quot;&gt;versions&lt;/a&gt; for those who think AES-GCM-SIV might be useful to them.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>CFI directives in assembly files</title>
   <link href="http://www.imperialviolet.org/2017/01/18/cfi.html"/>
   <updated>2017-01-18T00:00:00-05:00</updated>
   <id>http://www.imperialviolet.org/2017/01/18/cfi</id>
   <content type="html">&lt;p&gt;(This post uses x86-64 for illustration throughout. The fundamentals are similar for other platforms but will need some translation that I don't cover here.)&lt;/p&gt;

&lt;p&gt;Despite compilers getting better over time, it's still the case that hand-written assembly can be worthwhile for certain hot-spots. Sometimes there are special CPU instructions for the thing that you're trying to do, sometimes you &lt;a href=&quot;http://link.springer.com/chapter/10.1007/978-3-319-48965-0_36&quot;&gt;need detailed control of the resulting code&lt;/a&gt; and, to some extent, it remains possible for &lt;i&gt;some&lt;/i&gt; people to out-optimise a compiler.&lt;/p&gt;

&lt;p&gt;But hand-written assembly doesn't automatically get some of the things that the compiler generates for normal code, such as debugging information. Perhaps your assembly code never crashes (although any function that takes a pointer can suffer from bugs in other code) but you probably still care about accurate profiling information. In order for debuggers to walk up the stack in a core file, or for profilers to correctly account for CPU time, they need be able to unwind call frames.&lt;/p&gt;

&lt;p&gt;Unwinding used to be easy as every function would have a standard prologue:&lt;/p&gt;

&lt;pre&gt;push rbp
mov rbp, rsp&lt;/pre&gt;

&lt;p&gt;This would make the stack look like this (remember that stacks grow &lt;i&gt;downwards&lt;/i&gt; in memory):&lt;/p&gt;

&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; version=&quot;1.2&quot; width=&quot;326.873&quot; height=&quot;356.576&quot;&gt;&lt;defs&gt;&lt;marker orient=&quot;auto&quot; id=&quot;c&quot; overflow=&quot;visible&quot;&gt;&lt;path d=&quot;M0 4.52v-9.04&quot; fill=&quot;none&quot; stroke=&quot;#000&quot; stroke-width=&quot;.8pt&quot;/&gt;&lt;/marker&gt;&lt;marker orient=&quot;auto&quot; id=&quot;d&quot; overflow=&quot;visible&quot;&gt;&lt;path d=&quot;M-4 0l-2 2 7-2-7-2 2 2z&quot; fill-rule=&quot;evenodd&quot; stroke=&quot;#000&quot; stroke-width=&quot;.4pt&quot;/&gt;&lt;/marker&gt;&lt;linearGradient id=&quot;a&quot;&gt;&lt;stop offset=&quot;0&quot; stop-color=&quot;#fbfbfc&quot; stop-opacity=&quot;0&quot;/&gt;&lt;stop offset=&quot;1&quot; stop-color=&quot;#fbfbfc&quot;/&gt;&lt;/linearGradient&gt;&lt;linearGradient x1=&quot;281.833&quot; y1=&quot;214.062&quot; x2=&quot;282.085&quot; y2=&quot;152.695&quot; id=&quot;b&quot; xlink:href=&quot;#a&quot; gradientUnits=&quot;userSpaceOnUse&quot; gradientTransform=&quot;matrix(.80886 0 0 .6277 67.565 77.66)&quot;/&gt;&lt;linearGradient x1=&quot;281.833&quot; y1=&quot;214.062&quot; x2=&quot;282.085&quot; y2=&quot;152.695&quot; id=&quot;e&quot; xlink:href=&quot;#a&quot; gradientUnits=&quot;userSpaceOnUse&quot; gradientTransform=&quot;matrix(.81994 0 0 .6277 63.443 -537.595)&quot;/&gt;&lt;/defs&gt;&lt;path fill=&quot;none&quot; stroke=&quot;#000&quot; d=&quot;M28.335 30.545h111.96V99.74H28.336z&quot;/&gt;&lt;path fill=&quot;none&quot; stroke=&quot;#000&quot; d=&quot;M28.335 99.235h111.96v69.195H28.336z&quot;/&gt;&lt;path fill=&quot;none&quot; stroke=&quot;#000&quot; d=&quot;M28.335 167.926h111.96v69.195H28.336z&quot;/&gt;&lt;path fill=&quot;none&quot; stroke=&quot;#000&quot; d=&quot;M28.335 236.616h111.96v69.195H28.336z&quot;/&gt;&lt;path fill=&quot;url(#b)&quot; d=&quot;M220.971 160.903h147.482v51.518H220.971z&quot; transform=&quot;translate(-196.424 -138.944)&quot;/&gt;&lt;text x=&quot;-232.062&quot; y=&quot;206.617&quot; transform=&quot;rotate(-90 -167.684 28.74)&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot; font-size=&quot;14&quot; font-weight=&quot;400&quot; letter-spacing=&quot;0&quot; word-spacing=&quot;0&quot; font-family=&quot;Arial&quot;&gt;&lt;tspan x=&quot;-232.062&quot; y=&quot;206.617&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot;&gt;Caller&amp;apos;s stack&lt;/tspan&gt;&lt;/text&gt;&lt;path d=&quot;M216.173 233.128v-92.934&quot; fill=&quot;none&quot; stroke=&quot;#000&quot; marker-start=&quot;url(#c)&quot; marker-end=&quot;url(#d)&quot; transform=&quot;translate(-196.424 -138.944)&quot;/&gt;&lt;path d=&quot;M372.241 238.684h-30.304&quot; fill=&quot;none&quot; stroke=&quot;#000&quot; marker-end=&quot;url(#d)&quot; transform=&quot;translate(-196.424 -138.944)&quot;/&gt;&lt;text x=&quot;375.272&quot; y=&quot;242.725&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot; font-size=&quot;14&quot; font-weight=&quot;400&quot; letter-spacing=&quot;0&quot; word-spacing=&quot;0&quot; font-family=&quot;Arial&quot; transform=&quot;translate(-196.424 -138.944)&quot;&gt;&lt;tspan x=&quot;375.272&quot; y=&quot;242.725&quot;&gt;RSP value before CALL&lt;/tspan&gt;&lt;/text&gt;&lt;path d=&quot;M372.241 307.375h-30.304&quot; fill=&quot;none&quot; stroke=&quot;#000&quot; marker-end=&quot;url(#d)&quot; transform=&quot;translate(-196.424 -138.944)&quot;/&gt;&lt;text x=&quot;375.272&quot; y=&quot;311.415&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot; font-size=&quot;14&quot; font-weight=&quot;400&quot; letter-spacing=&quot;0&quot; word-spacing=&quot;0&quot; font-family=&quot;Arial&quot; transform=&quot;translate(-196.424 -138.944)&quot;&gt;&lt;tspan x=&quot;375.272&quot; y=&quot;311.415&quot;&gt;RSP at function entry&lt;/tspan&gt;&lt;/text&gt;&lt;text x=&quot;243.447&quot; y=&quot;346.771&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot; font-size=&quot;14&quot; font-weight=&quot;400&quot; letter-spacing=&quot;0&quot; word-spacing=&quot;0&quot; font-family=&quot;Arial&quot; transform=&quot;translate(-196.424 -138.944)&quot;&gt;&lt;tspan x=&quot;243.447&quot; y=&quot;346.771&quot;&gt;Caller&amp;apos;s RBP&lt;/tspan&gt;&lt;/text&gt;&lt;path transform=&quot;matrix(1 0 0 -1 -196.424 -138.944)&quot; fill=&quot;url(#e)&quot; d=&quot;M218.951-454.352h149.503v51.518H218.951z&quot;/&gt;&lt;path d=&quot;M216.173 375.315v92.934&quot; fill=&quot;none&quot; stroke=&quot;#000&quot; marker-start=&quot;url(#c)&quot; marker-end=&quot;url(#d)&quot; transform=&quot;translate(-196.424 -138.944)&quot;/&gt;&lt;text x=&quot;-496.217&quot; y=&quot;206.617&quot; transform=&quot;rotate(-90 -167.684 28.74)&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot; font-size=&quot;14&quot; font-weight=&quot;400&quot; letter-spacing=&quot;0&quot; word-spacing=&quot;0&quot; font-family=&quot;Arial&quot;&gt;&lt;tspan x=&quot;-496.217&quot; y=&quot;206.617&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot;&gt;Callee&amp;apos;s local variables&lt;/tspan&gt;&lt;/text&gt;&lt;text x=&quot;243.447&quot; y=&quot;261.918&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot; font-size=&quot;14&quot; font-weight=&quot;400&quot; letter-spacing=&quot;0&quot; word-spacing=&quot;0&quot; font-family=&quot;Arial&quot; transform=&quot;translate(-196.424 -138.944)&quot;&gt;&lt;tspan x=&quot;243.447&quot; y=&quot;261.918&quot;&gt;Saved RIP&lt;/tspan&gt;&lt;/text&gt;&lt;text x=&quot;234.86&quot; y=&quot;288.687&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot; font-size=&quot;11&quot; font-weight=&quot;400&quot; letter-spacing=&quot;0&quot; word-spacing=&quot;0&quot; font-family=&quot;Arial&quot; transform=&quot;translate(-196.424 -138.944)&quot;&gt;&lt;tspan x=&quot;234.86&quot; y=&quot;288.687&quot;&gt;(pushed by CALL)&lt;/tspan&gt;&lt;/text&gt;&lt;path d=&quot;M372.241 375.055h-30.304&quot; fill=&quot;none&quot; stroke=&quot;#000&quot; marker-end=&quot;url(#d)&quot; transform=&quot;translate(-196.424 -138.944)&quot;/&gt;&lt;text x=&quot;375.272&quot; y=&quot;379.095&quot; style=&quot;text-align:start;line-height:125%;-inkscape-font-specification:Arial&quot; font-size=&quot;14&quot; font-weight=&quot;400&quot; letter-spacing=&quot;0&quot; word-spacing=&quot;0&quot; font-family=&quot;Arial&quot; transform=&quot;translate(-196.424 -138.944)&quot;&gt;&lt;tspan x=&quot;375.272&quot; y=&quot;379.095&quot;&gt;RBP always points here&lt;/tspan&gt;&lt;/text&gt;&lt;/svg&gt;

&lt;p&gt;So, upon entry to a function, the &lt;kbd&gt;CALL&lt;/kbd&gt; instruction that jumped to the function in question will have pushed the previous program counter (from the &lt;kbd&gt;RIP&lt;/kbd&gt; register) onto the stack. Then the function prologue saves the current value of &lt;kbd&gt;RBP&lt;/kbd&gt; on the stack and copies the current value of the stack pointer into &lt;kbd&gt;RBP&lt;/kbd&gt;. From this point until the function is complete, &lt;kbd&gt;RBP&lt;/kbd&gt; won't be touched.&lt;/p&gt;

&lt;p&gt;This makes stack unwinding easy because &lt;kbd&gt;RBP&lt;/kbd&gt; always points to the call frame for the current function. That gets you the saved address of the parent call and the saved value of its &lt;kbd&gt;RBP&lt;/kbd&gt; and so on.&lt;/p&gt;

&lt;p&gt;The problems with this scheme are that a) the function prologue can be excessive for small functions and b) we would like to be able to use &lt;kbd&gt;RBP&lt;/kbd&gt; as a general purpose register to avoid spills. Which is why the &lt;a href=&quot;https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html&quot;&gt;GCC documentation&lt;/a&gt; says that &amp;ldquo;-O also turns on -fomit-frame-pointer on machines where doing so does not interfere with debugging&amp;rdquo;. This means that you can't depend on being able to unwind stacks like this. A process can be comprised of various shared libraries, any of which might be compiled with optimisations.&lt;/p&gt;

&lt;p&gt;To be able to unwind the stack without depending on this convention, additional debugging tables are needed. The compiler will generate these automatically (when asked) for code that it generates, but it's something that we need to worry about when writing assembly functions ourselves if we want profilers and debuggers to work.&lt;/p&gt;

&lt;p&gt;The reference for the assembly directives that we'll need is &lt;a href=&quot;https://sourceware.org/binutils/docs/as/CFI-directives.html&quot;&gt;here&lt;/a&gt;, but they are very lightly documented. You can understand more by reading the &lt;a href=&quot;http://www.dwarfstd.org/doc/DWARF4.pdf&quot;&gt;DWARF&lt;/a&gt; spec, which documents the data that is being generated. Specifically see sections 6.4 and D.6. But I'll try to tie the two together in this post.&lt;/p&gt;

&lt;p&gt;The tables that we need the assembler to emit for us are called Call Frame Information (CFI). (Not to be confused with Control Flow Integrity, which is very different.) Based on that name, all the assembler directives begin with &lt;kbd&gt;.cfi_&lt;/kbd&gt;.&lt;/p&gt;

&lt;p&gt;Next we need to define the Canonical Frame Address (CFA). This is the value of the stack pointer just before the &lt;kbd&gt;CALL&lt;/kbd&gt; instruction in the parent function. In the diagram above, it's the value indicated by &amp;ldquo;RSP value before CALL&amp;rdquo;. Our first task will be to define data that allows the CFA to be calculated for any given instruction.&lt;/p&gt;

&lt;p&gt;The CFI tables allow the CFA to be expressed as a register value plus an offset. For example, immediately upon function entry the CFA is &lt;kbd&gt;RSP&lt;/kbd&gt; + 8. (The eight byte offset is because the &lt;kbd&gt;CALL&lt;/kbd&gt; instruction will have pushed the previous &lt;kbd&gt;RIP&lt;/kbd&gt; on the stack.)&lt;/p&gt;

&lt;p&gt;As the function executes, however, the expression will probably change. If nothing else, after pushing a value onto the stack we would need to increase the offset.&lt;/p&gt;

&lt;p&gt;So one design for the CFI table would be to store a (register, offset) pair for every instruction. Conceptually that's what we do but, to save space, only changes from instruction to instruction are stored.&lt;/p&gt;

&lt;p&gt;It's time for an example, so here's a trivial assembly function that includes CFI directives and a running commentary.&lt;/p&gt;

&lt;pre&gt;  .globl  square
  .type   square,@function
  .hidden square
square:&lt;/pre&gt;

&lt;p&gt;This is a standard preamble for a function that's unrelated to CFI. Your assembly code should already be full of this.&lt;/p&gt;

&lt;pre&gt;  .cfi_startproc&lt;/pre&gt;

&lt;p&gt;Our first CFI directive. This is needed at the start of every annotated function. It causes a new CFI table for this function to be initialised.&lt;/p&gt;

&lt;pre&gt;  .cfi_def_cfa rsp, 8&lt;/pre&gt;

&lt;p&gt;This is defining the CFA expression as a register plus offset. One of the things that you'll see compilers do is express the registers as numbers rather than names. But, at least with GAS, you can write names. (I've included a table of DWARF register numbers and names below in case you need it.)&lt;/p&gt;

&lt;p&gt;Getting back to the directive, this is just specifying what I discussed above: on entry to a function, the CFA is at &lt;kbd&gt;RSP&lt;/kbd&gt; + 8.&lt;/p&gt;

&lt;pre&gt;  push    rbp
  .cfi_def_cfa rsp, 16&lt;/pre&gt;

&lt;p&gt;After pushing something to the stack, the value of &lt;kbd&gt;RSP&lt;/kbd&gt; will have changed so we need to update the CFA expression. It's now &lt;kbd&gt;RSP&lt;/kbd&gt; + 16, to account for the eight bytes we pushed.&lt;/p&gt;

&lt;pre&gt;  mov     rbp, rsp
  .cfi_def_cfa rbp, 16&lt;/pre&gt;

&lt;p&gt;This function happens to have a standard prologue, so we'll save the frame pointer in &lt;kbd&gt;RBP&lt;/kbd&gt;, following the old convention. Thus, for the rest of the function we can define the CFA as &lt;kbd&gt;RBP&lt;/kbd&gt; + 16 and manipulate the stack without having to worry about it again.&lt;/p&gt;

&lt;pre&gt;  mov     DWORD PTR [rbp-4], edi
  mov     eax, DWORD PTR [rbp-4]
  imul    eax, DWORD PTR [rbp-4]
  pop     rbp
  .cfi_def_cfa rsp, 8&lt;/pre&gt;

&lt;p&gt;We're getting ready to return from this function and, after restoring &lt;kbd&gt;RBP&lt;/kbd&gt; from the stack, the old CFA expression is invalid because the value of &lt;kbd&gt;RBP&lt;/KBD&gt; has changed. So we define it as &lt;kbd&gt;RSP&lt;/kbd&gt; + 8 again.&lt;/p&gt;

&lt;pre&gt;  ret
  .cfi_endproc&lt;/pre&gt;

&lt;p&gt;At the end of the function we need to trigger the CFI table to be emitted. (It's an error if a CFI table is left open at the end of the file.)&lt;/p&gt;

&lt;p&gt;The CFI tables for an object file can be dumped with &lt;kbd&gt;objdump -W&lt;/kbd&gt; and, if you do that for the example above, you'll see &lt;i&gt;two&lt;/i&gt; tables: something called a CIE and something called an FDE.&lt;/p&gt;

&lt;p&gt;The CIE (Common Information Entry) table contains information common to all functions and it's worth taking a look at it:&lt;/p&gt;

&lt;pre&gt;&amp;hellip; CIE
  Version:         1
  Augmentation:    &quot;zR&quot;
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Augmentation data:     1b

  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8&lt;/pre&gt;

&lt;p&gt;You can ignore everything until the &lt;kbd&gt;DW_CFA_&amp;hellip;&lt;/kbd&gt; lines at the end. They define CFI directives that are common to all functions (that reference this CIE). The first is saying that the CFA is at &lt;kbd&gt;RSP&lt;/kbd&gt; + 8, which is what we had already defined at function entry. This means that &lt;i&gt;you don't need a CFI directive at the beginning of the function&lt;/i&gt;. Basically &lt;kbd&gt;RSP&lt;/kbd&gt; + 8 is already the default.&lt;/p&gt;

&lt;p&gt;The second directive is something that we'll get to when we discuss saving registers.&lt;/p&gt;

&lt;p&gt;If we look at the FDE (Frame Description Entry) for the example function that we defined, we see that it reflects the CFI directives from the assembly:&lt;/p&gt;

&lt;pre&gt;&amp;hellip; FDE cie=&amp;hellip;
  DW_CFA_advance_loc: 1 to 0000000000000001
  DW_CFA_def_cfa: r7 (rsp) ofs 16
  DW_CFA_advance_loc: 3 to 0000000000000004
  DW_CFA_def_cfa: r6 (rbp) ofs 16
  DW_CFA_advance_loc: 11 to 000000000000000f
  DW_CFA_def_cfa: r7 (rsp) ofs 8&lt;/pre&gt;

&lt;p&gt;The FDE describes the range of instructions that it's valid for and is a series of operations to either update the CFA expression, or to skip over the next &lt;i&gt;n&lt;/i&gt; bytes of instructions. Fairly obvious.&lt;/p&gt;


&lt;h4&gt;Optimisations for CFA directives&lt;/h4&gt;

&lt;p&gt;There are some shortcuts when writing CFA directives:&lt;/p&gt;

&lt;p&gt;Firstly, you can update just the offset, or just the register, with &lt;kbd&gt;cfi_def_cfa_offset&lt;/kbd&gt; and &lt;kbd&gt;cfi_def_cfa_register&lt;/kbd&gt; respectively. This not only saves typing in the source file, it saves bytes in the table too.&lt;/p&gt;

&lt;p&gt;Secondly, you can update the offset with a relative value using &lt;kbd&gt;cfi_adjust_cfa_offset&lt;/kbd&gt;. This is useful when pushing lots of values to the stack as the offset will increase by eight each time.&lt;/p&gt;

&lt;p&gt;Here's the example from above, but using these directives and omitting the first directive that we don't need because of the CIE:&lt;/p&gt;

&lt;pre&gt;  .globl  square
  .type   square,@function
  .hidden square
square:
  .cfi_startproc
  push    rbp
  .cfi_adjust_cfa_offset 8
  mov     rbp, rsp
  .cfi_def_cfa_register rbp
  mov     DWORD PTR [rbp-4], edi
  mov     eax, DWORD PTR [rbp-4]
  imul    eax, DWORD PTR [rbp-4]
  pop     rbp
  .cfi_def_cfa rsp, 8
  ret
  .cfi_endproc&lt;/pre&gt;


&lt;h4&gt;Saving registers&lt;/h4&gt;

&lt;p&gt;Consider a profiler that is unwinding the stack after a profiling signal. It calculates the CFA of the active function and, from that, finds the parent function. Now it needs to calculate the parent function's CFA and, from the CFI tables, discovers that it's related to &lt;kbd&gt;RBX&lt;/kbd&gt;. Since &lt;kbd&gt;RBX&lt;/kbd&gt; is a callee-saved register, that's reasonable, but the active function might have stomped &lt;kbd&gt;RBX&lt;/kbd&gt;. So, in order for the unwinding to proceed it needs a way to find where the active function saved the old value of &lt;kbd&gt;RBX&lt;/kbd&gt;. So there are more CFI directives that let you document where registers have been saved.&lt;/p&gt;

&lt;p&gt;Registers can either be saved at an offset from the CFA (i.e. on the stack), or in another register. Most of the time they'll be saved on the stack though because, if you had a caller-saved register to spare, you would be using it first.&lt;/p&gt;

&lt;p&gt;To indicate that a register is saved on the stack, use &lt;kbd&gt;cfi_offset&lt;/kbd&gt;. In the same example as above (see the stack diagram at the top) the caller's &lt;kbd&gt;RBP&lt;/kbd&gt; is saved at CFA - 16 bytes. So, with saved registers annotated too, it would start like this:&lt;/p&gt;

&lt;pre&gt;square:
  .cfi_startproc
  push    rbp
  .cfi_adjust_cfa_offset 8
  .cfi_offset rbp, -16&lt;/pre&gt;

&lt;p&gt;If you need to save a register in another register for some reason, see &lt;a href=&quot;https://sourceware.org/binutils/docs/as/CFI-directives.html&quot;&gt;the documentation&lt;/a&gt; for &lt;kbd&gt;cfi_register&lt;/kbd&gt;.&lt;/p&gt;

&lt;p&gt;If you get all of that correct then your debugger should be able to unwind crashes correctly, and your profiler should be able to avoid recording lots of detached functions. However, I'm afraid that I don't know of a better way to test this than to zero &lt;kbd&gt;RBP&lt;/kbd&gt;, add a crash in the assembly code, and check whether GBD can go &lt;kbd&gt;up&lt;/kbd&gt; correctly.&lt;/p&gt;

&lt;p&gt;(None of this works for Windows. But Per Vognsen, via Twitter, notes that there are &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms235241.aspx&quot;&gt;similar directives&lt;/a&gt; in MASM.)&lt;/p&gt;

&lt;h4&gt;CFI expressions&lt;/h4&gt;

&lt;p&gt;New in &lt;a href=&quot;http://www.dwarfstd.org/doc/Dwarf3.pdf&quot;&gt;version three&lt;/a&gt; of the DWARF standard are CFI Expressions. These define a stack machine for calculating the CFA value and can be useful when your stack frame is non-standard (which is fairly common in assembly code). However, there's no assembler support for them that I've been able to find, so one has to use &lt;tt&gt;cfi_escape&lt;/tt&gt; and provide the raw DWARF data in a .s file. As an example, see &lt;a href=&quot;https://gitlab-beta.engr.illinois.edu/ejclark2/linux/commit/eab9e6137f237681a04649e786cc4d942bedd6d1&quot;&gt;this kernel patch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since there's no assembler support, you'll need to read section 2.5 of the &lt;a href=&quot;http://www.dwarfstd.org/doc/Dwarf3.pdf&quot;&gt;standard&lt;/a&gt;, then search for &lt;kbd&gt;DW_CFA_def_cfa_expression&lt;/kbd&gt; and, perhaps, search for &lt;kbd&gt;cfi_directive&lt;/kbd&gt; in OpenSSL's &lt;a href=&quot;https://github.com/openssl/openssl/blob/master/crypto/perlasm/x86_64-xlate.pl&quot;&gt;perlasm script for x86-64&lt;/a&gt; and the places in OpenSSL where that is used. Good luck.&lt;/p&gt;

&lt;p&gt;(I suggest testing by adding some instructions that write to NULL in the assembly code and checking that gdb can correctly step up the stack and that &lt;kbd&gt;info reg&lt;/kbd&gt; shows the correct values for callee-saved registers in the parent frame.)&lt;/p&gt;

&lt;h4&gt;CFI register numbers&lt;/h4&gt;

&lt;p&gt;In case you need to use or read the raw register numbers, here they are for a few architectures:&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Register number&lt;/th&gt;&lt;th&gt;x86-64&lt;/th&gt;&lt;th&gt;x86&lt;/th&gt;&lt;th&gt;ARM&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;RAX&lt;/td&gt;&lt;td&gt;EAX&lt;/td&gt;&lt;td&gt;r0&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;RDX&lt;/td&gt;&lt;td&gt;ECX&lt;/td&gt;&lt;td&gt;r1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;RCX&lt;/td&gt;&lt;td&gt;EDX&lt;/td&gt;&lt;td&gt;r2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;RBX&lt;/td&gt;&lt;td&gt;EBX&lt;/td&gt;&lt;td&gt;r3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;RSI&lt;/td&gt;&lt;td&gt;ESP&lt;/td&gt; (may be EBP on MacOS)&lt;td&gt;r4&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;RDI&lt;/td&gt;&lt;td&gt;EBP&lt;/td&gt; (may be ESP on MacOS)&lt;td&gt;r5&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;RBP&lt;/td&gt;&lt;td&gt;ESI&lt;/td&gt;&lt;td&gt;r6&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;RSP&lt;/td&gt;&lt;td&gt;EDI&lt;/td&gt;&lt;td&gt;r7&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;R8&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;r8&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;R9&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;r9&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;R10&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;r10&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;R11&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;r11&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;R12&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;r12&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;R13&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;r13&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;14&lt;/td&gt;&lt;td&gt;R14&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;r14&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;R15&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;r15&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;RIP&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;(x86 values taken from page 25 of &lt;a href=&quot;https://www.uclibc.org/docs/psABI-i386.pdf&quot;&gt;this doc&lt;/a&gt;. x86-64 values from page 57 of &lt;a href=&quot;https://www.uclibc.org/docs/psABI-x86_64.pdf&quot;&gt;this doc&lt;/a&gt;. ARM taken from page 7 of &lt;a href=&quot;http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf&quot;&gt;this doc&lt;/a&gt;.)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>RISC-V assembly</title>
   <link href="http://www.imperialviolet.org/2016/12/31/riscv.html"/>
   <updated>2016-12-31T00:00:00-05:00</updated>
   <id>http://www.imperialviolet.org/2016/12/31/riscv</id>
   <content type="html">&lt;p&gt;RISC-V is a new, open instruction set. Fabrice Bellard wrote a Javascript emulator for it that boots Linux &lt;a href=&quot;http://bellard.org/riscvemu/js/&quot;&gt;here&lt;/a&gt; (&lt;a href=&quot;http://bellard.org/riscvemu/&quot;&gt;more info&lt;/a&gt;). I happen to have just gotten a physical chip that implements it too (one of &lt;a href=&quot;https://www.crowdsupply.com/sifive/hifive1&quot;&gt;these&lt;/a&gt;) and what's cool is that you can get the source code to the chip &lt;a href=&quot;https://github.com/sifive/freedom&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The full, user-level instruction set is &lt;a href=&quot;https://content.riscv.org/wp-content/uploads/2016/06/riscv-spec-v2.1.pdf&quot;&gt;documented&lt;/a&gt; but there's a lot of information in there. I wanted a brief summary of things that I could keep in mind when reading disassembly. This blog post is just a dump of my notes; it's probably not very useful for most people! It also leaves out a lot of things that come up less frequently. There's also an unofficial &lt;a href=&quot;http://www.cl.cam.ac.uk/teaching/1617/ECAD+Arch/files/docs/RISCVGreenCardv8-20151013.pdf&quot;&gt;reference card&lt;/a&gt; which is good, but still aimed a little low for me.&lt;/p&gt;

&lt;p&gt;RISC-V is little-endian and comes in 32 and 64 bit flavours. In keeping with the RISC-V documents, the flavour (either 32 or 64) is called &lt;kbd&gt;XLEN&lt;/kbd&gt; below in the few places where it matters.&lt;/p&gt;

&lt;p&gt;For both, &lt;kbd&gt;int&lt;/kbd&gt; is 32 bits. Pointers and &lt;kbd&gt;long&lt;/kbd&gt; are the native register size. Signed values are always sign extended in a larger register and unsigned 8- and 16-bit values are zero extended. But unsigned 32-bit values are sign-extended. Everything has natural alignment in structs and the like, but alignment isn't required by the hardware.&lt;/p&gt;

&lt;p&gt;The stack grows downwards and is 16-byte aligned upon entry to a function.&lt;/p&gt;

&lt;p&gt;Instructions are all 32 bits and 32-bit aligned. There is a compressed-instruction extension that adds 16-bit instructions and changes the required alignment of all instructions to just 16 bits. Unlike Thumb on ARM, RISC-V compressed instructions are just a short-hand for some 32-bit instruction and 16- and 32-bit instructions can be mixed freely.&lt;/p&gt;

&lt;p&gt;There are 31 general purpose registers called x1–x31. Register x0 drops all writes and always reads as zero. Each register is given an alias too, which describes their conventional use:&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Register&lt;/th&gt;&lt;th&gt;Alias&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Saved by&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x0&lt;/td&gt;&lt;td&gt;zero&lt;/td&gt;&lt;td&gt;Zero&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x1&lt;/td&gt;&lt;td&gt;ra&lt;/td&gt;&lt;td&gt;Return address&lt;/td&gt;&lt;td&gt;Caller&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x2&lt;/td&gt;&lt;td&gt;sp&lt;/td&gt;&lt;td&gt;Stack pointer&lt;/td&gt;&lt;td&gt;Callee&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x3&lt;/td&gt;&lt;td&gt;gp&lt;/td&gt;&lt;td&gt;Global pointer&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x4&lt;/td&gt;&lt;td&gt;tp&lt;/td&gt;&lt;td&gt;Thread pointer&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x5–7&lt;/td&gt;&lt;td&gt;t0–2&lt;/td&gt;&lt;td&gt;Temporary&lt;/td&gt;&lt;td&gt;Caller&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x8&lt;/td&gt;&lt;td&gt;s0/fp&lt;/td&gt;&lt;td&gt;Saved register / frame pointer&lt;/td&gt;&lt;td&gt;Callee&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x9&lt;/td&gt;&lt;td&gt;s1&lt;/td&gt;&lt;td&gt;Saved register&lt;/td&gt;&lt;td&gt;Callee&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x10–17&lt;/td&gt;&lt;td&gt;a1–a7&lt;/td&gt;&lt;td&gt;Arguments and return values&lt;/td&gt;&lt;td&gt;Caller&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x18–27&lt;/td&gt;&lt;td&gt;s2–11&lt;/td&gt;&lt;td&gt;Saved registers&lt;/td&gt;&lt;td&gt;Callee&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;x28–31&lt;/td&gt;&lt;td&gt;t3–6&lt;/td&gt;&lt;td&gt;Temporary&lt;/td&gt;&lt;td&gt;Caller&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;There are two types of immediates, which will be written as ‘I’ and ‘J’. Type ‘I’ intermediates are 12-bit, signed values and type ‘J’ are 20-bit, signed values. They are always sign-extended to the width of a register before use.&lt;/p&gt;

&lt;h4&gt;Arithmetic&lt;/h4&gt;

&lt;p&gt;There's no carry flag, instead one has to use a comparison instruction on the result in order to get the carry in a register.&lt;/p&gt;

&lt;p&gt;A &lt;kbd&gt;U&lt;/kbd&gt; suffix indicates an unsigned operation. Note that the multiplication and division instructions are part of the ‘M’ extension, but I expect most chips to have them.&lt;/p&gt;

&lt;div&gt;
&lt;style scoped&gt;
td { vertical-align: top; }
&lt;/style&gt;

&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;Instruction&lt;/th&gt;&lt;th&gt;Effect&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;ADD&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1&amp;nbsp;+&amp;nbsp;src2&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SUB&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1&amp;nbsp;-&amp;nbsp;src2&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;ADDI&amp;nbsp;dest,src1,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1&amp;nbsp;+&amp;nbsp;I&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;MUL&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1&amp;nbsp;×&amp;nbsp;src2&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;MULH[|U|SH]&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;(src1&amp;nbsp;×&amp;nbsp;src2) &amp;gt;&amp;gt; XLEN&lt;/td&gt;&lt;td&gt;This returns the high word of the multiplication result for signed×signed, unsigned×unsigned or signed×unsigned, respectively&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;DIV[U]&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1/src2&lt;/td&gt;&lt;td&gt;There's no trap on divide-by-zero, rather special values are returned. (See documentation.)&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;REM[U]&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1%src2&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h4&gt;Bitwise&lt;/h4&gt;

&lt;p&gt;These should all be obvious:&lt;/p&gt;

&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;Instruction&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;AND dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;OR dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;XOR dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;ANDI dest,src1,I&lt;/kbd&gt;&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;ORI dest,src1,I&lt;/kbd&gt;&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;XORI dest,src1,I&lt;/kbd&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h4&gt;Shifts&lt;/h4&gt;

&lt;p&gt;Instructions here are Shift [Left|Right] [Logical|Arithmetic].&lt;/p&gt;

&lt;p&gt;Note that only the minimal number of bits are read from the shift count. So shifting by the width of the register doesn't zero it, it does nothing.&lt;/p&gt;

&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;Instruction&lt;/th&gt;&lt;th&gt;Effect&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SLL&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1 &amp;lt;&amp;lt; src2%XLEN&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SRL&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1 &amp;gt;&amp;gt; src2%XLEN&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SRA&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1 &amp;gt;&amp;gt; src2%XLEN&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SLLI&amp;nbsp;dest,src1,0‥31/63&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1 &amp;lt;&amp;lt; I&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SRLI&amp;nbsp;dest,src1,0‥31/63&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1 &amp;gt;&amp;gt; I&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SRAI&amp;nbsp;dest,src1,0‥31/63&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1 &amp;gt;&amp;gt; I&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h4&gt;Comparisons&lt;/h4&gt;

&lt;p&gt;These instructions set the destination register to one or zero depending on whether the relation is true or not.&lt;/p&gt;

&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;Instruction&lt;/th&gt;&lt;th&gt;Effect&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SLT&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1&amp;lt;src2&lt;/td&gt;&lt;td&gt;(signed compare)&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SLTU&amp;nbsp;dest,src1,src2&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1&amp;lt;src2&lt;/td&gt;&lt;td&gt;(unsigned compare)&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SLTI&amp;nbsp;dest,src1,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1&amp;lt;I&lt;/td&gt;&lt;td&gt;(signed compare)&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;SLTIU&amp;nbsp;dest,src1,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;src1&amp;lt;I&lt;/td&gt;&lt;td&gt;(unsigned compare, but remember that the immediate is sign-extended first)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h4&gt;Control flow&lt;/h4&gt;

&lt;p&gt;The JAL[R] instructions write the address of the next instruction to the destination register for the subsequent return. This can be &lt;kbd&gt;x0&lt;/kbd&gt; if you don't care.&lt;/p&gt;

&lt;p&gt;Many instructions here take an immediate that is doubled before use. That's because no instruction (even with compressed instructions) can ever start on an odd address. However, when you write the value in assembly you write the actual value; the assembler will halve it when encoding.&lt;/p&gt;

&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;Instruction&lt;/th&gt;&lt;th&gt;Effect&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;JAL&amp;nbsp;dest,J&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;pc+2/4; pc+=2*J&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;JALR&amp;nbsp;dest,src,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;pc+2/4; pc=src1+(I&amp;amp;~1)&lt;/td&gt;&lt;td&gt;Note that the least-significant bit of the address is ignored&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;BEQ&amp;nbsp;src1,src2,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;if src1==src2, pc+=2*I&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;BNE&amp;nbsp;src1,src2,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;if src1!=src2, pc+=2*I&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;BLT&amp;nbsp;src1,src2,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;if src1&amp;lt;src2, pc+=2*I&lt;/td&gt;&lt;td&gt;signed compare&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;BLTU&amp;nbsp;src1,src2,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;if src1&amp;lt;src2, pc+=2*I&lt;/td&gt;&lt;td&gt;unsigned compare&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;BGE&amp;nbsp;src1,src2,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;if src1&amp;gt;=src2, pc+=2*I&lt;/td&gt;&lt;td&gt;signed compare&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;BGEU&amp;nbsp;src1,src2,I&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;if src1&amp;gt;=src2, pc+=2*I&lt;/td&gt;&lt;td&gt;unsigned compare&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h4&gt;Memory&lt;/h4&gt;

&lt;p&gt;The suffix on these instructions denotes the size of the value read or written: ‘D’ = double-word (64 bits), ‘W’ = word (32 bits), ‘H’ = half-word (16 bits), ´B’ = byte. Reading and writing 64-bit values only works on 64-bit systems, and &lt;kbd&gt;LWU&lt;/kbd&gt; only exists on 64-bit systems because it's the same as &lt;kbd&gt;LW&lt;/kbd&gt; otherwise.&lt;/p&gt;

&lt;p&gt;Alignment is not required, but might be faster. Also note that there's no consistent direction of data flow in the textual form of the assembly: the register always comes first.&lt;/p&gt;

&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;Instruction&lt;/th&gt;&lt;th&gt;Effect&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;L[D|W|H|B]&amp;nbsp;dest,I(src)&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;*(src + I)&lt;/td&gt;&lt;td&gt;result is sign extended&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;L[D|W|H|B]U&amp;nbsp;dest,I(src)&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;*(src + I)&lt;/td&gt;&lt;td&gt;result is zero extended&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;S[D|W|H|B]&amp;nbsp;src1,I(src2)&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;*(src2 + I)&amp;nbsp;=&amp;nbsp;src1&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h4&gt;Other&lt;/h4&gt;

&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;Instruction&lt;/th&gt;&lt;th&gt;Effect&lt;/th&gt;&lt;th&gt;Notes&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;LUI&amp;nbsp;dest,J&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;J&amp;lt;&amp;lt;12&lt;/td&gt;&lt;td&gt;“Load Upper Immediate”. The result is sign extended on 64-bit.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;kbd&gt;AUIPC&amp;nbsp;dest,J&lt;/kbd&gt;&lt;/td&gt;&lt;td&gt;dest&amp;nbsp;=&amp;nbsp;pc + J&amp;lt;&amp;lt;12&lt;/td&gt;&lt;td&gt;“Add Upper Immediate to PC”. The result of the shift is sign-extended on 64-bit before the addition.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h4&gt;W instructions&lt;/h4&gt;

&lt;p&gt;These instructions only exist on 64-bit and are copies of the same instruction without the ‘W’ suffix, except that they operate only on the lower 32 bits of the registers and, when writing the result, sign-extend to 64 bits. They are &lt;kbd&gt;ADDW&lt;/kbd&gt;, &lt;kbd&gt;SUBW&lt;/kbd&gt;, &lt;kbd&gt;ADDIW&lt;/kbd&gt;, &lt;kbd&gt;DIV[U]W&lt;/kbd&gt;, &lt;kbd&gt;REM[U]W&lt;/kbd&gt;, &lt;kbd&gt;S[L|R]LW&lt;/kbd&gt;, &lt;kbd&gt;SRAW&lt;/kbd&gt;, &lt;kbd&gt;S[L|R]LIW&lt;/kbd&gt; and &lt;kbd&gt;SRAIW&lt;/kbd&gt;&lt;/p&gt;

&lt;h4&gt;Pseudo-instructions&lt;/h4&gt;

&lt;p&gt;For clarity, there are also a number of pseudo-instructions defined. These are just syntactic sugar for one of the primitive instructions, above. Here's a handful of the more useful ones:&lt;/p&gt;

&lt;table&gt;
	&lt;tr&gt;&lt;th&gt;Pseudo-instruction&lt;/th&gt;&lt;th&gt;Translation&lt;/th&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;nop&lt;/td&gt;&lt;td&gt;addi x0,x0,0&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;mv dest,src&lt;/td&gt;&lt;td&gt;addi dest,src,0&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;not dest,src&lt;/td&gt;&lt;td&gt;xor dest,src,-1&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;seqz dest,src&lt;/td&gt;&lt;td&gt;sltiu dest,src,1&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;snez dest,src&lt;/td&gt;&lt;td&gt;sltu dest,x0,src&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;j J&lt;/td&gt;&lt;td&gt;jal x0,J&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;ret&lt;/td&gt;&lt;td&gt;jalr x0,x1,0&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;call offset&lt;/td&gt;&lt;td&gt;auipc x6, offset &amp;gt;&amp;gt; 12; jalr x1,x6,offset &amp;amp; 0xfff&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;li dest,value&lt;/td&gt;&lt;td&gt;(&lt;i&gt;possibly several instructions to load arbitrary value&lt;/i&gt;)&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;la dest,symbol&lt;/td&gt;&lt;td&gt;auipc dest, symbol &amp;gt;&amp;gt; 12; addi dest,dest,offset &amp;amp; 0xfff&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;l[d|w|h|b] dest,symbol&lt;/td&gt;&lt;td&gt;auipc dest, symbol &amp;gt;&amp;gt; 12; l&lt;i&gt;x&lt;/i&gt; dest,offset &amp;amp; 0xfff(dest)&lt;/td&gt;&lt;/tr&gt;
	&lt;tr&gt;&lt;td&gt;s[d|w|h|b] src,symbol&lt;/td&gt;&lt;td&gt;auipc dest, symbol &amp;gt;&amp;gt; 12; s&lt;i&gt;x&lt;/i&gt; dest,offset &amp;amp; 0xfff(dest)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Note that the instructions that expand to two instructions where the first is &lt;kbd&gt;AUIPC&lt;/kbd&gt; aren't quite as simple as they appear. Since the 12-bit immediate in the second instruction is sign extended, it could end up negative. If that happens, the J immediate for &lt;kbd&gt;AUIPC&lt;/kbd&gt; needs to be one greater and then you can reach the value by subtracting from there.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>CECPQ1 results</title>
   <link href="http://www.imperialviolet.org/2016/11/28/cecpq1.html"/>
   <updated>2016-11-28T00:00:00-05:00</updated>
   <id>http://www.imperialviolet.org/2016/11/28/cecpq1</id>
   <content type="html">&lt;p&gt;In July my colleague, Matt Braithwaite, &lt;a href=&quot;https://security.googleblog.com/2016/07/experimenting-with-post-quantum.html&quot;&gt;announced&lt;/a&gt; that Chrome and Google would be experimenting with a post-quantum key-agreement primitive in TLS. One should read the &lt;a href=&quot;https://security.googleblog.com/2016/07/experimenting-with-post-quantum.html&quot;&gt;original announcement&lt;/a&gt; for details, but we had two goals for this experiment:&lt;/p&gt;

&lt;p&gt;Firstly we wanted to direct cryptoanalytic attention at the family of Ring Learning-with-Errors (RLWE) problems. The algorithm that we used, &lt;a href=&quot;https://eprint.iacr.org/2015/1092&quot;&gt;NewHope&lt;/a&gt;, is part of this family and appeared to be the most promising when we selected one at the end of 2015.&lt;/p&gt;

&lt;p&gt;It's very difficult to know whether we had any impact here, but it's good to see the recent publication and withdrawal of &lt;a href=&quot;https://arxiv.org/abs/1611.06999&quot;&gt;a paper&lt;/a&gt; describing a quantum attack on a fundamental lattice problem. Although the algorithm contained an error, it still shows that capable people are testing these new foundations.&lt;/p&gt;

&lt;p&gt;Our second goal was to measure the feasibility of deploying post-quantum key-agreement in TLS by combining NewHope with an existing key-agreement (X25519). We called the combination CECPQ1.&lt;/p&gt;

&lt;p&gt;TLS key agreements have never been so large and we expected a latency impact from the extra network traffic. Also, any incompatibilities with middleboxes can take years to sort out, so it's best to discover them as early as possible.&lt;/p&gt;

&lt;p&gt;Here the results are more concrete: we did not find any unexpected impediment to deploying something like NewHope. There were no reported problems caused by enabling it.&lt;/p&gt;

&lt;p&gt;Although the median connection latency only increased by a millisecond, the latency for the slowest 5% increased by 20ms and, for the slowest 1%, by 150ms. Since NewHope is computationally inexpensive, we're assuming that this is caused entirely by the increased message sizes. Since connection latencies compound on the web (because subresource discovery is delayed), the data requirement of NewHope is moderately expensive for people on slower connections.&lt;/p&gt;

&lt;p&gt;None the less, if the need arose, it would be practical to quickly deploy NewHope in TLS 1.2. (TLS 1.3 makes things a little more complex and we did not test with CECPQ1 with it.)&lt;/p&gt;

&lt;p&gt;At this point the experiment is concluded. We do not want to promote CECPQ1 as a de-facto standard and so a future Chrome update will disable CECPQ1 support. It's likely that TLS will want a post-quantum key-agreement in the future but a more multilateral approach is preferable for something intended to be more than an experiment.&lt;/p&gt;
</content>
 </entry>
 

</feed>
