2011-06-01

OATHによるワンタイムパスワードの仕様 - 3

By Taro Yamazaki  |  23:30 No comments

前回は2つのワンタイムパスワードの生成方法について取り上げました。今回はいよいよ実際の生成アルゴリズムを取り上げましょう。TOTPをベースに説明します(ただ、前回も解説したように、基本的なロジックはTOTPとHOTPで同じです)。
参考としてpythonのコードも併記してみます。


1. タイムステップを考慮したカウンタの算出

TOTPの場合、カウンタはunixtimeになります。しかし、これをそのまま使うとワンタイムパスワードが毎秒変わってしまうことになり、さすがにこれは実用的ではありません。それで、ワンタイムパスワードが切り替わる間隔としてタイムステップ (Time-Step) を設定し、unixtimeをタイムステップで割った値をカウンタとします。
messagetime = unixtime / timestep
これにより、タイムステップが30なら、30秒間は同じワンタイムパスワードが生成されることになります。
※ OATHの仕様ではタイムステップとして30秒が推奨されています。

2. HMAC (SHA) の算出

まず、1.で生成した値を16バイトの16進数表記に変換します(バイト数が足りない分はゼロ埋めします)。その16バイトをASCII文字列に変換したものをデータとし、パスコードをキーとしてHMACダイジェストを算出します。
message = '%016X' % messagetime
h = hmac.new(key, message.decode("hex_codec"), sha)
d = h.digest()

hmac_result = []

for c in d:
hmac_result.append(ord(c))
これにより、20バイトのハッシュ文字列が生成されます。この文字列の文字コードを1文字ずつ配列に格納しておきます。
※ なお、ハッシュの算出にはSHA-1だけでなく、SHA-256やSHA-512なども使用できます。

3. オフセットの算出とビット演算

2. で生成されたハッシュの最後のバイト(20バイト目)を 0xf でマスクした値をオフセットとし、そのオフセットに基づいてビット演算を行います。
offset = hmac_result[19] & 0xf

sn = (hmac_result[offset]  & 0x7f) << 24 | \
(hmac_result[offset+1] & 0xff) << 16 | \
(hmac_result[offset+2] & 0xff) <<  8 | \
(hmac_result[offset+3] & 0xff)

4. ワンタイムパスワードの出力

3. で計算された値を 10のn乗(nはワンタイムパスワードの桁数となります)で割ります。その余りがワンタイムパスワードとなります。8桁の場合はこのようになります(桁数を合わせるためにゼロ埋めが必要です)。
result = '%08d' % (sn % 10**8)

OATHの仕様には、Javaで記述されたリファレンスコードが掲載されています。また、生成されたワンタイムパスワードの値が正しいかどうかをテストするための値のリストも載せられていますので、独自に実装した際の確認のために使用することができます。
今回説明したように、ワンタイムパスワードの生成自体はそれほど難しいものではなく(計算は少々ややこしいですが…)、スクリプト言語でも比較的簡単に実装できます。PHPやpythonなどで開発されたWebアプリケーションに組み込むことも容易ですし、スマートフォンを使ったソフトウェア・トークンもいろいろと出てきていますので、Webアプリケーションのセキュリティを高めるためにも取り組んでみるいい機会かもしれませんね。

Author: Taro Yamazaki

0 コメント:

© 2015 yamata::memo | Distributed By My Blogger Themes | Created By BloggerTheme9
TOP