YubiKeyのワンタイムパスワードでZIPの暗号化してみた

## はじめに

### YubiKeyをユーザ認証以外にも使いたい！

YubiKeyの一番多い使い方は、ユーザ認証(ログイン認証など)だと思っています。
言い換えると、**ユーザ認証以外の使い方を見たことがありません。**

これたけ拡張性の高い**YubiKeyをユーザ認証だけにしか使わないのはもったいない!**
という訳で、今回は**DAuth**というサービスを使用して、**ZIPの暗号化/UNZIPの複号にYubiKeyのワンタイムパスワード(OTP)**を使ってみたいと思います。


もしYubiKeyをご存じない方は、下記のサイトをご参照ください。

[YubiKeyの概要(日本語サイト)](https://www.meettheyubikey.com/technology/detail.php?eid=00001)
[yubico社(メーカー)](https://www.yubico.com/)


## 概要

YubiKeyのワンタイムパスワードを使用したZIP/UNZIPアプリケーションをBashで作ります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289974/5346ef01-aab0-c03b-5615-6229c9e08792.png)

### 準備するもの

- YubiKey
- インターネットに接続したPC (Webブラウザ)
- Bashが動く環境 (私はAWS EC2のAmazon Linux2上で作りました)

### 構成

「YubiKeyのワンタイムパスワードの検証」、「ZIP(暗号化)に使用するパスワードの保管」等をゼロから自前で作ると大変なので、**DAuthというオンライン・データベースサービスを使います。**

- ZIP/UNZIPアプリケーション : Bashで作成
- DAuth : 「YubiKeyの検証」と「ZIP(暗号化)に使用したパスワードを保存するデータベース」として使用
- Rakuten Rapid API : **DAuthの無料トライアル版を使用するために必要**

アプリケーションの作成途中で、DAuthとRakuten Rapid APIマーケットプレイスのアカウントを作ります。
本記事の範囲であれば、無料かつクレジットカード不要でアカウントを作れます。

> Rakuten Rapid APIマーケットプレイスとは、開発者がAPIを検索・接続し、利用状況を管理できるAPIマーケットプレイスです。 ご自身のプロジェクトに必要なAPIを検索してアプリに埋め込み、ダッシュボードでAPIの利用状況が一括管理できます。

### 注意事項

このサンプルアプリケーションでZIP(暗号化)した場合、DAuthのトライアル用アカウントの期限超過、データベースから該当データを削除した場合、データをUNZIP(複号)できなくなる恐れがあります。

**圧縮・暗号化前のオリジナルデータを削除しないようにしてください。**

このサンプルアプリケーションの目的は、YubiKeyをログイン認証以外で使うことにあります。
セキュリティについては、利用される環境のセキュリティポリシーに合わせてご対応ください。

また、このサンプルアプリケーションの使用により生じる如何なる損害に対しても、その法的根拠に関わらず責任を負いません。自己責任の範囲でご利用ください。




## DAuthとは

DAuthは、**「YubiKeyと連動したクラウド上のオンライン・データベース」**です。

仕組みは非常にシンプルで、KVSや連想配列のような使い方ができます。

#### ■データベースに登録するとき

データをデータベースに登録するとき、次のものが必要になります。

- 認証に使うYubiKeyのID (ワンタイムパスワードの先頭12桁)
- キーワード (データベースのプライマリーキー)
- データ (JSON)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289974/ee55dfb6-65f2-b10f-33a3-c0496e2c6103.png)


#### ■データを取得するとき

データベースからデータを取得するとき、次のものが必要になります。

- 認証に使うYubiKeyのワンタイムパスワード(OTP)
- キーワード (データベースのプライマリーキー)

YubiKeyのOTPが正しいとき、キーワードに紐付いたデータが取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289974/9cd63958-cb0a-841c-729b-311b511b12bd.png)


## アプリケーションの仕様

今回はDAuthのデータベースを下記の仕様で使います。

- YubiKeyのID : 複号を許可するYubiKeyのID
- キーワード : 複号するときに必要なので、ZIP後のファイル名に付ける
- データ : ZIP(暗号化)に使用したパスワード

#### ZIP(暗号化)アプリケーション

▼ zip.shの処理の流れ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289974/6e60b1dc-39d9-f398-3742-c2c6d4266039.png)

▼ zip.shの使い方

```shell:暗号化(zip.sh)するとき
$ ./zip.sh test.txt ccccccxxxxgrjdtlgtlglffueedttuklinncddibljiu

# 元ファイル               : test.txt
# ZIP(暗号化)されたファイル : test.txt.hcYB7lwI.zip
```

zip.shの第1引数に「ZIP(暗号化)するファイル名」を入力します。
第2引数に「複号を許可するYubiKeyのワンタイムパスワード(OTP)」を入力します。

ZIP(暗号化)したファイル名には、キーワード(DAuthのデータベースのプライマリーキー)を付けます。"test.txt.hcYB7lwI.zip"の"hcYB7lwI"の部分。

zip.shからDAuthのデータベースに、下記のデータを登録します。

- YubiKeyのID : OTPの先頭12桁
- キーワード : "hcYB71wI" スクリプト内で自動生成 (複号するとき用にファイル名に付けます)
- パスワード : ZIP暗号化したときのパスワード。スクリプト内で自動生成


#### UNZIP(複号)アプリケーション

