Share via


Communicator クラスのコード分析 (CNG の例)

Communicator.cs ファイルは、CNG (Cryptography Next Generation) のセキュリティで保護された通信の例で使用される、暗号化メソッドと復号化メソッドをカプセル化します。これは、Communicator という名前の 1 つのクラスだけで構成されます。このクラスには、次の各セクションで説明するメンバーとメソッドが含まれています。

  • クラス メンバー

  • クラス コンストラクター

  • Dispose メソッド

  • StoreDSKey メソッド

  • Send_or_Receive_PublicCryptoKey メソッド

  • SendMessage メソッド

  • ReceiveMessage メソッド

ここで説明している例の概要およびバージョンの説明については、「CNG (Cryptography Next Generation) のセキュリティで保護された通信の例」を参照してください。

クラス メンバー

Communicator クラスには、次のプライベート メンバーが含まれています。

  • CngKey m_DSKey

    このメンバーは、Communicator.StoreDSKey でデジタル署名キーを格納するために使用されます。

  • ECDiffieHellmanCng m_ECDH_Cng

    このメンバーは、ECDiffieHellmanCng クラスのインスタンスを格納するためにコンストラクターで使用されます。ReceiveMessage メソッドと SendMessage メソッドは、このメンバーを使用してキー マテリアルを派生させます。

  • string m_ECDH_local_publicKey_XML

    このメンバーは、ローカルの ECDH (Elliptic Curve Diffie-Hellman) 公開暗号化キーの XML 文字列表現を格納するためにコンストラクターで使用されます。Alice、Bob、および Mallory は、Send_or_Receive_PublicCryptoKey メソッドを使用してこの XML 文字列を交換します。

  • ECDiffieHellmanPublicKey m_ECDH_remote_publicKey

    このメンバーは、リモートの ECDH 公開暗号化キーを格納するために Send_or_Receive_PublicCryptoKey メソッドで使用されます。

Communicator クラスには、次のパブリック メンバーもあります。

  • ChannelManager ChMgr

    このメンバーは、名前付きパイプ サービスを提供するために Alice、Bob、および Mallory によって使用されます。

クラス コンストラクター

public Communicator(string mode, string ChannelName)

コンストラクターは、次の 3 つのオブジェクトを作成します。

  • 521 ビットのキー サイズを使用し、ランダムなキー ペアを持つ ECDiffieHellmanCng クラスのインスタンス

    m_ECDH_Cng = new ECDiffieHellmanCng(521)
    

    結果として生成されるオブジェクトは、プライベート メンバーとして Communicator クラスにバインドされます。各 Communicator オブジェクトは、このクラスのインスタンスを 1 つ作成します。

    Alice と Bob は、それぞれ 1 つの Communicator オブジェクトを作成するので、単一の m_ECDH_Cng メンバーにアクセスできます。Mallory は、2 つの Communicator オブジェクトを作成します。1 つは Alice と使用し、もう 1 つは Bob と使用します。したがって、Mallory は 2 つの m_ECDH_Cng メンバーにアクセスできます。

  • プライベートな XML 文字列として保持される ECDH 公開キー

    m_ECDH_XmlString = m_ECDH_CryptoKey.ToXmlString(ECKeyXmlFormat.Rfc4050)
    

    ECDiffieHellmanCng.ToXmlString メソッドは、ECKeyXmlFormat.Rfc4050 形式を使用して公開 ECDH キーをシリアル化します。

    例のバージョン 2 ~ 5 では、Alice の Run メソッドで、次のコード ステートメントを使用して Alice から Bob に結果の XML 文字列が送信されます。

    Alice.Send_or_Receive_PublicCryptoKey("send", MyColor);
    
  • ChannelManager クラスのパブリック インスタンス

    ChMgr = new ChannelManager(mode, ChannelName)
    

    コンストラクターは、次の 2 つのパラメーターを受け取ります。

    • mode: 名前付きパイプの作成方法を示す文字列。このパラメーターには、"server" または "client" を指定できます。

    • ChannelName: 新しい名前付きパイプを識別する名前を示す文字列。

Dispose メソッド

public void Dispose()

Communicator クラスは、IDisposable インターフェイスを継承し、Dispose メソッドを提供して、機密性の高いリソースを即座に解放します。このようなリソースとして、m_ECDH_Cng、m_ECDH_local_publicKey_XML、および ChMgr の各オブジェクトがあります。

