Share via


ソース コードの概要 (CNG の例)

この概要では、CNG (Cryptography Next Generation) のセキュリティで保護された通信の例について、そのさまざまなコード要素間で行われるやり取りを全体的に説明します。

ここでは、例について次の点から説明します。

  • アプリケーション

  • [ファイル]

  • クラス

  • セキュリティのバージョン

  • セッションの概要

  • 暗号化キー (バージョン 2 ~ 5)

  • パブリック チャネルを介して交換されるデジタル署名 (バージョン 3)

  • プライベート チャネルを介して交換されるデジタル署名 (バージョン 4)

  • セッションの終了 (バージョン 5)

  • 追加情報

  • CNG の例の制限

アプリケーション

この例は、Alice、Bob、および Mallory という 3 つの独立したコンソール アプリケーションで構成されています。各アプリケーションは、個別の Visual Studio プロジェクトとしてビルドされ、1 つのメイン ファイルと 3 つの共有ファイルから成っています。各アプリケーションとそのファイルを次の表に示します。

アプリケーション (プロジェクト) 名

[ファイル]

Alice

  • Alice.cs (メイン ファイル)

  • Utilities.cs

  • ChannelManager.cs

  • Communicator.cs

Bob

  • Bob.cs (メイン ファイル)

  • Utilities.cs

  • ChannelManager.cs

  • Communicator.cs

Mallory

  • Mallory.cs (メイン ファイル)

  • Utilities.cs

  • ChannelManager.cs

  • Communicator.cs

[ファイル]

次のセクションの表は、各アプリケーションで使用されるクラスとメソッドを、ソース コードに出現する順にまとめたものです。

Alice.cs、Bob.cs、および Mallory.cs

クラス、メソッド、または

グローバル変数名

用途

CNG_SecureCommunicationExample

プロジェクト全体の部分クラス。

MyColor

OtherColor

fDisplaySendMessage

グローバル変数。

Main

各アプリケーションのプログラムのエントリ ポイント。このメソッドは次の処理を行います。

  • Alice によって呼び出された場合は、Bob.exe と Mallory.exe を自動的に読み込みます。

  • 処理ループを作成します。

  • InitConsole メソッドを呼び出し、コンソールのサイズ、位置、およびタイトルを設定します。

  • Run メソッドを呼び出します。

Run

InitializeOptions メソッドを呼び出し、選択されたセキュリティのシナリオを作成するメソッド。

Utilities.cs

クラス、メソッド、または

グローバル変数名

用途

CNG_SecureCommunicationExample

プロジェクト全体の部分クラス。

Version

fVerbose

fMallory

グローバル変数。

Autoloader

Alice によって呼び出され、Bob.exe と Mallory.exe の各アプリケーションを読み込むメソッド。

InitConsole

ユーザー インターフェイス メニューおよびアプリケーション レベルのメッセージを処理するメソッド。

SplashScreen

コンソール ウィンドウのタイトルを設定するメソッド。

ReadALine

コンソールからユーザーが入力した行を読み込むユーティリティ メソッド。

ReadAChar

質問を表示し、Yes または No の回答をユーザーに求めるユーティリティ メソッド。

InitializeOptions

オプションを表示し、ユーザーに 1 つを選択するように求めるメソッド。このメソッドは、Version、fVerbose、および fMallory の各グローバル フラグも設定します。

Display(string s)

2 つの Display メソッドの 1 つ目。このメソッドは、受け取った文字列と MyColor 変数を 2 つ目の Display メソッドに渡します。

Display(string DisplayString, int color)

2 つの Display メソッドの 2 つ目。このメソッドは、Console.WriteLine ステートメントをラップし、出力行の色分けをサポートします。

これらのクラス、メソッド、および変数の詳細については、「Utility クラスのコード分析 (CNG の例)」を参照してください。

ChannelManager.cs

クラス、メソッド、または

グローバル変数名

