はじめに
暗号の世界では、速度とセキュリティの間でトレードオフに直面することがよくあります。AES のような対称暗号アルゴリズムは非常に高速であり、大量のデータを暗号化するのに理想的ですが、送信者と受信者の両方に安全に配布されなければならない共有シークレットキーが必要です。RSA のような非対称暗号アルゴリズムは、公開鍵/秘密鍵ペアを使用した安全な鍵交換に優れていますが、計算負荷が高く、バルクデータを暗号化するには遅すぎます。
ハイブリッド暗号化は、これら両方の手法の長所を組み合わせることで、この問題を解決します。これは「両方の長所を活かす (best of both worlds)」アプローチを使用します。
- 非対称暗号化を使用して、一時的なワンタイム対称鍵(しばしば「セッション鍵」と呼ばれる)を安全に暗号化し共有します。
- その後、このセッション鍵を使用して対称暗号化を行い、実際の大きなメッセージデータを迅速かつ効率的に暗号化します。
この実験(Lab)では、opensslコマンドラインツールを使用して、完全なハイブリッド暗号化スキームをゼロから実装します。RSA 鍵ペアを生成し、ランダムな AES セッション鍵を作成し、RSA を使用してセッション鍵を暗号化し、AES を使用してメッセージを暗号化し、最後にプロセスを逆転させてメッセージを復号化します。
ハイブリッド暗号の概要
このステップでは、ハイブリッド暗号化を強力で広く利用されている技術にしている中核となる概念を簡単に復習します。このステップで実行するコマンドはありません。目的は、実践的な作業を開始する前に、強固な概念的基盤を築くことです。
対称暗号化(例:AES)
- 仕組み: 暗号化と復号化の両方に、単一の共有シークレットキーを使用します。
- 強み: 非常に高速かつ効率的であり、大きなファイルやデータストリームの暗号化に最適です。
- 弱み: 鍵の配布(Key distribution)。共有シークレットキーをどのようにして安全に受信者に渡すか?攻撃者がその鍵を傍受した場合、すべての通信を復号化できてしまいます。
非対称暗号化(例:RSA)
- 仕組み: 暗号化用の公開鍵と復号化用の秘密鍵という、鍵のペアを使用します。公開鍵は自由に共有できますが、秘密鍵はその所有者によって秘密に保たれなければなりません。
- 強み: 鍵の配布の問題を解決します。誰でもあなたの公開鍵を使ってあなた宛てのメッセージを暗号化できますが、それを復号化できるのはあなたの秘密鍵を持つあなただけです。
- 弱み: 数学的に複雑であるため、対称暗号化よりもはるかに低速です。大量のデータを暗号化するには実用的ではありません。
ハイブリッドな解決策
ハイブリッド暗号化は、これら 2 つの手法を組み合わせることで、非対称暗号化のセキュリティと対称暗号化の速度の両方を得ます。典型的なワークフローは次のとおりです。
- 送信者(アリス)は、受信者(ボブ)に安全なメッセージを送信したいと考えます。
- アリスは、新しくランダムな対称セッション鍵を生成します。
- アリスはこの高速な対称セッション鍵を使用して、実際のメッセージを暗号化します。
- アリスはボブの公開鍵を入手します。それを使用して、小さな対称セッション鍵のみを暗号化します。
- アリスは、対称暗号化されたメッセージと非対称暗号化されたセッション鍵の両方をボブに送信します。
- ボブは 2 つのアイテムを受け取ります。彼はまず、秘密鍵を使用して暗号化されたセッション鍵を復号化します。
- ボブが元の対称セッション鍵を入手したので、それを使用して実際のメッセージを高速に復号化します。
このプロセスにより、バルクデータが効率的に暗号化され、その暗号化に使用された鍵が最大限のセキュリティで交換されることが保証されます。次のステップでは、この正確なワークフローを実装します。
RSA キーと AES キーの生成
このステップでは、ハイブリッド暗号化スキームに必要な 2 種類の鍵セットを生成します。非対称部分のための RSA 鍵ペア(公開鍵と秘密鍵)と、対称部分(AES)のためのランダムなセッション鍵です。すべての操作は~/projectディレクトリ内で行います。
まず、2048 ビットの RSA 秘密鍵を生成します。この鍵は受信者によって秘密に保たれる必要があります。
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
鍵が生成される際に、何らかの出力が表示されます。次に、作成した秘密鍵から対応する公開鍵を抽出する必要があります。この公開鍵は、暗号化されたメッセージを送信したい人なら誰とでも共有できます。
openssl rsa -pubout -in private_key.pem -out public_key.pem
このコマンドは writing RSA key と出力します。
次に、ランダムな 256 ビット(32 バイト)のセッション鍵を作成します。この鍵は AES アルゴリズムと組み合わせて、実際のデータを暗号化するために使用されます。ここでは、暗号学的に強力なランダムデータを生成し、扱いやすくするために Base64 でエンコードするためにopenssl randを使用します。
openssl rand -base64 32 > session_key.key
作成した鍵を確認するために、ディレクトリ内のファイルを一覧表示してみましょう。
ls -l
セットアップ時に作成されたmessage.txtファイルと共に、今生成した 3 つの鍵ファイルが表示されるはずです。
-rw-rw-r-- 1 labex labex 57 Oct 20 15:12 message.txt
-rw------- 1 labex labex 1704 Oct 20 15:14 private_key.pem
-rw-rw-r-- 1 labex labex 451 Oct 20 15:14 public_key.pem
-rw-rw-r-- 1 labex labex 45 Oct 20 15:14 session_key.key
セッションキーの RSA による暗号化
このステップでは、ハイブリッド暗号化プロセスの重要な部分、すなわち対称セッション鍵の暗号化を実行します。セッション鍵を意図した受信者のみが使用できるようにするため、受信者の RSA 公開鍵を使用して暗号化します。
ここでは、公開鍵操作のためのユーティリティであるopenssl pkeyutlコマンドを使用します。これを使用して、public_key.pemでsession_key.keyファイルを暗号化します。
次のコマンドを実行してください。
openssl pkeyutl -encrypt -pubin -inkey public_key.pem -in session_key.key -out encrypted_session_key.bin
このコマンドの内訳は以下の通りです。
pkeyutl: 公開鍵ユーティリティツール。-encrypt: 暗号化操作を実行することを指定します。-pubin: 入力鍵(-inkey)が公開鍵であることを示します。-inkey public_key.pem: 暗号化に使用する公開鍵を指定します。-in session_key.key: 暗号化される入力ファイル(AES セッション鍵)。-out encrypted_session_key.bin: 暗号化された鍵が保存される出力ファイル。
このコマンドは、セッション鍵が暗号化された形式で含まれる新しいファイルencrypted_session_key.binを作成します。このファイルは、対応する秘密鍵の所有者のみが復号化できるため、安全に送信できます。
新しく作成されたファイルを確認してみましょう。
ls -l encrypted_session_key.bin
暗号化された鍵を含むバイナリファイルが表示されます。
-rw-rw-r-- 1 labex labex 256 Oct 20 15:14 encrypted_session_key.bin
AES によるデータの暗号化
セッション鍵を保護したので、元の平文のセッション鍵を使用して、メインのデータファイルであるmessage.txtを高速に暗号化できます。このタスクには AES-256-CBC 対称暗号を使用します。
openssl encコマンドは、鍵と初期化ベクトル(IV)を 16 進数形式で提供することを要求します。私たちのsession_key.keyは Base64 形式なので、まずそれをデコードして 16 進数に変換する必要があります。また、ランダムな IV を生成します。便宜上、これら両方を環境変数に保存します。
まず、セッション鍵を変換し、AES_KEY変数に保存します。
export AES_KEY=$(cat session_key.key | base64 -d | xxd -p -c 32)
次に、128 ビット(16 バイト)のランダムな IV を生成し、AES_IV変数に保存します。IV は、同じ平文を複数回暗号化しても異なる暗号文が生成されるようにするために使用されます。
export AES_IV=$(openssl rand -hex 16)
鍵と IV の準備ができたので、openssl encを使用してmessage.txtを暗号化できます。
openssl enc -aes-256-cbc -in message.txt -out encrypted_message.dat -K $AES_KEY -iv $AES_IV
コマンドオプションを確認しましょう。
-aes-256-cbc: CBC モードの AES-256 暗号を指定します。-in message.txt: 入力データファイル。-out encrypted_message.dat: 暗号化されたデータの出力ファイル。-K $AES_KEY: 16 進数形式の暗号化鍵(大文字の K)。-iv $AES_IV: 16 進数形式の初期化ベクトル。
この時点で、送信者はencrypted_message.dat、encrypted_session_key.bin、および IV($AES_IV)をパッケージ化して受信者に送信することになります。この実験(Lab)では、復号化のステップのために必要なすべてのファイルがディレクトリ内に揃っています。
暗号化されたデータファイルが作成されたことを確認します。
ls -l encrypted_message.dat
-rw-rw-r-- 1 labex labex 64 Oct 20 15:14 encrypted_message.dat
メッセージの復号化
この最終ステップでは、受信者のアクションをシミュレートします。受信者は、暗号化されたデータ(encrypted_message.dat)、暗号化されたセッション鍵(encrypted_session_key.bin)、および IV を受け取ります。彼らは自身の秘密鍵を使用してプロセスを逆転させ、元のメッセージを復元します。
まず、受信者は自身のprivate_key.pemを使用してセッション鍵を復号化する必要があります。
openssl pkeyutl -decrypt -inkey private_key.pem -in encrypted_session_key.bin -out decrypted_session_key.key
このコマンドは、-decryptフラグと秘密鍵を使用してpkeyutlを実行し、元の AES セッション鍵を復元し、decrypted_session_key.keyに保存します。
復号化された鍵がステップ 2 で作成した元の鍵と同一であることを簡単に確認できます。ファイルが同じであれば、diffコマンドは何も出力しません。
diff session_key.key decrypted_session_key.key
セッション鍵が手に入ったので、メインメッセージを復号化できます。暗号化ステップと同様に、まず鍵を 16 進数形式に変換する必要があります。
export DECRYPTED_AES_KEY=$(cat decrypted_session_key.key | base64 -d | xxd -p -c 32)
最後に、-d(復号化)フラグを付けてopenssl encを使用し、暗号化に使用されたのと同じ鍵と IV を提供します。($AES_IV変数は、前のステップからシェルの設定が残っています)。
openssl enc -d -aes-256-cbc -in encrypted_message.dat -out decrypted_message.txt -K $DECRYPTED_AES_KEY -iv $AES_IV
プロセスは完了です!元のメッセージが復元され、decrypted_message.txtに保存されました。成功を確認するために、その内容を見てみましょう。
cat decrypted_message.txt
ターミナルに元の秘密メッセージが表示されるはずです。
This is a secret message that needs to be sent securely.
まとめ
この実験(Lab)では、OpenSSL を使用してハイブリッド暗号化および復号化のワークフロー全体を正常に実装しました。これにより、デジタル通信の多くを保護している基本的な概念について実践的な経験を積むことができました。
以下のことを学びました。
- 非対称暗号化のための RSA 鍵ペアの生成。
- 対称暗号化のためのランダムな AES セッション鍵の作成。
- RSA 公開鍵を使用したセッション鍵の安全な暗号化。
- AES セッション鍵を使用したバルクデータの効率的な暗号化。
- RSA 秘密鍵によるセッション鍵の復号化、およびそれに続くデータの復号化によるプロセスの逆転。
鍵交換には非対称暗号のセキュリティを、データ暗号化には対称暗号の速度を組み合わせるこの「両方の世界の最良」のアプローチは、毎日インターネット上のデータを保護する TLS/SSL のような最新のセキュリティプロトコルの基礎となっています。



