Skip to content

Eclypses/tutorial-mte-socket-csharp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

C# Socket Tutorial

MTE Implementation Tutorial (MTE Core, MKE, MTE Fixed Length)

Using MTE version 4.x.x

Introduction

Socket Tutorial Server and Client

Introduction

This tutorial is sending messages via a socket connection. This is only a sample, the MTE does NOT require the usage of sockets, most communication protocols can be used..

This tutorial demonstrates how to use MTE Core, MKE, and Fixed Length. For this application, only one type can be used at a time. However, any new or existing application can be adapted to handle multiple types at the same time.

This tutorial contains two main programs, a client and a server, and also for Windows and Linux. Note that any of the available language socket tutorials can be used for any available platform as long as communication is possible between the platforms. It is recommended that a server program is started and wait for a client program to start and establish a connection.

The MTE Encoder and Decoder need several pieces of information to be the same in order to function properly. This includes entropy, nonce, and personalization. If this information must be shared, the entropy MUST be passed securely. One way to do this is with a Diffie-Hellman key exchange. Each side will then be able to create two shared secrets to use as entropy for each pair of Encoder/Decoder. The two personalization values will be created by the client and shared to the other side. The two nonce values will be created by the server and shared with the client.

MTE Core: This is the default functionality of the MTE to use. Unless payloads are large or sequencing is needed this is the recommended style of the MTE and the most secure.

MTE MKE: This add-on of the MTE is recommended when payloads are very large, the MTE Core would, depending on the token byte size, be multiple times larger than the original payload. Because this uses the MTE technology on encryption keys and encrypts the payload, the payload is only enlarged minimally. If the SDK contains "-MKE" in the name then this add-on is included.

MTE Fixed Length: This add-on of the MTE is very secure and is used when the resulting payload is desired to be the same size for every transmission. The Fixed Length add-on is mainly used when using the sequencing verifier with MTE. In order handle dropped, skipped, or asynchronous packets the sequencing verifier requires that all packets be a predictable size. The Fixed Length add-on is a great choice to make that easier. This is ONLY an Encoder change - the Decoder that is used is the MTE Core Decoder. All data smaller than the fixed length size will be padded, and all data larger will be dropped to the fixed length size. When strings are used, any extra padding will be removed. Raw bytes will contain zeros for any padding; any trimming needed should be handled by the application. If the SDK contains "-FLEN" in the name then this add-on is included.

MTE Random: This add-on will help with the generation of cryptographically secure random numbers. This application uses it for the generation of information that will be used for initializing the Encoder/Decoder. Note that for Windows, the bcrypt.dll library may need to be linked in during compilation.

MTE ECDH: This add-on utilizes the Elliptic Curve Diffie-Hellman (ECDH) key agreement protocol. This application uses it to generate public keys that get exchanged and to generate shared secrets to be used as entropy for initiliazing Encoders and Decoders. If the SDK contains "-ECDH" in the name then this add-on is included. Note that this application will need this add-on to function as-is; however, the application could be modified to use another key exchange protocol if needed.

In this tutorial, there is an MTE Encoder on the client that is paired with an MTE Decoder on the server. Likewise, there is an MTE Encoder on the server that is paired with an MTE Decoder on the client. Secured messages wil be sent to and from both sides. If a system only needs to secure messages one way, only one pair could be used.

IMPORTANT

Please note the solution provided in this tutorial does NOT include the MTE library or supporting MTE library files. Please contact Eclypses Inc. if the MTE SDK (which contatins the library and supporting files) has NOT been provided. The solution will only work AFTER the MTE library and other files have been incorporated.

Socket Tutorial Server and Client

MTE Directory and File Setup

  1. Navigate to the "tutorial-mte-socket-csharp" directory.
  2. Create a directory named "MTE". This will contain all needed MTE files.
  3. Copy the "lib" directory and contents from the MTE SDK into the "MTE" directory.
  4. Copy the "src/cs" directory and contents from the MTE SDK into the "MTE" directory.
  5. Copy this "MTE" directory into both the "SocketClient" and "SockerServer" directories.

The common source code between the client and server will be found in the "common" directory. The client and server specific source code will be found in their respective directories.

Project Settings

  1. In the Conditional compilation symbols section under the Build tab (for Debug or Relase), custom symbols can be used to set the project to build for the MTE Core or an add-on configuration. Use one (and olny one) of the following: 'USE_MTE_CORE' to utilize the main MTE Core functions; 'USE_MKE_ADDON' to use the MTE MKE add-on functions; or 'USE_FLEN_ADDON' to use the MTE Fixed length add-on functions. In this application, only one can be used at a time. Each project will need to be set individually.

Source Code Key Points

