## Book Review: Throne of the Crescent Moon by Saladin Ahmed After reading [Saladin Ahmed's collection of short stories]( ), I was keen to read more. This book is fantastic! Fantasy books usually seem to be swords and dragons, set in a generic European country. Crescent Moon is scimitars and sorcery, and set in a mythical Middle-Eastern country. The writing is sublime. It feels like an ancient epic, translated a hundred years ago with archaic language left intact. It'll make good use of your eReader's dictionary to discover words like "ensorcelled". Amongst all the blood and magic, are literary gems like: > Zamia’s little laugh cut through him like a sword poisoned with pure happiness. But, perhaps the best thing about this, is that it reads like the *end* of a trilogy. The characters are all established, there's little exposition about the fantasy-word, the environment is richly textured. Above all, the characters are *tired*! It is a fast-paced, exciting, and entertaining book. Perfect for fantasy-lovers who fancy something a bit different from endless Game-of-Thrones rip-offs. #BookReview
## Towards a test-suite for TOTP codes Because I'm a massive nerd, I *actually try to read* specification documents. As I've ranted *ad nauseam* before, the current TOTP<a href="#fn:totp" class="footnote-ref" title="Time-based One Time Passwords. Not the TV show you remember from your youth, grandad." role="doc-noteref">0</a> spec is [irresponsibly obsolete]( ). The three major implementations of the spec - [Google]( ), [Apple]( ), and [Yubico]( ) - all subtly disagree on how it should be implemented. Every other MFA app has their own idiosyncratic variants. The [official RFC is infuriatingly vague]( ). That's no good for a security specification. Multiple implementations are great, multiple interpretations are not. So I've [built a nascent test suite]( ) - you can use it to see if your favourite app can correctly implement the TOTP standard. []( ) Please do contribute tests and / or feedback. Here's what the standard *actually* says - see if you can find apps which don't implement it correctly.## [Background](#background )Time-based One Time Passwords are based on HOTP - HMAC-Based One-Time Password. HOTP uses counters; a new password is regularly generated. TOTP uses time as the counter. At the time of writing this post, there have been about 1,740,800,000 seconds since the UNIX Epoc. So a TOTP with an period of 30 seconds is on counter (1,740,800,000 ➗ 30) = 58,026,666. Every 30 seconds, that counter increments by one.### [Number of digits](#number-of-digits )How many digits should your 2FA token have? Google says 6 or 8. YubiCo graciously allows 7. Why those limits? Who knows!? [The HOTP specification gives an *example* of 6 digits]( ). The example generates a code of 0x50ef7f19 which, in decimal, is 1357872921. It then takes the last 6 digits to produce the code 872921. The TOTP RFC say: > Basically, the output of the HMAC-SHA-1 calculation is truncated to obtain user-friendly values > [> 1.2. Background]( ) But doesn't say how far to truncate. There's nothing I can see in the spec that *prevents* an implementer using all 10. The HOTP spec, however, *does* place a minimum requirement - but no maximum: > Implementations MUST extract a 6-digit code at a minimum and possibly 7 and 8-digit code. Depending on security requirements, Digit = 7 or more SHOULD be considered in order to extract a longer HOTP value. > [> RFC 4226 - 5.3. Generating an HOTP Value]( ) (As a minor point, the first digit is restricted to 0-2, so being 10 digits long isn't significantly stronger than 9 digits.) Is a 4 digit code acceptable? The security might be weaker, but the usability is greater. Most apps will allow a *one* digit code to be returned. If no digits are specified, what should the default be?### [Algorithm](#algorithm )The given algorithm in the HOTP spec is SHA-1. > In order to create the HOTP value, we will use the HMAC-SHA-1 algorithm > [> RFC 4226 - 5.2. Description]( ) As we now know, SHA-1 has some fundamental weaknesses. The spec comments (perhaps somewhat naïvely) about SHA-1: > The new attacks on SHA-1 have no impact on the security of HMAC-SHA-1. > [> RFC 4226 - B.2. HMAC-SHA-1 Status]( ) I daresay that's accurate. But the TOTP authors disagree and allow a for some different algorithms to be used. The specification for HMAC says: > HMAC can be used with > *any*> iterative cryptographic hash function, e.g., MD5, SHA-1 [Emphasis added] > [> RFC 2104 - HMAC: Keyed-Hashing for Message Authentication]( ) So most TOTP implementation allow SHA-1, SHA-256, and SHA-512. > TOTP implementations MAY use HMAC-SHA-256 or HMAC-SHA-512 functions […] instead of the HMAC-SHA-1 function that has been specified for the HOTP computation > [> RFC 6238 - TOTP: Time-Based One-Time Password Algorithm]( ) But the HOTP spec goes on to say: > Current candidates for such hash functions include SHA-1, MD5, RIPEMD-128/160. These different realizations of HMAC will be denoted by HMAC-SHA1, HMAC-MD5, HMAC-RIPEMD > [> RFC 2104 - Introduction]( ) So, should your TOTP app be able to handle an MD5 HMAC, or even SHA3-384? Will it? If no algorithm is specified, what should the default be?### [Period](#period )As discussed, this is what increments the counter for HOTP. The [Google Spec]( ) says: > The period parameter defines a period that a TOTP code will be valid for, in seconds. The default value is 30. The TOTP RFC says: > We RECOMMEND a default time-step size of 30 seconds > [> 5.2. Validation and Time-Step Size]( ) It doesn't make sense to have a negative number of second. But what about one second? What about a thousand? Lots of apps artificially restrict TOTP codes to 15, 30, or 60 seconds. But there's no specification to define a maximum or minimum value. A user with mobility difficulties or on a high-latency connection probably wants a 5 minute validity period. Conversely, machine-to-machine communication can probably be done with a single-second (or lower) time period.### [Secret](#secret )Google says the secret is > an arbitrary key value encoded in Base32 according to RFC 3548. The padding specified in RFC 3548 section 2.2 is not required and should be omitted. Whereas Apple says it is: > An arbitrary key value encoded in Base32. Secrets should be at least 160 bits. Can a shared secret be a single character? What about a thousand? Will padding characters cause a secret to be rejected or can they be safely stripped?### [Label](#label )The label allows you to have multiple codes for the same service. For example Big Bank:Personal Account and Big Bank:Family Savings. The Google spec is slightly confusing: > The issuer prefix and account name should be separated by a literal or url-encoded colon, and optional spaces may precede the account name. Neither issuer nor account name may themselves contain a colon. What happens if they are *not* URl encoded? What about Matrix accounts which use a colon in their account name? Why are spaces allowed to precede the account name? Is there any practical limit to the length of these strings? If no label is specified, what should the default be?### [Issuer](#issuer )Google says this parameter is: > **Strongly Recommended**> The issuer parameter is a string value indicating the provider or service this account is associated with, URL-encoded according to RFC 3986. If the issuer parameter is absent, issuer information may be taken from the issuer prefix of the label. If both issuer parameter and issuer label prefix are present, they should be equal. Apple merely says: > The domain of the site or app. The password manager uses this field to suggest credentials when setting up a new code generator. Yubico equivocates with > The issuer parameter is recommended, but it can be absent. Also, the issuer parameter and issuer string in label should be equal. If it isn't a domain, will Apple reject it? What happens if the issuer and the label don't match?## [Next Steps](#next-steps )<li>If you're a user, <a href="https://codeberg.org/edent/TOTP_Test_Suite">please contribute tests</a> or give feedback.</li><li>If you're a developer, please check your app conforms to the specification.</li><li>If you're from Google, Apple, Yubico, or another security company - wanna help me write up a proper RFC so this doesn't cause issues in the future?</li><li id="fn:totp" role="doc-endnote"><p>Time-based One Time Passwords. Not the TV show you remember from your youth, grandad.&nbsp;<a href="#fnref:totp" class="footnote-backref" role="doc-backlink">↩︎</a></p></li> #2fa #CyberSecurity #HTOP #MFA #OpenSource #totp
## Why are QR Codes with capital letters smaller than QR codes with lower-case letters? Take a look at these two QR codes. Scan them if you like, I promise there's nothing dodgy in them.     Left is upper-case HTTPS://EDENT.TEL/ and right is lower-case You can clearly see that the one on the left is a "smaller" QR as it has fewer bits of data in it. Both go to the same URl, the only difference is the casing. What's going on? Your first thought might be that there's a different level of error-correction. QR codes can have increasing levels of redundancy in order to make sure they can be scanned when damaged. But, in this case, they both have **L**ow error correction. The smaller code is "Type 1" - it is 21px * 21px. The larger is "Type 2" with 25px * 25px. The [official specification]( ) describes the versions in more details. The smaller code should be able to hold 25 alphanumeric character. But is only 18 characters long. So why is it bumped into a larger code? Using a decoder like [ZXING]( ) it is possible to see the raw bytes of each code. UPPER<code class="_" itemprop="text">20 93 1a a6 54 63 dd 28 &nbsp; <br>35 1b 50 e9 3b dc 00 ec<br>11 ec 11</code> lower:<code class="_" itemprop="text">41 26 87 47 47 07 33 a2 &nbsp; <br>f2 f6 56 46 56 e7 42 e7<br>46 56 c2 f0 ec 11 ec 11 &nbsp; <br>ec 11 ec 11 ec 11 ec 11<br>ec 11</code> You might have noticed that they both end with the same sequence: ec 11 Those are "padding bytes" because the data needs to completely fill the QR code. But - hang on! - not only does the UPPER one safely contain the text, it also has some spare padding? The answer lies in the first couple of bytes. Once the raw bytes have been read, a QR scanner needs to know exactly what sort of code it is dealing with. [The first four *bits* tell it the mode]( ). Let's convert the hex to binary and then split after the first four bits:<thead><tr><th align="center">Type</th><th align="center">HEX</th><th align="center">BIN</th><th align="center">Split</th></tr></thead><tbody><tr><td align="center">UPPER</td><td align="center"><code>20 93</code></td><td align="center"><code>00100000 10010011</code></td><td align="center"><code>0010 000010010011</code></td></tr><tr><td align="center">lower</td><td align="center"><code>41 26</code></td><td align="center"><code>01000001 00100110</code></td><td align="center"><code>0100 000100100110</code></td></tr></tbody> The UPPER code is 0010 which indicates it is Alphanumeric - the standard says the next **9** bits show the length of data. The lower code is 0100 which indicates it is Byte mode - the standard says the next **8** bits show the length of data.<thead><tr><th align="center">Type</th><th align="center">HEX</th><th align="center">BIN</th><th align="center">Split</th></tr></thead><tbody><tr><td align="center">UPPER</td><td align="center"><code>20 93</code></td><td align="center"><code>00100000 10010011</code></td><td align="center"><code>0010 0000 10010</code></td></tr><tr><td align="center">lower</td><td align="center"><code>41 26</code></td><td align="center"><code>01000001 00100110</code></td><td align="center"><code>0100 000 10010</code></td></tr></tbody> Look at that! They both have a length of 10010 which, converted to binary, is 18 - the exact length of the text. Alphanumeric users 11 bits for every two characters, Byte mode uses (you guessed it!) 8 bits per single character. But why is the lower-case code pushed into Byte mode? Isn't it using letters and number? Well, yes. But in order to store data efficiently, Alphanumeric mode only has [a limited subset of characters available]( ). Upper-case letters, and a handful of punctuation symbols: space $ % * + - . / : Luckily, that's enough for a protocol, domain, and path. Sadly, no GET parameters. So, there you have it. If you want the smallest possible *physical* size for a QR code which contains a URl, make sure the text is all in capital letters. #qr #QRCodes