スコープ外に出たオブジェクトが直ちに解放されるようにするために、各オブジェクトは C# の using ステートメント内で作成されます。

StoreDSKey メソッド

public void StoreDSKey(byte[] DSKeyBlob)

このメソッドは、バイト配列に格納されたバイナリ ラージ オブジェクト (BLOB: Binary Large Object) を受け取ります。CngKey.Import(array<Byte[], CngKeyBlobFormat) メソッドを使用して、キー BLOB からデジタル署名キーを抽出します。このキーは次のコードによって格納されます。

m_DSKey = CngKey.Import(DSKeyBlob,CngKeyBlobFormat.Pkcs8PrivateBlob);

StoreDSKey メソッドは、次のバージョンにおいて、Alice、Bob、および Mallory の Run メソッドで呼び出されます。

  • バージョン 3 ~ 5 では、Alice、Bob、および Mallory はこのメソッドを使用して、パブリックに転送された同一のキーを格納します。

  • バージョン 4 およびバージョン 5 では、Alice と Bob はこのメソッドの 2 度目の呼び出しを行い、プライベートに転送されたキーで m_DSKey メンバーを上書きします。

Send_or_Receive_PublicCryptoKey メソッド

Send_or_Receive_PublicCryptoKey(string mode, int color)

このメソッドは、次の 2 つのパラメーターを受け取ります。

  • mode: キーを送信するパイプ サーバーを作成するか、キーを受信するパイプ クライアントを作成するかを示す文字列。このパラメーターには、"server" または "client" を指定できます。

  • color: キーの表示に使用される色を指定する整数。

Send_or_Receive_PublicCryptoKey メソッドは、CommunicatorReceiveMessage メソッドと SendMessage メソッドに似ていますが、暗号化メッセージではなく暗号化されていないキーを送受信する点が異なります。ReceiveMessage と SendMessage は暗号化されていないキーには使用できません。これらのメソッドでは、キーの暗号化と復号化が試みられるためです。

キーが交換された後、例のバージョン 3 ~ 5 では、キーのデジタル署名が検証されます。バージョン 3 は、PublicChannel 名前付きパイプを介して送信されるデジタル署名を使用します。この署名は Mallory によって傍受され、Alice および Bob に送信する代替キーとメッセージに署名するために使用されます。バージョン 3 では、Alice、Bob、および Mallory が同一のデジタル署名キーを使用するため、署名の検証は常に成功します。

注意

バージョン 4 およびバージョン 5 は、プライベートなデジタル署名を使用してキーとメッセージに署名し、セキュリティの警告を表示します。これらのバージョンは Alice と Bob だけに与えられます。そのため、Mallory は自分の傍受が検出されていることに気付きません。

SendMessage メソッド

public bool SendMessage(string plainTextMessage, bool fShowMsg)

