
ブラウザで動作する公開鍵暗号を使用した暗号化/復号プログラム
はじめに
公開鍵暗号は非常に強力で、これを使わない手はないです。実際にさまざまな形で使われていますが、ファイルの暗号化/復号ができるソフトは案外少ないです。
有名どころだと、Kleopatra、アタッシェケース4(公開鍵暗号対応版)なんですが、いずれもインストールが必要です現場でインストールする、という作業は大きな障壁でして、また、バイナリコードだと「それ大丈夫なん?」とか普通に言われます。
スマートフォンやMacのようにアプリストアから導入する形であれば、障壁は少ないのですが、Windowsだとなかなか厳しいです。
そこでブラウザのJavaScriptというコードが見える形であれば、よいのではないか、ということで、以前も少し手掛けたこともあり、やってみることにしました。
導入も非常に簡単で、OSなどのプラットフォームも選びません。
ローカルのJavaScript処理なので動作に通信は発生しません。
実装の方針
誰でも簡単に扱えること
シンプルで簡単なUIであること実装はAIを併用し、スピード感と正確さを出していく
せっかく課金もしているのでChatGPT o3-mini-highをメインで使用しました公開鍵ペアの種類は次の2種類
RSA4096bit
RSA鍵ペアでは4096bitの鍵を生成します
未保証ながら1024/2048bit鍵も使用できます
よって、アタッシェケース4で生成される鍵ペアも拡張子を変更してインポートすれば使用できますEC(楕円曲線暗号)P-521
短い暗号鍵でありながら、高い暗号強度を実現します
未保証ながらP-256/P-384も使用できます
今後の実装はこちらを重視します
AESは256bitでGCMモードを使用する
公開鍵でAES鍵を暗号化し、ファイルはAESで暗号化する
いわゆるハイブリッド暗号方式であり、実用的な高速処理を実現する
環境にもよりますが、650MBくらいなら数秒で暗号化を完了できます鍵はIndexedDBに格納して、ユーザーから隠蔽することで流出事故を防ぐ
公開鍵を複数使った暗号化/復号をサポートする
今回のウリの一つです復号は所持して認識している秘密鍵から一致するものを自動で適用する
鍵の保存場所について
ブラウザ内の IndexedDBに保存しています。つまり、パソコン内部のさらにユーザーに紐づけた場所ですので、パソコンを共用していてもユーザーが違うと読めません。
本体そのものについて
ブラウザ単体で動作します。
htmlファイルをダウンロードして、ローカルで実行、つまりネットワーク環境がない場所でも動作します。
使い方
鍵管理
任意の鍵名、鍵の方式[RSAまたはEC(楕円曲線)]を入力し、鍵生成ボタンを押下すると、秘密鍵と公開鍵が生成され、鍵一覧に掲載されます。

公開鍵、秘密鍵ともにファイルにエクスポートできます。
ただし、秘密鍵をエクスポートするときは注意が出ます。
テキストボックスに表示されるほか、ダウンロードもできます。
また、不要になった鍵は削除できます。

秘密鍵インポート
秘密鍵のインポートができます。インポートすると公開鍵を新たに生成します。鍵は鍵一覧で管理できます。

公開鍵のインポート機能は備えていません。
暗号化するとき公開鍵を都度、ファイルで指定します。
鍵管理の初期化
再度、アクセスしたときに鍵が再表示されないなどのトラブルが生じることがあります。その場合は、鍵管理の初期化を試してください。ただし、記憶している鍵は失われてしまいますので運用には注意してください。

暗号化
下記の通りの流れです。
暗号化するファイル(複数可能)をドロップまたは「ファイル選択」で選択
暗号化に使う公開鍵のファイルを選択(複数可能、鍵の方式が異なっていても可能)
暗号化

暗号化処理が終わるとブラウザからダウンロードとして出力されます。
復号
同様の流れです。復号に必要な秘密鍵は鍵一覧から自動選択しますので指定は不要です。
暗号化するファイル(複数可能)をドロップまたは「ファイル選択」で選択
復号

暗号化処理が終わるとブラウザからダウンロードとして出力されます。
具体的な運用のざっくりとした流れ
下記のとおりです

暗号化のプロセス
概略は次のとおりです

暗号化されたファイルの構造
次のとおりです。