用途

CNG_SecureCommunicationExample

プロジェクト全体の部分クラス。

AppControl

内部アプリケーション制御を実行し、3 つのコンソール アプリケーションを同期するメソッド。

Alice は、このメソッドを使用して、Bob および Mallory にプログラム オプション (Version フラグと fVerbose フラグ) を送信します。

AppControl はメッセージング メソッドではありません。そのコンテンツは暗号化も署名もされません。Communicator クラスは呼び出されません。

SendChannelName

ReceiveChannelName

PublicChannel 名前付きパイプから AliceAndBobChannel 名前付きパイプおよび AliceAndBobChannel1 名前付きパイプへの切り替えに使用されるメソッド。これらのメソッドによって、CNG の例の概要で説明されている意図的なセキュリティ侵害が実現されます。

ChannelManager

アプリケーションのプロセス間通信フレームワークを提供するクラス。

これらのクラスおよびメソッドの詳細については、「ChannelManager クラスのコード分析 (CNG の例)」を参照してください。

Communicator.cs

クラス、メソッド、または

グローバル変数名

用途

CNG_SecureCommunicationExample

プロジェクト全体の部分クラス。

Communicator

すべての暗号関数をカプセル化するクラス。このクラスは、Alice、Bob、および Mallory 間のすべてのメッセージを処理します。これは、ChannelManager の AppControl メソッドから送信されたメッセージは処理しません。

m_DSKey

m_ECDH_Cng

m_ECDH_local_publicKey_XML

m_ECDH_remote_publicKey

ChMgr

クラス変数。

Communicator

Communicator オブジェクトを構築するメソッド。

Dispose

プライベートに保持されたリソースを解放するメソッド。

StoreDSKey

デジタル署名キーを格納するメソッド。

Send_or_Receive_PublicCryptoKey

キーの交換をサポートするメソッド。

iv

ciphertext

signature

プレーンテキスト メッセージの暗号化に使用されるプライベート クラス変数。これらの変数は、ReceiveMessage() メソッドの近くに宣言されています。

ReceiveMessage

セキュリティ バージョンに応じて、プレーンテキスト メッセージまたは暗号化されたメッセージを受信するメソッド。

SendMessage

プレーンテキスト メッセージを受け取り、セキュリティ バージョンに応じて、そのメッセージをプレーンテキスト形式または暗号化された形式で送信するメソッド。

これらのクラス、メソッド、および変数の詳細については、「Communicator クラスのコード分析 (CNG の例)」を参照してください。

クラス

