TOTP(Time-based One-Time Password)について
最近、会社へのVPNへのログインでも銀行でもオンラインショッピングでも多要素の一つであるTOTPを使う機会が非常に増えました。仕組みをイマイチ理解しないまま使用しており、少々の不安とそのロバスト性に確信が持てていなかったので調べました。
結果として、盗み見等にも強いロバストであることを確信できましたが、Authyのようなサービスを気軽に利用する怖さを実感いたしました。(secretを他人に渡してしまうということなので、google authenticatorがクラウド同期をサポートしない気持ちがわかりました)
仕組み
完結に記すと以下の式になります
$$
password = hash(sercretkey, unixtime)
$$
これだけなのだがRFCという規格にても定義されており挙動が正確に記述されています
ハッシュアルゴリズムは何らかのデータを一方通行で非常に強い非可逆性の強い変換を行い数値化でき、bitcoinや各種さまざまなセキュリティはこれに依存しています。
Google AuthenticatorのいうところのTOTPはpythonで記すと以下のようなコードになります。
コード
import hmac, base64, struct, hashlib, time
def get_hotp_token(secret: str, intervals_no: int) -> str:
# まずシークレットキーをデコード
key = base64.b32decode(secret, True)
# PythonのデータをCの構造体に変換
msg = struct.pack(">Q", intervals_no)
# ハッシュ値を計算
h = hmac.new(key, msg, hashlib.sha1).digest()
o = h[19] & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return str(h)
def get_totp_token(secret):
# unix時間を30で割った整数をいれている
x = get_hotp_token(secret=secret, intervals_no=int(time.time())//30)
# 6桁に満たない場合は6桁になるまでパディング
while len(x)!=6:
x+='0'
return x
実行
# QRコード等で共有されたキー
secret = 'SOMETHINGSEC===='
print(get_totp_token(secret))
>> 829034
実際に自分で実行してみよう
Googleアカウントを持っている人ならばcolabでかんたんに再現できます。
説明用のプレゼン資料
子供に説明するために作成しました(ふんわりしています)