公開鍵エントリーを照合して秘密鍵とのマッチを行っています
公開鍵エントリーは公開鍵から作成していますので暗号化不要ですRSA暗号のモードとして RSA-OAEPを採用しています
本実装では、RSA暗号方式の大きな弱点である、「全く同一の平文を複数の送信先へ各々の公開鍵で暗号化して同報通信するには適していない。同じ e を持つ公開鍵(ハミング重み HW = 2 である 3 や 65537 が好んで用いられる)で暗号化された e 個以上の暗号文を手に入れたなら各々の公開鍵の法に関して中国の剰余定理を用いることで、通常の冪根によって平文を復元できるからである」(RSA暗号の誤用:同報通信)ということに相当します
本実装では、RSA-OAEPを採用して回避しています。
RSA-OAEPではランダムなパディングを付加することで暗号文のパターンをランダム化し、以下のような攻撃を防ぐために設計されていますが、同様の実装を行う場合は十分注意が必要です。
また、RSAの公開指数 (e)は、65537としており、今回の運用の想定としては十分大きいと認識しています。Hastadの Broadcast 攻撃
同じ平文を異なる公開鍵で暗号化しても、異なる暗号文が生成されるため、攻撃者は中国の剰余定理を用いた攻撃を実行できません。
暗号文の辞書攻撃(Ciphertext Dictionary Attack)
同じ平文を暗号化しても、暗号文は異なるため、事前に暗号文と平文の対応表を作成するような攻撃が困難になります。
Bleichenbacherの攻撃(Padding Oracle Attack)
RSA-OAEPはパディング方式として PKCS#1 v1.5 ではなく、より安全な PKCS#1 v2.0 に基づいた方式を採用しており、Bleichenbacherの攻撃を防ぎます。公開鍵による暗号化のパディングはRSA-OAEPで行っています。
楕円曲線暗号のモードとしてECDHを採用しています
EC方式では、暗号化のたびにエフェメラル(使い捨て)鍵ペアを生成し、送信先の公開鍵と自分の一時秘密鍵を用いて共通のラッピング鍵を導出します。これにより、同一の平文であっても、各送信において異なるラッピング鍵が得られるため、以下の攻撃に対して安全性が向上しています。Hastadの Broadcast 攻撃
同じ平文を複数の受信者向けに暗号化する場合でも、各送信時に異なるエフェメラル鍵ペアが生成され、受信者ごとにECDHにより導出されるラッピング鍵がランダムに決定されます。その結果、全く同一の暗号文が生成されることはなく、攻撃者は各受信者の暗号文から一括して共通鍵(および平文)を復元するための情報を得ることができません。
暗号文の辞書攻撃(Ciphertext Dictionary Attack)
ECDHを利用して毎回異なるラッピング鍵を導出するため、同一の平文であっても暗号化されるたびに全く異なる暗号文が生成されます。これにより、あらかじめ暗号文と平文の対応表(辞書)を作成して攻撃する手法が実質的に成立しなくなります。
Bleichenbacherの攻撃(Padding Oracle Attack)
EC方式の場合、AES-GCMなどの認証付き暗号方式を用いて実際のペイロードを暗号化するため、パディングの正否に関する情報が外部に漏れる可能性が非常に低くなります。さらに、ECDHにより導出されたラッピング鍵を用いることで、暗号化処理全体にランダム性が付与され、パディングオラクル攻撃に相当する攻撃手法は実質的に困難となります。なお、本実装ではECDHに基づく鍵導出に際し、エフェメラル鍵ペアを都度生成し、楕円曲線パラメータとしてP-256を採用しています。このパラメータおよび運用方式は、現行の攻撃手法に対して十分な安全性を有すると認識されています。
AESは256bit鍵を使っています
現在実装されているなかで最も強力ですAESはGCMモードを使っています
IVを使用しないEBCモードは文字比較攻撃(Known Plaintext Attack)やパターン解析攻撃でクラックされる理論的可能性があるので、推奨されていません
よって、当初、その考えでGCMあるいはCBCモードでの実装を検討をしていましたが、PowerShell 5系がGCMモードを実装していないので、CBCモードで実装していました
ですが、やはり改竄に対抗できるGCMモードにすべき、ということで、PowerShell版との互換性はいったん捨ててGCMモードで実装しています
GCMあるいはCBCモードは、IVが必要ですので、ファイルに記録していますが、IVは暗号化する必要はありません
GCMモードでは暗号化結果の認証化タグがつきますので、暗号化部分の改竄が検出できます
参考文献
「RSA 公開鍵暗号の PowerShell 実装」(https://www.vwnet.jp/windows/PowerShell/RSACrypto.htm)
このサイトは以前も今回も非常に参考になりました。
利用できる環境の情報
Windows
Windows 7以降の各バージョン(Windows 10/11 など)で、モダンなブラウザ(Chrome、Firefox、Edge、Opera など)が利用できれば問題なく動作します。macOS
最新の macOS(Catalina、Big Sur、Monterey など)に加え、過去数世代の macOS でも、Chrome、Firefox、Safari、Opera、Edge などのブラウザがサポートされていれば動作します。Linux
Ubuntu、Fedora、Debian など主要なディストリビューション上で、Chrome、Firefox、Opera などのブラウザが利用可能な環境。モバイル OS
Android
Chrome for Android、Firefox for Android、Opera などのモダンブラウザが対象です。iOS
Safari(および iOS 用の Chrome、Firefox など、内部的には Safari のエンジンを利用している場合が多い)で動作します。
おわりに
暗号化は財産を守る有力な手段です。
今回の提案はあくまでの導入に過ぎません。
世の中にはもっと手法も仕組みもあります。
それらを含め、安全なデータの受け渡しを推進いただければと思います。
提供サイト
現在はGitHubにおいています。今後、変更する可能性がありますが、とりあえず、こちらで
PubliCrypt
PubliCrypt本体(参考)PubliCryptDisp
ファイル解析用