概要
- Erlangでワンタイムパスワードを生成するライブラリがあるのでElixirから使ってみた
- githubにざっとドキュメントはあるが、実際に動作確認してみたメモ
動作メモ
HOTP生成
# secretはencodeしたものを渡す必要がある
iex(1)> raw_secret = "1234567890"
"1234567890"
iex(2)> encoded_secret = Base.encode32(raw_secret, padding: false)
"GEZDGNBVGY3TQOJQ"
iex(3)> counter = 1
1
iex(4)> :pot.hotp(encoded_secret, counter)
"263420"
# 桁を指定することも可能
iex(5)> :pot.hotp(encoded_secret, counter, token_length: 8)
"13263420"
# base32 で encode されていない secret を指定するとエラー
iex(6)> encoded_secret = "1234567890"
"1234567890"
iex(7)> :pot.hotp(encoded_secret, counter)
** (FunctionClauseError) no function clause matching in :base32.std_dec/1
...
ソースコードを見ると、digest method を指定することもできる模様。
crypt.hmac
を使っているので、 http://erlang.org/doc/man/crypto.html にある
md5, ripemd160, sha, sha224, sha256, sha384, sha512 あたりが使えそうだが、うまく動かなかったので未確認。
HOTP検証
iex(1)> encoded_secret = "GEZDGNBVGY3TQOJQ"
"GEZDGNBVGY3TQOJQ"
iex(2)> counter = 1
1
iex(3)> token = token = :pot.hotp(encoded_secret, counter)
"263420"
# :last として最後に検証したカウンタの値を指定
iex(4)> :pot.valid_hotp(token, encoded_secret, [{:last, counter - 1}])
1
# 戻り値はカウンタの値
iex(5)> counter = 3
3
iex(6)> token = token = :pot.hotp(encoded_secret, counter)
"626604"
iex(7)> :pot.valid_hotp(token, encoded_secret, [{:last, counter - 1}])
3
# 検証に失敗したら false
iex(8)> invalid_token = "000000"
"000000"
iex(9)> :pot.valid_hotp(invalid_token, encoded_secret, [{:last, counter - 1}])
false
TOTP作成
# encode secret を渡すと、現在時刻でTOTP生成
iex(1)> encoded_secret = "GEZDGNBVGY3TQOJQ"
"GEZDGNBVGY3TQOJQ"
iex(2)> :pot.totp(encoded_secret)
"508549"
# interval_length を指定することが可能
iex(3)> :pot.totp(encoded_secret)
"836210"
## デフォルトは30秒
iex(4)> :pot.totp(encoded_secret, interval_length: 30)
"836210"
iex(5)> :pot.totp(encoded_secret, interval_length: 60)
"136108"
HOTPで指定できるパラメータはTOTPでも指定可能。
interval_length
は指定できるのに時刻のタイムスタンプを指定できない。
自分でやろうと思ったら、タイムスタンプを interval_length
で割った値を counter
として HOTP 生成すれば可能。
TOTP検証
# encode secret を渡すと、現在時刻でTOTP生成
iex(1)> encoded_secret = "GEZDGNBVGY3TQOJQ"
"GEZDGNBVGY3TQOJQ"
iex(2)> token = :pot.totp(encoded_secret)
"363352"
# TOTPの検証成功時は true
iex(3)> :pot.valid_totp(token, encoded_secret)
true
感想
- HOTP/TOTPの生成/検証はほぼドキュメント通り一通りできる
- TOTPでタイムスタンプを指定できないのだけちょっとだけ不満
不満なところのパラメータを指定できるようにしたライブラリを自分で書いているので、いい感じになったら追記予定。