@niftyログインの際のワンタイムパスワードの表示に「Google認証システム」互換のアプリを使う


#この記事を書いた背景

[@nifty](https://www.nifty.com/) のログイン時の認証は2段階認証に対応していますが、その際に使用するワンタイムパスワード表示アプリとして@nifty独自の「[@niftyワンタイムパスワード](https://play.google.com/store/apps/details?id=com.nifty.sso.otp.android)」というアプリを使用するように指定されています。
シークレットコードの互換性が無いことが理由で、いくつかある「Google認証システム」互換のアプリはそのままでは使うことは出来ません。

- @niftyログインのためだけに余計なアプリを入れたくない。 
- 使い慣れたワンタイムパスワード表示のアプリを使いたい。
- 「@niftyワンタイムパスワード」アプリの使い勝手が悪い。

などの理由で、「Google認証システム」互換アプリを使うことは出来ないだろうかと試行錯誤したところ成功したのでその方法をまとめておきたいと思います。

#作業環境

##作業用PC Linux Mint 19.3 (Ubuntu18.04LTSベース)
@niftyのホームページ上でワンタイムパスワード設定の作業と、「Google認証システム」互換アプリで読み込めるQRコードを作成するのに使用します。

変換したQRコードを表示する作業で次のコマンドを使用します。

- bash
- base64
- base32
- sed
- qrencode

「qrencode」コマンドは標準では入っていないと思われるので、あらかじめaptなどでインストールしておきます。

##Androidスマートフォン1(「Google認証システム」互換アプリ用)
普段使っている「Google認証システム」互換アプリが入っているスマフォを用意します。
自分は「[IIJ SmartKey](https://play.google.com/store/apps/details?id=jp.ad.iij.smartkey2&hl=ja)」を使用しています。

##Androidスマートフォン2(「@niftyワンタイムパスワード」アプリの挙動確認用)
もう1台スマホを用意して「[@niftyワンタイムパスワード](https://play.google.com/store/apps/details?id=com.nifty.sso.otp.android)」をインストールしておきます。
これによって同じワンタイムパスワードが表示されているかを2台並べて確認することが出来ます。もし無いと確認作業が面倒なことになると思います。
古いスマフォを引っ張り出してきても良いです。ただし正常なパスワード表示のために時刻は正確に合わせておく必要があります。

#@niftyのワンタイムパスワードの仕様の中で問題になったところ

- アプリ読み込み用のQRコード内の文字列が独自のものになっているため、そのまま読み込めない(スキームが"niftylogin://totp/〜"で始まる文字列になっている)。"totpauth://totp/〜"文字列に置き換える必要がある。
- シークレットコードがBASE32ではなくBASE64でエンコードされているため、シークレットコードはQRコードでも手打ちでもそのままでは使用出来ず、BASE32に変換する必要がある。
- パスワード数値の桁数は6桁ではなく8桁(文字列に指定を追加すれば良い)
- パスワード更新秒数が30秒ではなく60秒(文字列に指定を追加すれば良い)

#作業手順

1. [@nifty](https://www.nifty.com/)にログイン
 ワンタイムパスワードの設定の手続きを進める。設定の途中で「@niftyワンタイムパスワード」アプリに読み込ませるためのQRコードと直接指定用のシークレットコードが表示されるところまで進める。
![niftyonetime.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18840/402904fc-ed66-689a-32ec-5017b96209b6.png)

2. 1で表示されたQRコードを「@niftyワンタイムパスワード」アプリで撮影する
表示されたQRコードをAndoroidスマートフォン2の「@niftyワンタイムパスワード」アプリで読み込みます。成功するとアプリ上に8桁のワンタイムパスワードが出る状態になると思います。このままの状態にしておいて後述の確認作業のために使用します。

3. 1で表示されたシークレットコード文字列をコピー&ペーストし、QRコードを作成・表示するコマンドを実行する
シークレットコード(「登録コード」と記載されている英数字からなる文字列)をコピー＆ペーストして、以下のコマンドを実行します。

    ```
$ echo -n "otpauth://totp/nifty?secret=$(echo 'ここにシークレットコード文字列をペースト' | base64 -d | base32 | sed s/=//g )&period=60&digits=8&algorithm=SHA1&issuer=nifty" | qrencode -t ANSI
```

    コマンドについて軽く説明すると、QRコードに格納するための文字列を作成し、それをqrencodeコマンドに渡してQRコード化させて表示しています。
「$(echo 'ここにシークレットコード文字列をペースト' | base64 -d | base32 | sed s/=//g )」の部分がBASE64のシークレットコード文字列をBASE32に変換した文字列を作り出している部分です。また「&period=60&digits=8&algorithm=SHA1」の形で@niftyのワンタイムパスワードの仕様(更新秒数とパスワード桁数とハッシュ化アルゴリズム)に合致するようにパラメータで与えるようにしています。

    実行するとターミナル上に次のような感じのQRコードが表示されます。
もしQRコード表示が画面全体に入り切っていない場合は、フォントサイズを小さくして画面内に収まるようにしてください。またはqrencodeコマンドでPNG画像を出力するようにオプションを変えるなど工夫してください。

    ![qrcode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18840/c24978eb-fbe8-9659-4e64-8325672e23ae.png)

4. 3で表示されたQRコードを「Google認証システム」互換アプリで撮影する
表示されたQRコードをAndroidスマートフォン1の「Google認証システム」互換アプリで読み込みます。成功するとアプリ上に8桁のワンタイムパスワードが出る状態になると思います。

5. 確認をする
今までの作業で2台のスマフォにそれぞれ表示されている「@niftyワンタイムパスワード」アプリと「Google認証システム」互換アプリのパスワード表示が一致して更新されていることを数分に渡って確認します。
もし一致していなければ、これまでの作業を見直してやり直すなどしてください。

    ![phone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18840/41457576-9e4f-f28f-4346-680d8ef9ba7e.png)

6. @niftyのワンタイムパスワード手続きを再開し、手続きを完了させる
「@niftyワンタイムパスワード」アプリの代わりに「Google認証システム」互換アプリを使うことが出来るようになります。
不要であれば「@niftyワンタイムパスワード」アプリはアンインストールして構いません。


#終わりに

QRコード作成コマンドに使った「echo」コマンドで「-n」オプションを付けて改行を取り除いておかないと、アプリに不正扱いされて読み込んでくれないのに気づくまでものすごく時間がかかってしまいました。