▼ unzip.shの処理の流れ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289974/6f516d54-c27e-8556-21f2-7310a8b10f25.png)

▼ unzip.shの使い方

```shell:複号(unzip.sh)するとき
$ ./unzip.sh test.txt.hcYB7lwI.zip ccccccxxxxgrgnkthelculjkufbcnhhuucddhhcebdgu
```

unzip.shの第1引数に「UNZIP(複号)するファイル名」を入力します。
第2引数に「複号許可されたYubiKeyのOTP」を入力します。

unzip.shはDAuthからパスワードを取得するために、OTPとキーワード(ファイル名から抽出 "hcYB71wI")を送ります。
OTPの検証結果が正しく、かつ認可されたYubiKeyだった場合、キーワードに紐付いたデータ(パスワード)が返ります。

そのパスワードで、ZIPデータを解凍・複号します。



## アプリケーションの作り方

DAuthドキュメントサイトにあるチュートリアルを行ってください。

[Step 1. DAuth APIを使ってみる](https://docs.d-auth.com/tutorial/step_1/)
[Step 2. ZIP暗号/複合アプリを作ってみる(bashスクリプト)](https://docs.d-auth.com/tutorial/step_2/)

DAuthのアカウントを既に持っている場合は、Step 1は省略できます。

※プログラムはGitHubでも公開されています。
[GitHub - dauth-yubikey-zip-bash](https://github.com/tada16/dauth-yubikey-zip-bash)


Macで"zip.sh"を作ったときに、乱数生成部分でハマったので対応方法を記載します。

```bash:zip.sh
#!/bin/bash
​
# Usage : zip.sh source.txt otp
​
# ここの値を入れ替える    
# tr -dc 'abcdefghijkmnpqrstuvwxyz'
APIKEY=XXXXXXXXXXXXXXXX  # <- 自分のAPIキーを入力してください
RAPIDKEY=XXXXXXXXXXXXXX  # <- 自分のRAPID APIキーを入力してください
​
# ランダム文字生成
PASSWORD=$(LC_CTYPE=C tr -dc 'A-Za-z0-9#%@&()' < /dev/urandom | fold -w64 | head -n 1)
KEY=$(LC_CTYPE=C tr -dc 'A-Za-z0-9' < /dev/urandom | fold -w8 | head -n 1)
​
ZIPFILE=${1}
OTP=${2}
KEYID=${OTP::12}
​
# call DAuth API
​
# Rapid
RESULT=$(curl \
  -X POST \
  -s \
  -H "X-DAUTH-API-KEY:${APIKEY}" \
  -H "x-rapidapi-key: ${RAPIDKEY}" \
  -H "Content-Type: application/json" \
  -d '{"device_id":"'${KEYID}'", "key":"'${KEY}'", "value":"\"'${PASSWORD}'\""}' \
  'https://dauth-trial.p.rapidapi.com/v1/dkvs' \
)
​
# Error check
if [ "`echo ${RESULT} | grep 'errors'`" ] ; then
  echo "Error!!"
  echo "`echo ${RESULT} | jq -r '.errors[0].message'`"
  exit 1
fi
​
# zip
zip -e --password=${PASSWORD} ${ZIPFILE}.${KEY}.zip ${ZIPFILE}
```


## 動作確認

"test.txt"をZIP(暗号化)し、UNZIP(復号)してみます。

```shell
$ ls
test.txt  unzip.sh  zip.sh

# 暗号化(zip.sh)
$ ./zip.sh test.txt ccccccxxxxgrjdtlgtlglffueedttuklinncddibljiu
adding: test.txt (stored 0%)

# "test.txt.hcYB7lwI.zip"がZIP(暗号化)されたファイル
$ ls
test.txt  test.txt.hcYB7lwI.zip  unzip.sh  zip.sh

# オリジナルファイルを退避
$ mv test.txt test.txt.org
$ ls 
test.txt.hcYB7lwI.zip  test.txt.org  unzip.sh  zip.sh

# 複号(unzip.sh)するとき
$ ./unzip.sh test.txt.hcYB7lwI.zip ccccccxxxxgrgnkthelculjkufbcnhhuucddhhcebdgu
Archive:  test.txt.hcYB7lwI.zip
 extracting: test.txt                

# "test.txt"がUNZIP(複号)されたファイル
$ ls
test.txt  test.txt.hcYB7lwI.zip  test.txt.org  unzip.sh  zip.sh
```

## 参考

- [DAuth ドキュメント : チュートリアル](https://docs.d-auth.com/tutorial/)

## おわりに

DAuthはオンライン・データベースサービスです。
「YubiKeyを使ったユーザ認証サービス」と違い、ユーザという概念がありません。
もちろん、「ログインの他要素認証」を簡単に作ることもできますが、それ以外の目的でも自由に使えます。

今回は、ZIP(暗号化)のパスワードをYubiKeyのワンタイムパスワードにしてみましたが、DAuthを使えば

- ワークフローのハンコ代わりにYubiKeyを使う
- システムのメンテナンスをするときに、管理者に遠隔でYubiKeyで許可をもらう多人数?認証

など、いろいろなことが出来そうです。

「YubiKeyをユーザ認証以外にも使いたい！」
「簡単に自分のプログラムに組み込みたい！」

という方は、ぜひ一度DAuthを試して頂けたら幸いです。