ブラウザだけで使えるカジュアルなRSA暗号ツールを作ってみた

# パスワードとかをメールで安心して受け取るための暗号ボックス 🆓

Web Crypto APIを使って、カジュアルにRSA暗号を使う無料ツールをリリースしました。

https://angobox.com

![angobox.com_encrypt_MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnxJNIJdGJ3z%2FcAkcYqDJXpoKBII6Vka4y59F12tAKNxtov7Yg4pc3xSvGTy2WV5pv2bdm9UbBxYrsiJ5Ji6L0nsChD0bzGhDURrlVuXDdMVz3w7Jv%2B7QFwfqv3oiKZdhLJR1ZOzg8%2Fh2USNrgCjycEItKmeJWaEVzuZ9JQ (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35178/34a7b1b8-25d9-63b0-933d-6299c7bbc7d6.png)

暗号関係は正直知識や経験が浅く、この実装でいいのかな？と思うところもあるので、詳しい方がいらしたらぜひアドバイスください！

# なぜ作ったか

PPAPも然りパスワードとかをメールで送られるとドキッとするのでなんとかしたいと思いつつ、暗号化は何かと敷居が高いのでカジュアルに使える自分ツールが欲しいと考えていました。

調べていたら[Web Crypto API](https://developer.mozilla.org/ja/docs/Web/API/Web_Crypto_API)の存在を知り、これならブラウザだけのオフラインでRSAをサクッと使えるんじゃない？と思い、2月の3連休でガガっと作った次第です。

# 方向性

## とっつきやすくする

暗号化をして欲しい相手が暗号に詳しいことはまずないので、できるだけ専門用語を使わず使ってもらえるようにしたいです。

僕もBase64を見ると酔ってしまうので、公開鍵の表現にこのとてもかわいいボックス状のIdenticonを拝借しました。

https://github.com/emeraldpay/hashicon

**この箱に情報を入れると暗号にできて、箱の持ち主しか解読できないんだよ**という説明だとちょっとわかりやすいかなーと思いました。

## サーバーを持たない

平文や秘密鍵をネットワークに通したくないので、すべてブラウザ上のJavaScriptで完結します。

今はFirebaseでホスティングしていますが、Webサーバーさえあればどこでも運用できます。

# 暗号処理の実装について

## キーペアの生成と保存

初回アクセス時に`RSA-OAEP`のキーペアを生成します。以下のサンプル通りです。

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey

公開鍵は`SPKI`でエクスポートしてLocalStorageに保存します。

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey

秘密鍵はそのままエクスポートしてLocalStorageに保存すると、XSSが成立したときに抜かれちゃってヤバいのでユーザーの決めた`あいことば`でAES暗号にします。

`あいことば`にしたのは、このツール自体が**パスワードとかを暗号化するツール**なので、混同しないように言葉を変えてみたわけです。

そのための`wrapKey`というAPIがあるので、これもほぼサンプルのまま使います。変えたのはソルトを128ビットにしたことくらいです(長い方がいいらしいので)。

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/wrapKey

初期化ベクトル`IV`とソルトは秘密鍵を複合するときに使うので、LocalStorageに保存しておきます。

`IV`は秘匿する必要なさそうなんですが、ソルトを平文で同じ場所に置くのはあまり良くないんじゃないかなと思いつつ、他にいい方法が思いつきませんでした。ソルトを長くしてもこれでは意味なさげ…

## 暗号化

公開鍵をそのままURLとした暗号化フォームを一般に公開します。

URLがめっちゃ長い…

https://angobox.com/encrypt/MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnxJNIJdGJ3z%2FcAkcYqDJXpoKBII6Vka4y59F12tAKNxtov7Yg4pc3xSvGTy2WV5pv2bdm9UbBxYrsiJ5Ji6L0nsChD0bzGhDURrlVuXDdMVz3w7Jv%2B7QFwfqv3oiKZdhLJR1ZOzg8%2Fh2USNrgCjycEItKmeJWaEVzuZ9JQUWTR2CLVnAkM7XHNbtrs4nE3ExeaoiVKSR6t3pve67F%2BVUwR8sKIDitC24NbDESp7R5zrTWiS7%2BksI01EddSFGFVBlQ27GssZEYwkE5pC0D8krXGA4fJKno8EO8Qm5V%2FyS1%2F6d6wvoSw9Cjm4Mw1Mv%2F2ZsnRHBP5QNuSSv2%2BSxv%2BQ5RBFiip0L3IQeRfEjxtSTfltEyizBbUYkOKGsdrV97sswUw7vXA8coKnTaonU%2F8NmBVWKS0qJehUddRJ1qkrMB%2F0gjyvK8Cin4b68N%2FMI0dwiM0Cnd3cPoFWSqoR0e4CFwqCBBCzG4imZ%2BImBF%2B6Q8FwEMQv4vQaWn8FcNuwt40FqdX%2B32sRsMuYan0pMRkoj%2FNTMl2t0I00jh%2FfdZxEh5gppw7rdkBNe9Xxu6IQ88frePerizKQCtvDvBZsHQlNihFSUlml28OafZg3WfMjXtHywk4prlU8frQrz%2Bg4E0hcUYHRArlSsd2rBzqGBVLzovQQVt0jQyFokujuQzEq2VZcCAwEAAQ%3D%3D

平文を公開鍵で`RSA-OAEP`により暗号化します。これもほぼサンプル通り。

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt

## 復号

`wrapKey`で暗号化した秘密鍵を、`IV`とソルトとともに`unwrapKey`でメモリ上だけに復元します。

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/unwrapKey

その秘密鍵を使って上記で作った暗号を復号します。

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decrypt

こんな感じで、平文や鍵をネットワークに通すことなく、オフラインで暗号を処理します。

# ぜひ試してみてください！

組織的・設備的に脅威への対策ができているなら、このツールは特に必要ないでしょう。

メールや汎用的なツールで仕事をしているけど、セキュリティには少し気を遣いたい、という方に使ってもらえると嬉しいです。