Now YubiKey. It can store TOTP secrets inside and time-based password can be viewed via corresponding software. You see here also my other accounts. BTW, the exact timestamp when I took screenshot is 2026-09-06 17-57-35 EEST. Will you be able to find HMAC key for all of them? It's considered not possible, despite the fact that SHA1 is (partially?) broken.
Also, the YubiKey app, running on android with YubiKey connected via USB-C. The app doesn't allow taking screenshots, so here is a photo. Exact timestamp is 2026-09-06 18-27-15 EEST.
YubiKey has a nice bonus: HMAC keys are stored internally and can't be extracted (at least, in absence of known bugs).
However, there is a weak spot. As of linux, there is a command-line YubiKey program: ykman. The oath.py file in $HOME/.local/lib/python3.12/site-packages/yubikit can be patched a bit:
% diff -u oath.py-bak oath.py
--- oath.py-bak 2026-08-06 23:07:46.758828187 +0300
+++ oath.py 2026-09-13 15:36:37.616423075 +0300
@@ -497,7 +497,8 @@
:param timestamp: A timestamp used for the TOTP challenge.
"""
- timestamp = int(timestamp or time())
+ timestamp = 1900000000 # Sunday, March 17, 2030 at 5:46:40 PM (UTC)
challenge = _get_challenge(timestamp, DEFAULT_PERIOD)
logger.debug(f"Calculating all codes for time={timestamp}")
Now run ykman:
% ykman oath accounts code Enter the password: lichess.org:temp_user12 452373 % date -d @1900000000 Sun 17 Mar 19:46:40 EET 2030
The code is indeed for that date, we can verify it after running this:
#!/usr/bin/env python3
import hmac, hashlib, time, base64, sys, re
def hotp(key: bytes, ctr: int, length: int) -> str:
m=hmac.new(key, digestmod=hashlib.sha1)
m.update(ctr.to_bytes(8, 'big'))
mac = m.digest()
offset = mac[-1] & 0xf
truncated = bytearray(mac[offset:offset+4])
truncated[0] &= 0x7f
value = int.from_bytes(truncated, 'big') % (10**length)
return str(value).rjust(length, '0')
URL=sys.argv[1]
result=re.search('secret=(.*)&', URL)
assert result!=None
secret=result.group(1)
s=base64.b32decode(secret.upper())
t=1900000000 # Sunday, March 17, 2030 at 5:46:40 PM (UTC)
print ("The code:", hotp(s,int(t/30),6))
time_remaining=int(30-(t % 30)) # remainder from division
print (f"The code is valid for {time_remaining} seconds")
An attacker can do so, getting your physical YubiKey for some time, like several minutes, and he/she can generate key(s) for future use. And then login to your account (assuming he/she also knows your password) during that exact 30-seconds interval. This is not impossible practically. This should be kept in mind. YubiKey has a feature of setting password for TOTP accounts protection.
