作ったもの
TOTP Generator — https://sen.ltd/portfolio/totp-generator/
- TOTP / HOTP の RFC 仕様準拠実装(RFC 4226 / 6238)
- Web Crypto API ベースの HMAC-SHA1(Node では crypto モジュールにフォールバック)
- Base32 デコーダ(RFC 4648)
-
otpauth://URL のインポート - 複数アカウント + localStorage 永続化
- AES-GCM + PBKDF2 で暗号化エクスポート
vanilla JS、ゼロ依存、ビルド不要。node --test で 47 ケース(RFC テストベクタ全一致)。
HOTP の 3 つの落とし穴
const offset = hash[hash.length - 1] & 0x0F;
const binary =
((hash[offset ] & 0x7F) << 24) |
((hash[offset + 1] & 0xFF) << 16) |
((hash[offset + 2] & 0xFF) << 8) |
((hash[offset + 3] & 0xFF) );
- カウンタは 8 バイトビッグエンディアン - 4 バイトじゃない
- オフセットはハッシュ最終バイトの下位 4 ビット - これが「dynamic」
-
先頭バイトの最上位ビットをマスク (
& 0x7F) - 符号なし整数として扱うため
RFC 6238 Appendix B
| Time | Code |
|---|---|
| 59 | 94287082 |
| 1111111109 | 07081804 ← 先頭ゼロ必須 |
| 1234567890 | 89005924 |
先頭ゼロがあるので padStart 必須。
Web Crypto API
const key = await crypto.subtle.importKey(
'raw', keyBytes, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign']
);
const sig = await crypto.subtle.sign('HMAC', key, dataBytes);
ブラウザで動く。Node テストでは node:crypto の createHmac にフォールバック。
シリーズ
100+ 公開ポートフォリオ シリーズの #53 です。
