This is very useful to anyone writing TOTP tools, big thanks to the author.
However, reading the article this section caught my eye:
"As we now know, SHA-1 has some fundamental weaknesses. ... But the TOTP authors disagree and allow a for some different algorithms to be used."
With significant compute resources SHA1 can be broken for some use cases, but I don't think this is one of them. Is HN aware of any practical attacks against TOTP-SHA1?
About the "validity" period: in practice it seems to be more like a rotation period, the code themselves seem to be valid longer than this, that is you can often enter them for quite some time after they get rotated.
And I also often wonder about the OTP aspect, whether there is any protection in TOTP backends for the same TOTP being used twice.
I'm so glad this has been created. I've felt for quite some time that TOTP is such a triumph of simplicity and security. It's so simple that if you have your secret key on hand, you can generate your TOTP code with just 30 lines of Python!: https://github.com/susam/mintotp/blob/main/mintotp.py
It's amazing! Its default UX assumes you're basically air gapped. It works based on a minimal shared secret that's totally portable. Conceptually, it's as clear as "hash (your secret+(now()//30)), display hash as decimal, only show the last 6 (ish) digits".
Wrong, what it's missing from passkey is phishing resistance. And you can use passkeys with at least a few independent commercial password managers if you are not happy giving your passkeys to Google & Apple (I work for one such password manager)
Psst: your employer is a vendor benefiting from said lock-in.
Without a means for transfering from one password management resource to another, passkeys create an increasingly significant friction against migrating one's account and artifically reduces competitive pressure on the vendor.
The phrase we use for that anti-consumer phenomenom is "vendor lock-in"
(If your employer has an effective and practical import and export technique for passkeys, I would be delighted to hear so and apologize for the suggestion otherwise. But as far as I've seen, that's not a thing.)
Being able to export a passkey sounds like a bug, not a feature. I was surprised that the spec was altered to allow hosting in the cloud at all, I thought it was more interesting as a means of keeping secrets in secure enclaves.
The expectation is that for any service you should be able to have multiple passkeys -- including multiple passkeys from different vendors. I'm not sure how that exactly causes lock in?
Exactly, you can just register passkeys from multiple providers if that's a fear. Worst case (i.e. Google nukes your account and you've only set one passkey), you go through the usual email recovery or backup codes process and set a new one.
It would be good to have a FOSS-implementation with TPM as the storage backend for computers and phones. Then people wouldn't need to use keys stored in the cloud.
Assuming you've only set one passkey (you can add multiple passkeys from different passkey managers) it's no more of an inconvenience than if you lost your password. Normal recovery/backup code processes still work.
TOTPs are amazing! I'm currently building a low-power, offline ESP32 device that generates time-based one-time QR codes and displays them on an e-ink screen. I plan to use it for proof of presence.
if you're only doing the signature generation rather than the full protocol (which TOTP leaves entirely up to the user), then the code to generate a passkey signature wouldn't be any longer
> 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
Am I bad at reading specs or is there a maximum here? If I say „minimum 6, possibly 7 or 8“, that sounds like 9 and more isn’t allowed.
HOTP requires a minimum of 6 digits (R4 in Section 4), but does not actually set a maximum. The algorithm in the RFC caps at 9-digits per Section E.2 (and my cursory reading of the code). That's not a required limit, but a technical limit of their choices. It also happens that 9-digits probably is about as big as you'd want to go, three 3-digit chunks aren't much harder to remember and type in correctly but past that it'd become increasingly impractical. The "and possibly 7 and 8-digit code" should be taken as descriptive, not prescriptive. The requirements occur earlier in the document and do not set a maximum. If they'd intended 8 as the maximum then they wouldn't have presented an algorithm that goes to 9 digits and would have stated it clearly in the requirements section, or followed up the HOTP RFC with another one clarifying these details.
This is very useful to anyone writing TOTP tools, big thanks to the author.
However, reading the article this section caught my eye:
"As we now know, SHA-1 has some fundamental weaknesses. ... But the TOTP authors disagree and allow a for some different algorithms to be used."
With significant compute resources SHA1 can be broken for some use cases, but I don't think this is one of them. Is HN aware of any practical attacks against TOTP-SHA1?
About the "validity" period: in practice it seems to be more like a rotation period, the code themselves seem to be valid longer than this, that is you can often enter them for quite some time after they get rotated.
And I also often wonder about the OTP aspect, whether there is any protection in TOTP backends for the same TOTP being used twice.
The validity is up to the service, as described in https://datatracker.ietf.org/doc/html/rfc6238#section-5.2
Because of clock skew and latency, a service might choose to allow the previous and/or next code as being acceptable.
I am not sure whether TOTP can be used two times, but that longer validity aspect already lead to a vulnerability called "Microsoft MFA AuthQuake"
They repeat roughly every year. 1,000,000 periods of 30 seconds is just less than 350 days.
I'm so glad this has been created. I've felt for quite some time that TOTP is such a triumph of simplicity and security. It's so simple that if you have your secret key on hand, you can generate your TOTP code with just 30 lines of Python!: https://github.com/susam/mintotp/blob/main/mintotp.py
It's amazing! Its default UX assumes you're basically air gapped. It works based on a minimal shared secret that's totally portable. Conceptually, it's as clear as "hash (your secret+(now()//30)), display hash as decimal, only show the last 6 (ish) digits".
What a triumph. I love TOTP.
This is meant as a sidelong critique on passkeys.
It doesn't have the killer feature of passkeys though, vendor lock-in. Which is the sole purpose of them.
Wrong, what it's missing from passkey is phishing resistance. And you can use passkeys with at least a few independent commercial password managers if you are not happy giving your passkeys to Google & Apple (I work for one such password manager)
Psst: your employer is a vendor benefiting from said lock-in.
Without a means for transfering from one password management resource to another, passkeys create an increasingly significant friction against migrating one's account and artifically reduces competitive pressure on the vendor.
The phrase we use for that anti-consumer phenomenom is "vendor lock-in"
(If your employer has an effective and practical import and export technique for passkeys, I would be delighted to hear so and apologize for the suggestion otherwise. But as far as I've seen, that's not a thing.)
Passkeys are still very much work in progress but there will be standard ways of transferring passkeys between password managers at least https://www.theverge.com/2024/10/15/24270875/password-manage...
I'm not working specifically on passkeys lately so I don't know exactly what is already available to the public, I'll ask around
Being able to export a passkey sounds like a bug, not a feature. I was surprised that the spec was altered to allow hosting in the cloud at all, I thought it was more interesting as a means of keeping secrets in secure enclaves.
The expectation is that for any service you should be able to have multiple passkeys -- including multiple passkeys from different vendors. I'm not sure how that exactly causes lock in?
Exactly, you can just register passkeys from multiple providers if that's a fear. Worst case (i.e. Google nukes your account and you've only set one passkey), you go through the usual email recovery or backup codes process and set a new one.
That misses the overhead of having to rotate the passkeys for thousands of websites you've used them on.
It would be good to have a FOSS-implementation with TPM as the storage backend for computers and phones. Then people wouldn't need to use keys stored in the cloud.
Have a look at Keepassxc. It doesn't use a tpm, but supports passkeys and is portable.
This is the sole reason I'm avoiding passkey setup. How big of a worry is it?
Assuming you've only set one passkey (you can add multiple passkeys from different passkey managers) it's no more of an inconvenience than if you lost your password. Normal recovery/backup code processes still work.
TOTPs are amazing! I'm currently building a low-power, offline ESP32 device that generates time-based one-time QR codes and displays them on an e-ink screen. I plan to use it for proof of presence.
if you're only doing the signature generation rather than the full protocol (which TOTP leaves entirely up to the user), then the code to generate a passkey signature wouldn't be any longer
Yeah, I have implemented it in PHP and Lua as well, cannot check the LOC right now, but it is around ~30 as well, if not less, at least in PHP.
It’s definitely a fairly trivial implementation, here’s one of a few dozen lines of (not very clean) Swift: https://github.com/JustAman62/ovault/blob/7ee38b7e5c2666cd34...
The simplicity of the implementation makes a test suite even more valuable, as it’s really quite hard to figure out if your implementation is correct.
As part of writing the test suite, I also wrote an implementation in JavaScript. It uses the Web Crypto API rather than external libraries.
https://shkspr.mobi/blog/2025/03/using-the-web-crypto-api-to...
> 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
Am I bad at reading specs or is there a maximum here? If I say „minimum 6, possibly 7 or 8“, that sounds like 9 and more isn’t allowed.
HOTP requires a minimum of 6 digits (R4 in Section 4), but does not actually set a maximum. The algorithm in the RFC caps at 9-digits per Section E.2 (and my cursory reading of the code). That's not a required limit, but a technical limit of their choices. It also happens that 9-digits probably is about as big as you'd want to go, three 3-digit chunks aren't much harder to remember and type in correctly but past that it'd become increasingly impractical. The "and possibly 7 and 8-digit code" should be taken as descriptive, not prescriptive. The requirements occur earlier in the document and do not set a maximum. If they'd intended 8 as the maximum then they wouldn't have presented an algorithm that goes to 9 digits and would have stated it clearly in the requirements section, or followed up the HOTP RFC with another one clarifying these details.
https://datatracker.ietf.org/doc/html/rfc4226