LoginSignup
15
23

More than 3 years have passed since last update.

PythonでTOTP(Time-based One-Time Password)を実行する

Posted at

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でかんたんに再現できます。

説明用のプレゼン資料

子供に説明するために作成しました(ふんわりしています)

参考

15
23
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
15
23