各プロジェクトには、次の 3 つのクラスが含まれています。

  • public partial class CNG_SecureCommunicationExample

    このクラスは、Alice、Bob、および Mallory の各アプリケーションに含まれる 4 つのプロジェクト ファイル全体に分散しています。コンパイル後、CNG_SecureCommunicationExample クラスには、4 つのプロジェクト ファイルのクラス、変数、およびメソッドがすべて含まれます。部分クラスの詳細については、「部分クラスと部分メソッド (C# プログラミング ガイド)」を参照してください。

  • internal sealed class ChannelManager

    このクラスでは、名前付きパイプをサポートします。各プロジェクトは、プログラムの実行中に別々のタイミングでいくつかの ChannelManager インスタンスを作成します。このクラスの詳細については、「ChannelManager クラスのコード分析 (CNG の例)」を参照してください。

  • internal sealed class Communicator

    このクラスでは、暗号化と復号化をサポートします。各プロジェクトは、プログラムの実行中に別々のタイミングでいくつかの Communicator インスタンスを作成します。このクラスの詳細については、「Communicator クラスのコード分析 (CNG の例)」を参照してください。

セキュリティのバージョン

ソース コードは、CNG の例の概要で説明されているセキュリティのシナリオをサポートします。コードによって、次の 5 つのバージョンのインスタント メッセージング (IM) ツールが実装されます。これらは 5 段階のセキュリティ レベルを表します。

  • バージョン 1: プレーンテキスト メッセージおよび名前付きパイプを使用します。

  • バージョン 2: 暗号化メッセージを使用します。

  • バージョン 3: 暗号化メッセージとデジタル署名を使用します。

  • バージョン 4: 暗号化メッセージとプライベートなデジタル署名を使用します。

  • バージョン 5: セキュリティ エラーが発生するとアプリケーションを終了します。

注意

このトピックの残りの部分では、これらのバージョンを数字で表します。また、"Alice"、"Bob"、および "Mallory" という名前は、文脈に応じて、例のシナリオに登場する 3 人の人物を指したり、3 つの Visual Studio アプリケーションを指したりすることがあります。

セッションの概要

Alice、Bob、および Mallory には、それぞれ Main メソッドと Run メソッドがあります。

Main メソッドは、アプリケーションを同期し、次の機能を実行します。

  • 起動時のスプラッシュ スクリーンを表示します。

  • ユーザーにセッション オプションの選択を求めます (Alice のみ)。

  • セッション オプションを Bob および Mallory に送信します (Alice のみ)。

  • セッション オプションを Alice から受信します (Bob および Mallory のみ)。

  • Run メソッドを呼び出し、要求されたセキュリティ セッションを実行します。

Run メソッドは、セキュリティのシナリオを実行します。

  • 各セッションは、前のセクションで説明したいずれかのバージョンを表します。

  • Alice、Bob、および Mallory が Run メソッドに入るとセッションが開始され、Main メソッドに戻るとセッションが終了します。

  • Alice、Bob、および Mallory は、セッションの間、常に同じバージョンを実行します。

  • Alice は、セッション中に実行されるすべてのトランザクションを開始します。Mallory は、Alice に応答し、Bob とのトランザクションを開始します。Bob は応答のみを行います。

Alice と Bob のソース コードは非常に似ています。主な違いは、Alice は各セッションを開始してパイプ サーバーとして動作するのに対し、Bob はパイプ クライアントとして動作する点です。Mallory のコードは、2 つの個別のパイプ (Alice とのパイプと Bob とのパイプ) を管理するため、より複雑になります。

Main メソッド

Alice は、Main メソッドの開始時に InitializeOptions メソッドを呼び出し、ユーザーからセッション オプション (Version、fVerbose、fMallory) を受け取ります。これらのオプションは、AppControl メソッドを使用して Bob と Mallory に送信されます。Bob と Mallory は、各自の AppControl メソッドを使用してオプションを受信します。ユーザーが文字「x」を入力してアプリケーションを閉じようとすると、Alice の AppControl メソッドは、セッション オプションの代わりに "exit" という文字列を Bob と Mallory に送信します。

3 つのアプリケーションがセッション オプションを受信した後で、各アプリケーションは自身の Run メソッドを呼び出します。

Run メソッド

Alice、Bob、および Mallory は、次の手順を実行して、要求されたセッションを実行します。

  1. Alice は SendChannelName メソッドを呼び出します。このメソッドでは、PublicChannel というチャネルが使用されます。Alice は Bob に新しいチャネル名 (AliceAndBobChannel) を送信します。

  2. fMallory フラグが true に設定されている場合、Mallory は PublicChannel で待機し、Alice からの新しいチャネル名 (AliceAndBobChannel) を傍受します。Mallory は Bob に別のチャネル名 (AliceAndBobChannel1) を送信します。

  3. Alice と Bob は、各自にちなんだ名前の Communicator オブジェクトを作成します。これらのオブジェクトは、C# の using ステートメント内で作成され、Run メソッドの終了時に破棄されます。

    Alice はパイプ サーバーとして初期化されます。

    using (Communicator Alice = new Communicator("server", NewChannelName))
    

    Bob はパイプ クライアントとして初期化されます。

    using (Communicator Bob = new Communicator("client", NewChannelName))
    

    Mallory は、2 つの Communicator オブジェクト (MalloryAlice と MalloryBob) を作成します。Mallory は、Alice に対してはパイプ クライアントとして初期化されます。

    using (Communicator MalloryAlice = new Communicator("client", AliceChannelName))
    

    Mallory は、Bob に対してはパイプ サーバーとして初期化されます。

    using (Communicator MalloryBob = new Communicator("server", BobChannelName"))
    
  4. Communicator クラスのコンストラクターは、チャネル名を受け取り、ChMgr という長期間のパブリック ChannelManager オブジェクトを作成します。

    ChMgr = new ChannelManager(mode, ChannelName);
    
  5. ChannelManager コンストラクターは、チャネル名を受け取り、対応する名前付きパイプを作成します。

    注意

    この時点で、Alice と Mallory の間では AliceAndBobChannel 名前付きパイプを介した通信が、Mallory と Bob の間では AliceAndBobChannel1 名前付きパイプを介した通信が始まっています。

    AliceAndBobChannel と AliceAndBobChannel1 は、セキュリティのシナリオが終わるまで (つまり、Run メソッドの終了まで) 開いたままになる長期間のチャネルです。

  6. 次に行われる処理は、セキュリティ バージョンを制御する fVersion フラグの値と、Mallory の介入を制御する fMallory フラグの値によって決まります。

    バージョン 3 では、PublicChannel を介して、Alice から Bob にデジタル署名キーが送信されます。Alice と Bob は、このデジタル署名キーを使用してキーとメッセージに署名します。fMallory が true の場合、Mallory はデジタル署名キーを傍受し、Alice および Bob に送信するキーとメッセージへの署名に使用します。

    バージョン 4 およびバージョン 5 では、Alice は、2 つのデジタル署名キーを Bob に送信します。デジタル署名キー 1 は、バージョン 3 で Alice が送信していたキーと同じです。デジタル署名キー 2 は、Mallory では認識されないデジタル署名の秘密キーです。

  7. Alice と Bob がバージョン 2 ~ 5 の公開暗号化キーを交換します。fMallory が true の場合、Mallory はその公開キーを傍受し、自身のものに置き換えます。

  8. Alice と Bob がメッセージを交換します。fMallory が true の場合、Mallory は、Alice のメッセージと Bob のメッセージを傍受し、変更して、再送信します。

  9. Alice と Bob の対話が終了した後で、ユーザー独自のメッセージを送信するかどうかをたずねるプロンプトが表示されます。これにより、メッセージが暗号化される過程や、メッセージを変更するために Mallory が何を行っているかを確認できます。終了したら、Enter キーを押して Alice に制御を戻します。

  10. Alice がセッションを終了します。Alice、Bob、および Mallory の Run メソッドは、それぞれの Main メソッドに制御を戻し、例が再起動されます。

暗号化キー (バージョン 2 ~ 5)

バージョン 2 ~ 5 では、AES (Advanced Encryption Standard) アルゴリズムを使用してメッセージが暗号化されます。暗号化キーの交換は、Alice、Bob、および Mallory の Run メソッドで、次のコード ステートメントの後に実装されています。

if (2 <= Version)

暗号化キーは、Communicator クラスのコンストラクターで作成される長期間のパブリック ChannelManager オブジェクト (ChMgr) によって送信されます。

次の 2 つのコード ステートメントは、暗号化キーを Alice が送信する方法と、Bob が受信する方法を示しています。

Alice.Send_or_Receive_PublicCryptoKey("send", MyColor);
Bob.Send_or_Receive_PublicCryptoKey("receive", OtherColor);

2 番目のパラメーターは、受信側アプリケーションが暗号化キーの内容を表示するときに使用する色を定義します。

AES の実装は、数学的には解読不可能であると考えられます。ただし、AES には、man-in-the-middle 攻撃に対する保護は用意されていません。AES がこのような強力な暗号化を備えているのに、Mallory が Alice と Bob のメッセージを復号化できるのは矛盾しているように見えるかもしれません。これが可能なのは、Mallory が Alice と Bob の共有秘密協定を把握しているためです。Mallory がキーを傍受して置き換えることで、強力な AES も無意味になります。

認証なしの暗号化キーを使用することは、セキュリティで保護されているという誤った認識を与えます。Alice と Bob は、バージョン 2 によりメッセージ転送方式がセキュリティで保護されていると考えていますが、実際には、最初のメッセージが送信される前にセキュリティの問題が生じています。

Alice と Bob の会社では、社内から攻撃を受けているのか、外部から受けているのかも把握していません。そこで、攻撃元を突き止めるためにバージョン 3 の IM ツールを設計します。

パブリック チャネルを介して交換されるデジタル署名 (バージョン 3)

バージョン 3 では、デジタル署名を使用してキーとメッセージに署名することにより、バージョン 2 のセキュリティの欠陥を修正します。デジタル署名キーの交換は、Alice、Bob、および Mallory の Run メソッドで、次のコード ステートメントの後に実装されています。

if (3 <= Version)

デジタル署名キーは、暗号化キーと同じ長期間のパブリック チャネルを介して送信されます。デジタル署名キーを送信するためのコードを次に示します。

Alice.ChMgr.SendMessage(dsKeyBlob);

注意

デジタル署名キーを送信する ChannelManager インスタンス (ChMgr) は、Alice の Communicator オブジェクトのメンバーです。

Alice と Bob は、それぞれの Communicator オブジェクトのプライベート メンバーとしてデジタル署名キーを格納します。

Alice.StoreDSKey(DSKey);
Bob.StoreDSKey(DSKey);

残念ながら、Mallory は PublicChannel から簡単にデジタル署名をコピーして保存します。

Mallory.StoreDSKey(DSKey);

署名されたメッセージが Alice と Bob で互いに受信されたとき、デジタル署名はメッセージと完全に一致します。これは、Alice と Bob によって使用されているのと同じ署名キーで Mallory が署名したためです。

バージョン 3 では、暗号化キーとデジタル署名の両方が、企業ネットワーク上のパブリック チャネルで交換されます。Alice と Bob が働く会社は、会社内に盗用を行っている者がいるのではないかと疑いを持ちました。そこで、この考えを検証するためにバージョン 4 を作成します。

プライベート チャネルを介して交換されるデジタル署名 (バージョン 4)

バージョン 4 では、2 つのデジタル署名キーを使用します。バージョン 3 で使用されたキーと、プライベート チャネルを介して送信される 2 番目の秘密キーです。最初のキーは、ここでは盗用をトラップするために、偽のデジタル キーとして扱われます。2 番目のキーは、暗号化キーとメッセージにデジタル署名するために、Alice と Bob によって使用されます。

バージョン 4 の IM ソフトウェアは、Alice と Bob だけに与えられます。Mallory はバージョン 3 を使い続けているため、自分の使用しているデジタル署名が無効であることに気付きません。ただし、Alice と Bob の IM ツールは、キーやメッセージを 1 回受信するたびにセキュリティの警告を表示します。

バージョン 4 では、暗号化キーとメッセージの両方が傍受されていることも明らかになります。これにより、man-in-the-middle 攻撃を受けていること、その攻撃は暗号化キーの送信前から開始されていたことがわかります。つまり、企業の PublicChannel へのアクセス権を持つ会社の従業員が、Bob よりも先にログインしていたことになります。デジタル署名の秘密キーを上手に使用すると、Mallory の極秘の活動を暴くことができます。

デジタル署名の共有キーの送信は、Alice および Bob の Run メソッドで、次のコード ステートメントの後に実装されています。

if (4 <= Version)

Alice と Bob のプライベートな ChannelManager インスタンスを作成するコード ステートメントを次に示します。

ChannelManager ChMgr2 = new ChannelManager("server", "PrivateChannel")
ChannelManager ChMgr2 = new ChannelManager("client", "PrivateChannel")

Alice と Bob が使用するプライベート チャネル (ChMgr2) は、それぞれの Communicator オブジェクトのメンバーではありません。これは、次の 2 つのコード ステートメントを比較することで確認できます。

Alice.ChMgr.SendMessage(dsKeyBlob); // Public channel - fake key
ChMgr2.SendMessage(dsKeyBlob);      // Private channel - real key

最初のステートメントでは、Run メソッドの開始時に作成される長期間の ChannelManager インスタンス (ChMgr) を使用します。このインスタンスは、セッションが終了するまで、Alice、Bob、および Mallory の Communicator オブジェクト (「セッションの概要」セクションの手順 3. を参照) のパブリック メンバーとして保持されます。2 番目のステートメントでは、キーを送受信する間のみ存在する一時的なオブジェクトを使用します。これは使用後に直ちに破棄されます。

Alice がデジタル署名の共有キーを送信すると、Bob は次のステートメントを使用してそれを受け取ります。

DSKey = ChMgr2.ReadMessage();

Alice と Bob は、それぞれの Communicator オブジェクトのプライベート メンバーとしてキーを格納します。

Alice.StoreDSKey(DSKey);
Bob.StoreDSKey(DSKey);

また、これらのステートメントは、偽のデジタル署名キーを上書きします。

バージョン 4 では、Alice と Bob は、偽のデジタル署名キーの代わりにデジタル署名の秘密キーを使用して、キーおよびメッセージに署名します。バージョン 4 では、暗号化キーへの署名も行い、メッセージのデジタル署名がメッセージと一致しない場合はセキュリティの警告を表示します。

セッションの終了 (バージョン 5)

バージョン 5 は、最初のエラーの発生後にセッションを終了する点を除き、バージョン 4 と同じです。Alice は、Bob の公開暗号化キーを受信するときに最初のエラーを受け取り、無効なデジタル署名が使用されたことに気付きます。Bob もまた、Alice の公開暗号化キーを受信するときに最初のエラーを受け取り、無効なデジタル署名が使用されたことに気付きます。

追加情報

  • オブジェクトの破棄 : C# の using ステートメントにより、セキュリティが強化されます。これは、ChannelManager オブジェクトと Communicator オブジェクトをすべて包含するために使用されます。これらのオブジェクトがスコープ外に出ると、Dispose メソッドが直ちに呼び出され、内部的に保持されたリソースが解放されます。

  • エンコード方法 : 暗号化データを送信するときは、常に UTF8 または Unicode でエンコードし、ASCII は避ける必要があります。

CNG の例の制限

CNG のセキュリティで保護された通信の例は、管理された CNG の機能を具体的に示すことを目的としています。そのため、次のような一部の機能は省略されています。

  • すべてのメソッドにおけるパラメーターの検証。

  • try/catch ブロックの広範な利用。

  • 信頼性の高いパイプ接続解除の検出。

  • 画面出力のファイルへの記録。

  • 暗号化アルゴリズムの動的設定。

  • デジタル署名アルゴリズムの動的設定。

  • デジタル署名キーを Bob に送信する別の方法。PrivateChannel 名前付きパイプは単純なソリューションです。より高度な他の方法もあります。

  • キーの永続化、格納、および取得。

  • オペレーティング システムによって生成されたデジタル署名キーの使用。

  • 公開キー基盤 (PKI: Public Key Infrastructure) によって指定されたキーの使用。

これらの機能を実装するとコードがさらに複雑になるため、この例では扱いません。

参照

概念

CNG (Cryptography Next Generation) のセキュリティで保護された通信の例

キーとメッセージの交換手順 (CNG の例)

出力される結果 (CNG の例)