MTE Setup

  1. In this application, the MTE ECDH add-on is used by each side (client and server) to create public and private keys. The public keys are then shared between the client and server, and then shared secrets are generated with the other's public key to use as matching entropy for the creation of the Encoders and Decoders. The personalization strings and nonces are created using the MTE Random add-on.
    // Create the private and public keys.
    int res = myEcdhManager.CreateKeyPair(myPublicKey);
    if (res < 0) {
      throw new Exception("Unable to create key pair: " + res);
    }

    The C# MTE ECDH class will keep the private key to itself and not provide access to the calling application.

  2. The public keys created by the client will be sent to the server, and vice versa, and will be received as peer public keys. Then the shared secret can be created on each side. These should match as long as the information has been created and shared correctly.
    // Create shared secret.
    byte[] secret = new byte[MteEcdh.SzSecretData];
    
    int res = myEcdhManager.CreateSecret(PeerKey, secret);
    if (res < 0) {
      throw new Exception("Unable to create shared secret: " + MteEcdh.MemoryFail);
    }

    These secrets will then be used to fufill the entropy needed for the Encoders and Decoders.

  3. The client will create the personalization strings, using C#'s basic Guid creation.
    // Create personalization strings.
    _clientEncoderInfo.Personalization = Encoding.ASCII.GetBytes(Guid.NewGuid().ToString());
    _clientDecoderInfo.Personalization = Encoding.ASCII.GetBytes(Guid.NewGuid().ToString());
  4. The two public keys and the two personalization strings will then be sent to the server. The client will wait for an acknowledgment.
    // Send out information to the server.
    // 1 - client Encoder public key (to server Decoder)
    // 2 - client Encoder personalization string (to server Decoder)
    // 3 - client Decoder public key (to server Encoder)
    // 4 - client Decoder personalization string (to server Encoder)
    
    ClientSocketManager.SendMessage('1', _clientEncoderInfo.GetPublicKey());
    ClientSocketManager.SendMessage('2', _clientEncoderInfo.Personalization);
    ClientSocketManager.SendMessage('3', _clientDecoderInfo.GetPublicKey());
    ClientSocketManager.SendMessage('4', _clientDecoderInfo.Personalization);
    
    // Wait for ack from server.
    ClientSocketManager.RecvMsg recvData = ClientSocketManager.ReceiveMessage();
    if (Char.ToLower(recvData.header) != 'a') {
      return false;
    }
    
    recvData.message = null;
  5. The server will wait for the two public keys and the two personalization strings from the client. Once all four pieces of information have been received, it will send an acknowledgment.
    // Processing incoming message all 4 will be needed.
    UInt16 recvCount = 0;
    ServerSocketManager.RecvMsg recvData = new ServerSocketManager.RecvMsg();
    
    // Loop until all 4 data are received from client, can be in any order.
    while (recvCount < 4) {
      // Receive the next message from the client.
      recvData = ServerSocketManager.ReceiveMessage();
    
      // Evaluate the header.
      // 1 - server Decoder public key (from client Encoder)
      // 2 - server Decoder personalization string (from client Encoder)
      // 3 - server Encoder public key (from client Decoder)
      // 4 - server Encoder personalization string (from client Decoder)
      switch (recvData.header) {
        case '1':
          if (_serverDecoderInfo.PeerKey?.Length != 0) {
            recvCount++;
          }
    
          _serverDecoderInfo.PeerKey = recvData.message;
          break;
        case '2':
          if (_serverDecoderInfo.Personalization?.Length != 0) {
            recvCount++;
          }
    
          _serverDecoderInfo.Personalization = recvData.message;
          break;
        case '3':
          if (_serverEncoderInfo.PeerKey?.Length != 0) {
            recvCount++;
          }
    
          _serverEncoderInfo.PeerKey = recvData.message;
          break;
        case '4':
          if (_serverEncoderInfo.Personalization?.Length != 0) {
            recvCount++;
          }
    
          _serverEncoderInfo.Personalization = recvData.message;
          break;
        default:
          // Unknown message, abort here, send an 'E' for error.
          ServerSocketManager.SendMessage('e', Encoding.ASCII.GetBytes("ERR"));
          return false;
      }
    }
    
    // Now all values from client have been received, send an 'a' for acknowledge to client.
    ServerSocketManager.SendMessage('a', Encoding.ASCII.GetBytes("ACK"));
  6. The server will create the private and public keypairs, one for the server Encoder and client Decoder, and one for the server Decoder and client Encoder. The server uses the same file "MTESeuptInfo.cs"
    // Create the private and public keys.
    int res = myEcdhManager.CreateKeyPair(myPublicKey);
    if (res < 0) {
      throw new Exception("Unable to create key pair: " + res);
    }
  7. The server will create the nonces, using the platform supplied secure RNG.
    // Create nonces.
    MteBase baseObj = new MteBase();
    int minNonceBytes = baseObj.GetDrbgsNonceMinBytes(baseObj.GetDrbg());
    if (minNonceBytes <= 0) {
      minNonceBytes = 1;
    }
    
    byte[] serverEncoderNonce = MteRandom.GetBytes((uint)minNonceBytes);
    if (serverEncoderNonce.Length == 0) {
      return false;
    }
    
    _serverEncoderInfo.Nonce = serverEncoderNonce;
    
    byte[] serverDecoderNonce = MteRandom.GetBytes((uint)minNonceBytes);
    if (serverDecoderNonce.Length == 0) {
      return false;
    }
    
    _serverDecoderInfo.Nonce = serverDecoderNonce;
  8. The two public keys and the two nonces will then be sent to the client. The server will wait for an acknowledgment. ```csharp // Send out information to the client. // 1 - server Encoder public key (to client Decoder) // 2 - server Encoder nonce (to client Decoder) // 3 - server Decoder public key (to client Encoder) // 4 - server Decoder nonce (to client Encoder) ServerSocketManager.SendMessage('1', _serverEncoderInfo.GetPublicKey());

    if (_serverEncoderInfo.Nonce != null) { ServerSocketManager.SendMessage('2', _serverEncoderInfo.Nonce); }

    ServerSocketManager.SendMessage('3', _serverDecoderInfo.GetPublicKey());

    if (_serverDecoderInfo.Nonce != null) { ServerSocketManager.SendMessage('4', _serverDecoderInfo.Nonce); }

    // Wait for ack from client. recvData = ServerSocketManager.ReceiveMessage();

    if (Char.ToLower(recvData.header) != 'a') { return false; }

    </li>
    
    <li>
    The client will now wait for information from the server. This includes the two server public keys, and the two nonces. Once all pieces of information have been obtained, the client will send an acknowledgment back to the server.
    
    ```csharp
    // Processing incoming message all 4 will be needed.
    UInt16 recvCount = 0;
    
    while (recvCount < 4) {
      // Receive the next message from the server.
      recvData = ClientSocketManager.ReceiveMessage();
    
      // Evaluate the header.
      // 1 - client Decoder public key (from server Encoder)
      // 2 - client Decoder nonce (from server Encoder)
      // 3 - client Encoder public key (from server Decoder)
      // 4 - client Encoder nonce (from server Decoder)
      switch (recvData.header) {
        case '1':
          if (_clientDecoderInfo.PeerKey?.Length != 0) {
            recvCount++;
          }
    
          _clientDecoderInfo.PeerKey = recvData.message;
          break;
        case '2':
          if (_clientDecoderInfo.Nonce?.Length != 0) {
            recvCount++;
          }
    
          _clientDecoderInfo.Nonce = recvData.message;
          break;
        case '3':
          if (_clientEncoderInfo.PeerKey?.Length != 0) {
            recvCount++;
          }
    
          _clientEncoderInfo.PeerKey = recvData.message;
          break;
        case '4':
          if (_clientEncoderInfo.Nonce?.Length != 0) {
            recvCount++;
          }
    
          _clientEncoderInfo.Nonce = recvData.message;
          break;
        default:
          // Unknown message, abort here, send an 'E' for error.
          ClientSocketManager.SendMessage('e', Encoding.ASCII.GetBytes("ERR"));
          return false;
      }
    }
    
    // Now all values from server have been received, send an 'A' for acknowledge to server.
    ClientSocketManager.SendMessage('a', Encoding.ASCII.GetBytes("ACK"));
    
  9. After the client and server have exchanged their information, the client and server can each create their respective Encoder and Decoder. This is where the personalization string and nonce will be added. Additionally, the entropy will be set by getting the shared secret from ECDH. This sample code showcases the client Encoder. There will be four of each of these that will be very similar. Ensure carefully that each function uses the appropriate client/server, and Encoder/Decoder variables and functions.
          // Display all info related to the client Encoder.
          Console.WriteLine("Client Encoder public key:");
          Console.WriteLine(BitConverter.ToString(_clientEncoderInfo.GetPublicKey()).Replace("-", ""));
          Console.WriteLine("Client Encoder peer's key:");
          Console.WriteLine(BitConverter.ToString(_clientEncoderInfo.PeerKey).Replace("-", ""));
          Console.WriteLine("Client Encoder nonce:");
          Console.WriteLine(BitConverter.ToString(_clientEncoderInfo.Nonce).Replace("-", ""));
          Console.WriteLine("Client Encoder personalization:");
          Console.WriteLine(Encoding.ASCII.GetString(_clientEncoderInfo.Personalization));
    
          try {
            // Create Encoder object.
    #if USE_MTE_CORE
            _encoder = new MteEnc();
    #endif
    #if USE_MKE_ADDON
            _encoder = new MteMkeEnc();
    #endif
    #if USE_FLEN_ADDON
            _encoder = new MteFlenEnc(Globals.MAX_INPUT_BYTES);
    #endif
    
            // Create shared secret.
            byte[] secret = _clientEncoderInfo.GetSharedSecret();
    
            // Set Encoder entropy using this shared secret.
            _encoder.SetEntropy(secret);
    
            // Set Encoder nonce.
            _encoder.SetNonce(_clientEncoderInfo.Nonce);
    
            // Instantiate Encoder.
            MteStatus status = _encoder.Instantiate(_clientEncoderInfo.Personalization);
            if (status != MteStatus.mte_status_success) {
              Console.Error.WriteLine("Encoder instantiate error {0}: {1}", _encoder.GetStatusName(status),
                _encoder.GetStatusDescription(status));
            }
    
            // Delete server Encoder info.
            _clientEncoderInfo = null;
          } catch (Exception ex) {
            Console.WriteLine(ex);
            throw;
          }

