0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TOTP をゼロから実装して RFC 6238 のテストベクタを全一致させた

0
Last updated at Posted at 2026-05-01

作ったもの

TOTP Generatorhttps://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)      );
  1. カウンタは 8 バイトビッグエンディアン - 4 バイトじゃない
  2. オフセットはハッシュ最終バイトの下位 4 ビット - これが「dynamic」
  3. 先頭バイトの最上位ビットをマスク (& 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:cryptocreateHmac にフォールバック。

シリーズ

100+ 公開ポートフォリオ シリーズの #53 です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?