このメソッドは、Alice、Bob、および Mallory の Run メソッドから呼び出されます。次の手順に従って、メッセージを暗号化、デジタル署名、および送信します。

  1. fShowMsg 値が true の場合、プレーンテキスト メッセージを表示します。

  2. 次のコードを使用して、メッセージを Unicode のバイト配列に変換します。

    byte[] UnicodeText = Encoding.Unicode.GetBytes(plainTextMessage);
    
  3. メッセージをプレーンテキストで送信する必要があるかどうかを判断します。例でバージョン 1 を実行している場合、SendMessage は次のコードを使用してメッセージを送信し、制御を戻します。

    ChMgr.SendMessage(UnicodeText);
    
  4. ECDiffieHellmanCng.DeriveKeyMaterial(ECDiffieHellmanPublicKey) メソッドを呼び出して、キー マテリアルを派生させます。

    byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey)
    
  5. 一時的な Aes オブジェクトを作成します。

    Aes aes = new AesCryptoServiceProvider()
    
  6. 手順 4. で派生されたキー マテリアルで Aes オブジェクトを初期化します。

    aes.Key = aesKey;
    
  7. 一時的な MemoryStream オブジェクトを作成し、暗号化された文字列を保持します。

  8. 一時的な CryptoStream オブジェクトを作成し、それを使用してメッセージを暗号化します。次に、そのメッセージを MemoryStream オブジェクトに書き込みます。

  9. 暗号文および初期化ベクターを保存します。

    iv = aes.IV
    ciphertext = ms.ToArray();
    
  10. 例でバージョン 3、バージョン 4、またはバージョン 5 を実行している場合は、次のように暗号文に署名します。

    • 一時的な ECDsaCng.ECDsaCng(CngKey) オブジェクトを作成します。

      ECDsaCng ecdsa = new ECDsaCng(m_DSKey)
      
    • このオブジェクトの HashAlgorithm プロパティを、Sha512 セキュリティで保護されたハッシュ アルゴリズムとして初期化します。

      ecdsa.HashAlgorithm = CngAlgorithm.Sha512
      
    • 暗号文に署名して、デジタル署名を作成します。

      signature = ecdsa.SignData(ciphertext);
      
  11. 次のように出力メッセージを準備します。

    • メッセージの初期化ベクター、暗号文、および署名の長さを保持する 3 バイトの配列を作成します。

    • 4 つの System.Collections.Generic.List<T> オブジェクトを作成して、前の手順で作成した長さの配列、初期化ベクター、暗号文、および署名を保持します。

    • 4 つの System.Collections.Generic.List<T> オブジェクトを連結し、それを単一の出力メッセージのバイト配列に変換します。

      byte[] message = list1.ToArray();
      
  12. 出力メッセージを送信します。

    ChMgr.SendMessage(message)
    

ReceiveMessage メソッド

public string ReceiveMessage()

このメソッドは、Alice、Bob、および Mallory の Run メソッドから呼び出されます。メッセージを受信して復号化し、そのデジタル署名を検証します。

メッセージは、このメソッドにはパラメーターとして渡されません。代わりに、Communicator クラスの ChannelManager メンバーが、次のコードを使用してメッセージを読み込みます。

byteBuffer = ChMgr.ReadMessage();

ReceiveMessage メソッドは、次の手順を実行します。

  1. メッセージがプレーンテキストで送信されたかどうかを判断します。例のバージョン 1 を実行している場合、メッセージはプレーンテキストなので、復号化の必要はありません。この場合、次のコードを使用して ASCII 文字列に変換されたメッセージが返されます。

    AsciiMessage = Encoding.Unicode.GetString(byteBuffer);
    
  2. メッセージを構成要素に分解します。バージョン 2 ~ 5 では、メッセージが暗号化されます。この場合、メッセージは 3 つの個別のバイト配列に分解されます。最初の配列には初期化ベクターが含まれ、2 番目の配列には暗号文が含まれ、3 番目の配列には暗号文のデジタル署名が含まれます。

  3. fVerbose フラグが設定されている場合は、初期化ベクター、暗号文、および署名を ASCII テキストで表示します。

  4. キー マテリアルを派生させます。次のコードに示すように、Communicator クラスのプライベートな ECDiffieHellmanCng メンバーである m_ECDH_Cng によって、ECDiffieHellmanCng.DeriveKeyMaterial メソッドを使用して共有キー マテリアルを派生させます。

    byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey);
    
  5. AesCryptoServiceProvider オブジェクトをインスタンス化して、Aes オブジェクトを作成します。

    Aes aes = new AesCryptoServiceProvider()
    
  6. 前の手順で派生させたキー マテリアルと初期化ベクターで Aes オブジェクトを初期化します。

  7. System.IO.MemoryStream オブジェクトと System.Security.Cryptography.CryptoStream オブジェクトを使用して、メッセージを復号化します。

  8. 復号化されたメッセージを表示します。

  9. バージョン 3 ~ 5 では、デジタル署名を使用してメッセージの暗号文を検証します。バージョン 3 では、Alice、Bob、および Mallory が同一の署名を使用するため、セキュリティの警告は表示されません。バージョン 4 では、メッセージの暗号文の署名が無効な場合にセキュリティの警告が表示されます。ただし、バージョン 4 は Alice と Bob だけに与えられるため、Mallory が警告を見ることはありません。バージョン 5 では、無効に署名された暗号化キーが検出されると、メッセージの送信と検証が行われる前にプログラムが終了します。

参照

概念

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

Communicator.cs ソース コード (CNG の例)

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

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

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