Diagnostic Test

  1. The application will run a diagnostic test, where the client will encode the word "ping", then send the encoded message to the server. The server will decode the received message to confirm that the original message is "ping". Then the server will encode the word "ack" and send the encoded message to the client. The client then decodes the received message, and confirms that it decodes it to the word "ack".

User Interaction

  1. The application will continously prompt the user for an input (until the user types "quit"). That input will be encoded with the client Encoder and sent to the server.
    public static bool EncodeMessage(byte[]? message, out byte[] encoded) {
    
      encoded = new byte[] { };
    
      // Display original message.
      if (message != null) {
        Console.WriteLine("\nMessage to be encoded: {0}", Encoding.ASCII.GetString(message));
        MteStatus status = MteStatus.mte_status_success;
        // Encode the message.
        encoded = _encoder?.Encode(message, out status);
        if (status != MteStatus.mte_status_success) {
          Console.Error.WriteLine("Error encoding (" + _encoder?.GetStatusName(status) + "): " +
                                  _encoder?.GetStatusDescription(status));
          return false;
        }
      }
    
      // Display encoded message.
      if (encoded != null) {
        Console.WriteLine("Encoded message being sent\n: {0}", BitConverter.ToString(encoded).Replace("-", ""));
      }
    
      return true;
    }
  2. The server will use its Decoder to decode the message.
    public static bool DecodeMessage(byte[] encoded, out byte[] decoded) {
      // Display encoded message.
      Console.WriteLine("Encoded message received\n: {0}",
        BitConverter.ToString(encoded).Replace("-", ""));
    
      // Decode the encoded message.
      MteStatus status = MteStatus.mte_status_success;
      decoded = _decoder?.Decode(encoded, out status);
    
      // Ensure that there were no decoding errors.
      if (_decoder != null && _decoder.StatusIsError(status)) {
        Console.Error.WriteLine("Error decoding (" + _decoder.GetStatusName(status) + "): " +
                                _decoder.GetStatusDescription(status));
    
        return false;
      }
    
      // Display decoded message.
      if (decoded != null) {
        Console.WriteLine("Decoded message: {0}\n", Encoding.ASCII.GetString(decoded));
      }
    
      return true;
    }
  3. Then that message will be re-encoded with the server Encoder and sent to the client.The client Decoder will then decode that message, which then will be compared with the original user input.

MTE Finialize

  1. Once the user has stopped the user input, the program should securely clear out MTE Encoder and Decoder information.
    // Uninstantiate Encoder and Decoder.
    _encoder?.Uninstantiate();
    _decoder?.Uninstantiate();

Contact Eclypses

Email: [email protected]

Web: www.eclypses.com

Chat with us: Developer Portal

All trademarks of Eclypses Inc. may not be used without Eclypses Inc.'s prior written consent. No license for any use thereof has been granted without express written consent. Any unauthorized use thereof may violate copyright laws, trademark laws, privacy and publicity laws and communications regulations and statutes. The names, images and likeness of the Eclypses logo, along with all representations thereof, are valuable intellectual property assets of Eclypses, Inc. Accordingly, no party or parties, without the prior written consent of Eclypses, Inc., (which may be withheld in Eclypses' sole discretion), use or permit the use of any of the Eclypses trademarked names or logos of Eclypses, Inc. for any purpose other than as part of the address for the Premises, or use or permit the use of, for any purpose whatsoever, any image or rendering of, or any design based on, the exterior appearance or profile of the Eclypses trademarks and or logo(s).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published