それはすべて、1つの小さなプロジェクトで暗号化を使用する必要があるという事実から始まりました。 クライアントは、傍受から保護されたメッセージをサーバーに送信する必要があります。 クライアント認証は原則として必要ではなく、データは一方向(クライアントからサーバー)にしか送られず、さらに、共通の暗号化キーの保存に煩わされたくなかったため、非対称暗号化を使用することを考え出しました。 アイデアは単純に見えます。クライアントにはサーバーの公開鍵が与えられ、サーバーに送信されるメッセージを暗号化します。 サーバー(および彼のみ)は、受信したメッセージを、自分が知っている秘密キーを使用して解読できます。
暗号化プリミティブを手動で実装することは恩恵がなく、エラーに満ちているため、上記のアイデアを実装するためにいくつかのオープンソースライブラリを使用することが決定されました。 このプロジェクトでは、すでにZeroMQライブラリとそのCZMQラッパーを使用していたため、 libsodiumライブラリに基づいたデータ転送のセキュリティが確保されたため 、彼女が選択しました。 確かに、すべてがすでに含まれているのに、なぜ依存関係を作成します。
libsodiumについて
公式Webサイトで述べたように、libsodiumは暗号化、電子デジタル署名、ハッシュなどのためのオープンでモダンなシンプルなライブラリです。
libsodiumを使用するプロジェクトや企業の印象的なリストもあります。たとえば、 Tox
libsodiumを使用するプロジェクトや企業の印象的なリストもあります。たとえば、 Tox
そのため、ドキュメントをすばやく読むと、ライブラリには公開鍵認証暗号化の楕円曲線上の非対称暗号化の実装が含まれていることがわかりました。 さらに、 MACを介してメッセージを認証することもできます。 MACの暗号化と生成は
crypto_box_easy
関数を使用して実行され、逆の手順(検証と復号化)は
crypto_box_open_easy
を使用して
crypto_box_open_easy
ます。
ドキュメントから:
オリジナル公開鍵認証暗号化を使用して、ボブはアリスの公開鍵を使用して、アリス専用の機密メッセージを暗号化できます。
ボリスの公開鍵を使用して、アリスは暗号化されたメッセージが実際にボブによって作成されたものであり、最終的に解読する前に改ざんされていないことを確認できます。
アリスが必要とするのは、ボブの公開鍵、ナンス、および暗号文だけです。 ボブは、アリスとさえ、彼の秘密鍵を決して共有すべきではありません。
そして、アリスにメッセージを送信するために、ボブはアリスの公開鍵のみを必要とします。 アリスは、ボブとさえ、彼女の秘密鍵を決して共有すべきではありません。
認証サポート付きの公開キー暗号化を使用すると、Bobは公開キーを使用してAliceの機密メッセージを暗号化できます。
ボブの公開鍵を使用して、アリスは暗号化されたメッセージが実際にボブによって作成されたものであり、偽造されていないことを復号前に確認できます。
アリスに必要なのは、ボブの公開鍵、ナンス、および暗号化されたメッセージだけです。 ボブは、アリスからも秘密鍵を秘密にしなければなりません。
アリスにメッセージを送信するには、ボブはアリスの公開鍵のみが必要です。 アリスは、ボブからも秘密鍵を秘密にしなければなりません。
すべてがシンプルで明確なようです。 クライアントはサーバーの公開鍵でメッセージを暗号化し、秘密鍵でメッセージに署名します。 メッセージを受信したサーバーは、クライアントの公開キーを使用してチェックし、秘密キーで解読します。 サーバーは別として、公開鍵で暗号化されているため、メッセージを解読することはできません(少なくともこれは非対称暗号化の主要な原則です)。 しかし、悪魔は詳細にあります。
概念をテストするために、公式サイトから例をコピーしましたが、誤ってミスをして、奇妙な結果を得ました。
テストコード
#include <string.h> #include "sodium.h" #define MESSAGE "test" #define MESSAGE_LEN 4 #define CIPHERTEXT_LEN (crypto_box_MACBYTES + MESSAGE_LEN) static bool TestSodium() { unsigned char alice_publickey[crypto_box_PUBLICKEYBYTES]; unsigned char alice_secretkey[crypto_box_SECRETKEYBYTES]; crypto_box_keypair(alice_publickey, alice_secretkey); unsigned char bob_publickey[crypto_box_PUBLICKEYBYTES]; unsigned char bob_secretkey[crypto_box_SECRETKEYBYTES]; crypto_box_keypair(bob_publickey, bob_secretkey); unsigned char nonce[crypto_box_NONCEBYTES]; unsigned char ciphertext[CIPHERTEXT_LEN]; randombytes_buf(nonce, sizeof nonce); // message alice -> bob if (crypto_box_easy(ciphertext, (const unsigned char*)MESSAGE, MESSAGE_LEN, nonce, bob_publickey, alice_secretkey) != 0) { return false; } unsigned char decrypted[MESSAGE_LEN + 1]; decrypted[MESSAGE_LEN] = 0; // //if (crypto_box_open_easy(decrypted, ciphertext, CIPHERTEXT_LEN, nonce, alice_publickey, bob_secretkey) != 0) // "" if (crypto_box_open_easy(decrypted, ciphertext, CIPHERTEXT_LEN, nonce, bob_publickey, alice_secretkey) != 0) { return false; } if(strcmp((const char*)decrypted, MESSAGE) != 0) return false; return true; }
アリスとボブのテストでは、最初にキーのペア(
crypto_box_keypair
)がランダムに生成され、次にノンス(
randombytes_buf
)がランダムに満たされます。 その後、アリスは公開キーを使用してボブへのメッセージを暗号化し、秘密キーを使用してMACを形成します。
// message alice -> bob if (crypto_box_easy(ciphertext, (const unsigned char*)MESSAGE, MESSAGE_LEN, nonce, bob_publickey, alice_secretkey) != 0) { return false; }
ただし、復号化手順で、ミスをして間違ったパラメーターを渡しました。 Bobのメッセージをプライベートキーで解読する代わりに、BobのパブリックキーとAliceのプライベートキーでメッセージを解読しようとしました(
// "" if (crypto_box_open_easy(decrypted, ciphertext, CIPHERTEXT_LEN, nonce, bob_publickey, alice_secretkey) != 0) { return false; }
メッセージが解読されたときの驚きを想像してください! それは非常に奇妙で、私を認知的不協和音の状態にしました。
私が最初に考えたのは、元の例のように復号化することであり、すべてが問題なく行われました-メッセージは復号化され、検証されました。 したがって、復号化(および確認)するには、メッセージは任意のキーペア(ボブの公開キーとアリスの秘密キー、またはその逆)になります。ボブのプライベートキーとアリスの公開キーです。
2番目の考えは、古いバージョンのライブラリを使用していたことです。 最新バージョンに更新されましたが、テストの動作は変更されていません。
率直に言って、私はlibsodiumソースを掘り下げる時間と欲求がほとんどありませんでした。 答えはStackoverflowで見つかりました。 libsodiumは、「公開鍵認証暗号化」を、私に思われたものとは多少異なる方法で理解していません。
詳細なレビューの後、暗号化アルゴリズムは次のようになりました。
- ECDHアルゴリズムを使用して、対称暗号の共通キーが生成されます。
- メッセージは、最初のステップで取得した共有キーを使用して、 XSalsa20対称暗号を使用して暗号化されます。
- MAC シミュレーター ( Poly1305 )は、同じ共有キーを使用して生成されます。
このアルゴリズムの次の結論と特性は、これに基づいています。
- BobまたはAliceによって生成された同じメッセージ(それぞれが相手の秘密鍵と公開鍵を使用してメッセージを生成します)は、同じ暗号化されたメッセージを生成します。
- 前の結論から、誰にメッセージを誰に書いたのかを正確に言うことは不可能であることがわかります-ボブアリスまたはアリスボブ。
- アリスの秘密鍵が危険にさらされると、これは以前にボブに送信されたすべてのメッセージを解読します(これは非対称暗号化の利点の1つです)。
- アリスの秘密鍵が危険にさらされると、攻撃者はボブからアリス宛てのメッセージを偽造できます(ボブの秘密鍵を知らなくても)。
アルゴリズムのこれらの特性は正常であり、事実は間違ったアルゴリズムを適用しようとしたことです。 ただし、公式Webサイトのドキュメントは、作品の機能やその使用に適した状況についてユーザーを誤解させると考えています。
私の目標は、秘密鍵を知らずにサーバーのメッセージを復号化できないアルゴリズムを使用することであったため、この暗号プリミティブのこの動作は私に合わず、使用を拒否しました。
私は考えを取り除くことができません:誰かがこの方法を使用して、実績のあるライブラリの信頼性を期待して真に重要なシステムを実装した場合、別のミスを認識し、関数の「奇妙な」動作に偶然つまずいたため。
私は誰かに役立っていたと思います。 皆さん、頑張ってください。