Share via


Source Code Overview (CNG Example)

This overview provides a high-level description of the interactions between the various code elements in the Cryptography Next Generation (CNG) secure communication example.

It discusses the following aspects of the example:

  • Applications

  • Files

  • Classes

  • Security versions

  • Session overview

  • Cryptographic keys (versions 2-5)

  • Digital signatures exchanged over public channel (version 3)

  • Digital signatures exchanged over private channel (version 4)

  • Session termination (version 5)

  • Additional notes

  • Limitations of the CNG example

Applications

The example consists of three separate console applications, Alice, Bob, and Mallory. Each application is built as a separate Visual Studio project and consists of a main file and three shared files. The following table shows the applications and their files.

Application (project) name

Files

Alice

  • Alice.cs (main file)

  • Utilities.cs

  • ChannelManager.cs

  • Communicator.cs

Bob

  • Bob.cs (main file)

  • Utilities.cs

  • ChannelManager.cs

  • Communicator.cs

Mallory

  • Mallory.cs (main file)

  • Utilities.cs

  • ChannelManager.cs

  • Communicator.cs

Files

The tables in the following sections summarize the classes and methods that are used by each application, in the order in which they appear in the source code.

Alice.cs, Bob.cs, and Mallory.cs

Class, method, or

global variable name

Use

CNG_SecureCommunicationExample

Projectwide partial class.

MyColor

OtherColor

fDisplaySendMessage

Global variables.

Main

Program entry point for each application. This method handles the following:

  • When called by Alice, automatically loads Bob.exe and Mallory.exe.

  • Creates a processing loop.

  • Calls the InitConsole method to set console size, position, and title.

  • Calls the Run method.

Run

Method that calls the InitializeOptions method and creates the selected security scenario.

Utilities.cs

Class, method, or

global variable name

Use

CNG_SecureCommunicationExample

Project-wide partial class.

Version

fVerbose

fMallory

Global variables.

Autoloader

Method that Alice calls to load the Bob.exe and Mallory.exe applications.

InitConsole

Method that handles the user interface menu and application-level messages.

SplashScreen

Method that provides console window titles.

ReadALine

Utility method that reads a user-entered line from the console.

ReadAChar

Utility method that displays a question and prompts the user for a yes or no answer.

InitializeOptions

Method that displays options and prompts the user for a selection. This method also sets the Version, fVerbose, and fMallory global flags.

Display(string s)

First of two Display methods. This method passes the string and the MyColor variable to the second Display method.

Display(string DisplayString, int color)

Second of two Display methods. This method wraps Console.WriteLine statements and provides color support for output lines.

For more information about these classes, methods, and variables, see Code Analysis of the Utility Classes (CNG Example).

ChannelManager.cs

Class, method, or

global variable name

Use

CNG_SecureCommunicationExample

Project-wide partial class.

AppControl

Method that provides internal application control and synchronizes the three console applications.

Alice uses this method to send the program options (Version and fVerbose flags) to Bob and Mallory.

AppControl is not a messaging method. Its content is not encrypted or signed. It does not call the Communicator class.

SendChannelName

ReceiveChannelName

Methods that are used to switch from the PublicChannel named pipe to the AliceAndBobChannel and AliceAndBobChannel1 named pipes. These methods allow the deliberate security breach that is discussed in the CNG example overview.

ChannelManager

Class that provides the interprocess communication framework for the application.

For more information about these classes and methods, see Code Analysis of the ChannelManager Class (CNG Example).

Communicator.cs

Class, method, or

global variable name

Use

CNG_SecureCommunicationExample

Project-wide partial class.

Communicator

Class that encapsulates all cryptographic functions. This class processes all messages between Alice, Bob, and Mallory. It does not process messages sent by the ChannelManager AppControl method.

m_DSKey

m_ECDH_Cng

m_ECDH_local_publicKey_XML

m_ECDH_remote_publicKey

ChMgr

Class variables.

Communicator

Method that constructs a Communicator object.

Dispose

Method that releases privately held resources.

StoreDSKey

Method that stores a digital signature key.

Send_or_Receive_PublicCryptoKey

Method that provides key exchange support.

iv

ciphertext

signature

Private class variables used for encrypting plaintext messages. These variables are declared near the ReceiveMessage() method.

ReceiveMessage

Method that receives plaintext or encrypted messages, depending on the security version.

SendMessage

Method that accepts a plaintext message and sends it out in either plaintext or encrypted format, depending on the security version.

For more information about these classes, methods, and variables, see Code Analysis of the Communicator Class (CNG Example).

Classes

Each project contains three classes:

  • public partial class CNG_SecureCommunicationExample

    This class extends across all four project files included in the Alice, Bob, and Mallory applications. After compilation, the CNG_SecureCommunicationExample class contains all the classes, variables, and methods for the four project files. For more information about partial classes, see Partial Classes and Methods (C# Programming Guide).

  • internal sealed class ChannelManager

    This class provides named pipe support. Each project creates several ChannelManager instances at different times during the program's execution. Details of this class can be found in Code Analysis of the ChannelManager Class (CNG Example).

  • internal sealed class Communicator

    This class provides encryption and decryption support. Each project creates several Communicator instances at different times during the program's execution. Details of this class can be found in Code Analysis of the Communicator Class (CNG Example).

Security Versions

The source code supports the security scenario presented in the CNG example overview. It implements the following five versions, representing five security levels, of the instant messaging (IM) tool:

  • Version 1: Uses plaintext messages and named pipes.

  • Version 2: Uses encrypted messages.

  • Version 3: Uses encrypted messages and digital signatures.

  • Version 4: Uses encrypted messages and a private digital signature.

  • Version 5: Terminates the application when security errors are encountered.

Note

The remainder of this topic refers to these versions by number. Also, depending on the context, the names "Alice", "Bob", and "Mallory" may refer to the three people involved in the example scenario or to the three Visual Studio applications.

Session Overview

Alice, Bob, and Mallory each have a Main method and a Run method.

The Main method synchronizes the applications and performs the following functions:

  • Displays a startup splash screen.

  • Asks the user to choose session options (Alice only).

  • Sends the session options to Bob and Mallory (Alice only).

  • Receives the session options from Alice (Bob and Mallory only).

  • Calls the Run method to perform the requested security session.

The Run method executes security scenarios.

  • Each session illustrates one of the versions listed in the previous section.

  • A session starts when Alice, Bob, and Mallory enter their Run methods and ends when they return to their Main methods.

  • Alice, Bob, and Mallory always run the same version during a session.

  • Alice initiates all the transactions that take place during a session. Mallory responds to Alice and initiates the transactions with Bob. Bob just responds.

The source code for Alice and Bob is very similar. The primary difference is that Alice initiates each session and acts as a pipe server, and Bob acts as a pipe client. Mallory's code is more complex because he manages two separate pipes: one with Alice and one with Bob.

Main Method

Alice calls the InitializeOptions method at the beginning of her Main method and receives session options (Version, fVerbose, fMallory) from the user. She uses her AppControl method to send the options to Bob and Mallory, who receive them by using their AppControl methods. If the user decides to close the application by typing the letter "x", Alice's AppControl method sends the string "exit" instead of the session options to Bob and Mallory.

After the three applications have received the session options, they call their Run methods.

Run Method

Alice, Bob, and Mallory execute the requested session by performing the following steps:

  1. Alice calls the SendChannelName method, which uses a channel named PublicChannel. She sends Bob a new channel name (AliceAndBobChannel).

  2. If the fMallory flag is set to true, Mallory listens on PublicChannel and intercepts the new channel name (AliceAndBobChannel) from Alice. He then sends Bob a different channel name (AliceAndBobChannel1).

  3. Alice and Bob create Communicator objects named after themselves. These objects are created within C# using statements, and are disposed of at the end of the Run method.

    Alice is initialized as a pipe server:

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

    Bob is initialized as a pipe client:

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

    Mallory creates two Communicator objects, MalloryAlice and MalloryBob. Mallory is initialized as a pipe client with Alice:

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

    Mallory is initialized as a pipe server with Bob:

    using (Communicator MalloryBob = new Communicator("server", BobChannelName"))
    
  4. The Communicator class constructor accepts the channel name and creates a long-term public ChannelManager object called ChMgr:

    ChMgr = new ChannelManager(mode, ChannelName);
    
  5. The ChannelManager constructor accepts the channel name and creates a corresponding named pipe.

    Note

    At this point, Alice and Mallory are communicating over a pipe named AliceAndBobChannel, and Mallory and Bob are communicating over a pipe named AliceAndBobChannel1.

    AliceAndBobChannel and AliceAndBobChannel1 are long-term channels that stay open until the end of the security scenario (that is, the end of the Run method).

  6. The values of the fVersion flag (which controls the security version) and the fMallory flag (which controls Mallory's involvement) determine what happens next:

    In version 3, Alice sends a digital signature key to Bob over PublicChannel. They use this digital signature key to sign keys and messages. If fMallory is true, Mallory intercepts the digital signature key and uses it to sign the keys and messages that he sends to Alice and Bob.

    In versions 4 and 5, Alice sends two digital signature keys to Bob. Digital signature key 1 is the same key that Alice sent in version 3. Digital signature key 2 is a secret digital signature key that Mallory does not know about.

  7. Alice and Bob exchange public cryptographic keys for versions 2 through 5. If fMallory is true, Mallory intercepts their public keys and substitutes his own.

  8. Alice and Bob exchange messages. If fMallory is true, Mallory intercepts, changes, and resends Alice's and Bob's messages.

  9. After Alice and Bob finish talking to each other, you are prompted to send your own messages. This enables you to see how your messages get encrypted and what Mallory does to change them. When you are finished, press ENTER to transfer control back to Alice.

  10. Alice ends the session. Alice, Bob, and Mallory's Run methods return control to their Main methods, and the example restarts.

Cryptographic Keys (Versions 2-5)

Versions 2 through 5 encrypt messages by using the Advanced Encryption Standard (AES) algorithm. The cryptographic key exchange is implemented in Alice, Bob, and Mallory's Run methods after the following code statement:

if (2 <= Version)

The cryptographic key is sent by the long-term public ChannelManager object (ChMgr) that is created by the Communicator class constructor.

The following two code statements show how Alice sends and Bob receives the cryptographic key:

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

The second parameter defines the color that the receiving application should use when it displays the contents of the cryptographic key.

AES implementations are considered mathematically infeasible to break. However, AES offers no protection against a man-in-the-middle attack. It may seem contradictory that Mallory can decrypt Alice and Bob's messages when AES provides such strong encryption. This is possible because Mallory has Alice's and Bob's shared secret agreements. Mallory's key interception and substitution make the strong AES encryption useless.

Using cryptographic keys without authentication provides a false sense of security. Alice and Bob think they have a secure message transmission scheme with version 2. In fact, security is compromised before they send their very first message.

Alice and Bob's company does not know whether the attacks are coming from inside or outside the company. They design version 3 of the IM tool to discover the source of the attacks.

Digital Signatures Exchanged over Public Channel (Version 3)

Version 3 tries to fix the security flaw in version 2 by using a digital signature to sign keys and messages. The digital signature key exchange is implemented in Alice, Bob, and Mallory's Run methods after the following code statement:

if (3 <= Version)

The digital signature key is sent through the same long-term public channel as the cryptographic keys. The following code is responsible for sending the digital signature key:

Alice.ChMgr.SendMessage(dsKeyBlob);

Note

The ChannelManager instance (ChMgr) that sends the digital signature key is a member of the Alice Communicator object.

Alice and Bob store the digital signature key as a private member of their Communicator objects:

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

Unfortunately, Mallory easily copies the digital signature from PublicChannel and saves it:

Mallory.StoreDSKey(DSKey);

When Alice and Bob receive signed messages from each other, the digital signatures match the messages perfectly. This is because Mallory signed them with the same digital signature key that Alice and Bob use.

In version 3, both the cryptographic keys and the digital signature are exchanged on a public channel over the corporate network. The company that Alice and Bob work for suspect that someone inside the company is performing the thefts. The company creates version 4 to test this idea.

Digital Signatures Exchanged over Private Channel (Version 4)

Version 4 uses two digital signature keys: the key that was used in version 3 and a second, secret key that is sent through a private channel. The first key is now treated as a fake digital key, to trap the thief. The second key is used by Alice and Bob to digitally sign their cryptographic keys and their messages.

Only Alice and Bob are given version 4 of the IM software. Mallory continues to use version 3. Therefore, Mallory never discovers that the digital signature he uses is invalid. However, Alice and Bob's IM tool displays a security warning for every single key and message they receive.

Version 4 also demonstrates that both cryptographic keys and messages are being intercepted. This indicates that a man-in-the-middle attack is occurring, and that it starts before the cryptographic keys are even sent. Therefore, a company employee who has access to the corporate PublicChannel must be logging on before Bob. The clever use of the secret digital signature key reveals Mallory's secret activities.

The secret digital signature key transmission is implemented in Alice and Bob's Run methods after the following code statement:

if (4 <= Version)

The following code statements are responsible for creating Alice and Bob's private ChannelManager instances:

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

The private channel that Alice and Bob use (ChMgr2) is not a member of their Communicator objects. You can see this by comparing the following two code statements:

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

The first statement uses the long-term ChannelManager instance (ChMgr) that is created at the start of the Run method. This instance is held as a public member of Alice, Bob, and Mallory's Communicator objects (see step 3 in the Session Overview section) until the end of the session. The second statement uses a temporary object that exists only long enough to send and receive the key. It is disposed immediately after use.

After Alice sends the secret digital signature key, Bob receives it by using the following statement:

DSKey = ChMgr2.ReadMessage();

Alice and Bob store the key as a private member in their Communicator objects:

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

These statements also overwrite the fake digital signature key.

In version 4, Alice and Bob use the secret digital signature key instead of the fake digital signature key to sign keys and messages. Version 4 also signs the cryptographic keys and displays security warnings whenever a message's digital signature does not match the message.

Session Termination (Version 5)

Version 5 is identical to version 4, except that it ends the session at the first error. Alice experiences the first error when she receives Bob's public cryptographic key and discovers an invalid digital signature. Bob experiences his first error when he receives Alice's public cryptographic key and also discovers an invalid digital signature.

Additional Notes

  • Object disposal: C# using statements provide increased security. They are used to enclose all ChannelManager and Communicator objects. When these objects go out of scope, their Dispose methods are called immediately, and all internally held resources are released.

  • Encoding methods: Whenever encrypted data is transmitted, you should encode it as UTF8 or Unicode, never as ASCII.

Limitations of the CNG Example

The purpose of the CNG secure communications example is to demonstrate the managed CNG functions. As a result, certain functionality has been omitted, including the following:

  • Parameter validation on all methods.

  • Extensive use of try/catch blocks.

  • Robust pipe disconnection discovery.

  • Logging screen output to a file.

  • Dynamic configurability of the encryption algorithm.

  • Dynamic configurability of the digital signature algorithm.

  • A different way to transmit the digital signal key to Bob. The named pipe PrivateChannel is a simple solution; other, more sophisticated methods exist.

  • Key persistence, storage, and retrieval.

  • Use of digital signature keys generated by the operating system.

  • Use of keys supplied by a public key infrastructure (PKI).

These features involve additional code complexity, and are beyond the scope of this example.

See Also

Concepts

Cryptography Next Generation (CNG) Secure Communication Example

Step-by-Step Key and Message Exchange (CNG Example)

Expected Output (CNG Example)