MTE Multiple Client Samples
Purpose
Samples expand on our "Examples" by providing longer snippets of code demonstrating the entire processes. The objective of an MTE Multiple Client "Samples" is to provide full samples of code of how to use the MTE with multiple clients.
The MTE requires each endpoint to be paired individually. For an endpoint to manage multiple MTE endpoints each endpoint must be tracked and be identifiable. When there are multiple MTE clients an easy way to manage all the clients is to save and restore the MTE state of each endpoint. This sample shows how to save and restore the MTE state in order to manage multiple MTE clients.
The sample below uses a console application that will prompt the user for the number of clients to create. Then it will do the following for each client.
- Handshake with server to pair MTE
- Create MTE Encoder
- Encrypt and save MTE encoder state
- Create MTE Decoder
- Encrypt and save MTE decoder state
- Sends a random number of messages, performing the following steps:
- Decrypts MTE encoder state
- Restores MTE encoder for client
- Encodes outgoing message with MTE
- Encrypts and saves updated MTE encoder state
- Decrypts MTE decoder state
- Restores MTE decoder for client
- Decodes incoming message using MTE
- Encrypts and saves updated MTE decoder state
- User is then prompted to either send additional messages or end.
The code samples for each section show the client side using a console application, the operations on the server side are almost identical. Each section breaks out portions of the code, at the bottom of this page the full program files are also available for the client as well as the server.
Initial Pairing Handshake
Our example pairs the MTE client using an initial handshake that uses the Diffie-Hellman key exchange to determine the entropy, the conversationID for the personalization string and the server creates and sets the nonce and sends it back to the client.
- CSharp
- Java
- Python
- Go
/// <summary>
/// Handshakes the with server.
/// </summary>
/// <param name="clientId">The client identifier.</param>
/// <param name="clients">The client dictionary</param>
/// <param name="currentConversation">The current conversation GUID.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private static bool HandshakeWithServer(int clientId,
Dictionary<int, string> clients,
string currentConversation = null)
{
try
{
Console.WriteLine($"Performing Handshake for Client {clientId}");
//--------------------------------
// create clientId for this client
//--------------------------------
HandshakeModel handshake = new HandshakeModel {
ConversationIdentifier = Guid.NewGuid().ToString() };
//-------------------------------------------------------------
// If current conversation guid is passed in, update identifier
//-------------------------------------------------------------
if (!string.IsNullOrWhiteSpace(currentConversation))
{
handshake.ConversationIdentifier = currentConversation;
}
//-------------------------------------------------------------
// Add client to dictionary list if this is a new conversation
//-------------------------------------------------------------
if (!clients.ContainsKey(clientId))
{
clients.Add(clientId, handshake.ConversationIdentifier);
}
//-------------------------------------------
// Create eclypses DH containers for handshake
//-------------------------------------------
EclypsesECDH encoderEcdh = new EclypsesECDH();
EclypsesECDH decoderEcdh = new EclypsesECDH();
//-------------------------------------------
// Get the public key to send to other side
//-------------------------------------------
handshake.ClientEncoderPublicKey =
encoderEcdh.GetPublicKey(encoderEcdh.GetTheContainer());
handshake.ClientDecoderPublicKey =
decoderEcdh.GetPublicKey(decoderEcdh.GetTheContainer());
//-------------------
// Perform handshake
//-------------------
string handshakeResponse =
MakeHttpCall($"{_restAPIName}/api/handshake",
HttpMethod.Post, handshake.ConversationIdentifier,
_jsonContentType,
JsonSerializer.Serialize(handshake, _jsonOptions)).Result;
//---------------------------------------
// Deserialize the result from handshake
//---------------------------------------
ResponseModel<HandshakeModel> response =
JsonSerializer.Deserialize<ResponseModel<HandshakeModel>>(handshakeResponse, _jsonOptions);
//---------------------------------------
// If handshake was not successful break
//---------------------------------------
if (!response.Success)
{
Console.WriteLine($"Error making DH handshake for Client " +
"{clientId}: {response.Message}");
return false;
}
//----------------------
// Create shared secret
//----------------------
var encoderSharedSecretModel =
encoderEcdh.ProcessPartnerPublicKey(response.Data.ClientEncoderPublicKey);
var decoderSharedSecretModel =
decoderEcdh.ProcessPartnerPublicKey(response.Data.ClientDecoderPublicKey);
//----------------------------------------------------------
// Create and store MTE Encoder and Decoder for this Client
//----------------------------------------------------------
ResponseModel mteResponse = CreateMteStates(response.Data.ConversationIdentifier,
encoderSharedSecretModel.SharedSecret,
decoderSharedSecretModel.SharedSecret,
Convert.ToUInt64(response.Data.Timestamp));
//----------------------------------------------------------
// Clear container to ensure key is different for each client
//----------------------------------------------------------
encoderEcdh.ClearContainer();
decoderEcdh.ClearContainer();
//-----------------------------------------
// If there was an error break out of loop
//-----------------------------------------
if (!mteResponse.Success)
{
Console.WriteLine($"Error creating mte states for Client {clientId}: {response.Message}");
return false;
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
/**
* Handshake with the server and create MTE states
* @param clientId --> Current client id
* @param clients --> Client hash map
* @param currentConversation --> current conversation ID
* @return
*/
private static boolean HandshakeWithServer(int clientId,
HashMap<Integer, String> clients,
String currentConversation)
{
try
{
System.out.println("Performing Handshake for Client " + clientId);
//--------------------------------
// create clientId for this client
//--------------------------------
HandshakeModel handshake = new HandshakeModel();
handshake.ConversationIdentifier = UUID.randomUUID().toString();
//----------------------------------------------------------
// If current conversation id passed in update identifier
//----------------------------------------------------------
if (currentConversation != null && !currentConversation.isEmpty())
{
handshake.ConversationIdentifier = currentConversation;
}
//-------------------------------------------------------------
// Add client to dictionary list if this is a new conversation
//-------------------------------------------------------------
if(!clients.containsKey(clientId)) {
clients.put(clientId, handshake.ConversationIdentifier);
}
//-------------------------------------------
// Create eclypses DH containers for handshake
//-------------------------------------------
EclypsesECDH encoderEcdh = new EclypsesECDH();
EclypsesECDH decoderEcdh = new EclypsesECDH();
//-------------------------------------------
// Get the public key to send to other side
//-------------------------------------------
handshake.ClientEncoderPublicKey = encoderEcdh.getDevicePublicKey();
handshake.ClientDecoderPublicKey = decoderEcdh.getDevicePublicKey();
//-------------------
// Perform handshake
//-------------------
String handshakeString = _gson.toJson(handshake);
String handshakeResponse = MakeHttpCall(_restAPIName + "/api/handshake",
"POST",
handshake.ConversationIdentifier,
_jsonContentType,
handshakeString);
//---------------------------------------
// Deserialize the result from handshake
//---------------------------------------
Type handshakeResponseType = new TypeToken<ResponseModel<HandshakeModel>>() {}.getType();
ResponseModel<HandshakeModel> response =
_gson.fromJson(handshakeResponse, handshakeResponseType);
//---------------------------------------
// If handshake was not successful end
//---------------------------------------
if (!response.Success)
{
System.out.println("Error making DH handshake for Client " + clientId+ ": " +response.Message);
return false;
}
//----------------------
// Create shared secret
//----------------------
var encoderSharedSecret = encoderEcdh.createSharedSecret(response.Data.ClientEncoderPublicKey);
var decoderSharedSecret = decoderEcdh.createSharedSecret(response.Data.ClientDecoderPublicKey);
//----------------------------------------------------------
// Create and store MTE Encoder and Decoder for this Client
//----------------------------------------------------------
ResponseModel mteResponse = CreateMteStates(response.Data.ConversationIdentifier,
encoderSharedSecret,
decoderSharedSecret,
Long.parseLong(response.Data.Timestamp));
//----------------------------------------------------------
// Clear container to ensure key is different for each client
//----------------------------------------------------------
encoderEcdh = null;
decoderEcdh = null;
//-----------------------------------------
// If there was an error break out of loop
//-----------------------------------------
if (!mteResponse.Success)
{
System.out.println("Error creating mte states for Client " + clientId + ": " + response.Message);
return false;
}
return true;
}catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
}
def handshake_with_server(client_id: int, current_conversation: str = NULL) -> bool:
"""
Handshakes with the server.
"""
print ("Performing Handshake for Client {0}".format(client_id))
# Create client_id for this client.
handshake = HandshakeModel()
# If current converation guid passed in, then upate identifier.
if len(current_conversation) > 0:
handshake.conversation_identifier = current_conversation
else:
handshake.conversation_identifier = str(uuid.uuid4())
# Add client to dictionary list if this is a new conversation.
if client_id not in _clients:
_clients[client_id] = handshake.conversation_identifier
# Create Eclypses DH containers for handshake.
encoder_ecdh = EclypsesECDH()
decoder_ecdh = EclypsesECDH()
# Get the public key to send to the other side.
handshake.client_encoder_public_key = encoder_ecdh.get_device_public_key()
handshake.client_decoder_public_key = decoder_ecdh.get_device_public_key()
# Perform handshake.
url = Constants().REST_API_NAME + "/api/handshake"
payload = {
"Timestamp": "null",
"ConversationIdentifier": handshake.conversation_identifier,
"ClientEncoderPublicKey": handshake.client_encoder_public_key.decode(),
"ClientDecoderPublicKey": handshake.client_decoder_public_key.decode()
}
headers = {
"Content-Type": JSON_CONTENT_TYPE,
"accept": "*/*",
Constants().CLIENT_ID_HEADER: handshake.conversation_identifier
}
handshake_response = requests.post(
url=url, data=json.dumps(payload), headers=headers)
# Deserialize the result from handshake.
response = handshake_response.json()
# If handshake was not successful, then break.
if response['Success'] == False:
print ("Error making DH handshake for Client {0}: {1}".format(client_id, response['Message']))
return False
# Create shared secret.
encoder_shared_secret_model = encoder_ecdh.create_shared_secret(
bytes(response['Data']['ClientEncoderPublicKey'], 'utf-8'))
decoder_shared_secret_model = decoder_ecdh.create_shared_secret(
bytes(response['Data']['ClientDecoderPublicKey'], 'utf-8'))
# Create and store MTE Encoder and Decoder for this Client.
mte_response = create_mte_states(personal=response['Data']['ConversationIdentifier'],
encoder_entropy=encoder_shared_secret_model, decoder_entropy=decoder_shared_secret_model,
nonce=int(response['Data']['Timestamp']))
# Clear container to ensure key is different for each client.
encoder_ecdh = NULL
decoder_ecdh = NULL
# If there was an error, break out of loop.
if mte_response.success == False:
print ("Error creating MTE states for Client {0}: {1}".format(client_id, response['Message']))
return False
return True
/**
* Performs Handshake with Server
* Creates the ECDH public keys and sends them to server
* When receives it back generates the shared secret
* then creates the Encoder and Decoder and saves the states
*
* clientId: clientId string
*
* Returns HandshakeResponse: encoderSharedSecret, decoderSharedSecret
*
*/
func PerformHandshakeWithServer(num int, clientId string) (out int, err error) {
fmt.Println("Performing handshake for client: "
+ strconv.FormatInt(int64(num), 10) + " ID: " + clientId)
//--------------------------------------------
// Set default return and response parameters
var handshakeModel HandshakeModel
handshakeModel.ConversationIdentifier = clientId
//----------------------------------------------
// Create eclypses ECDH for Encoder and Decoder
encoderEcdh := eclypsesEcdh.New()
decoderEcdh := eclypsesEcdh.New()
//----------------------------
// Get the Encoder public key
clientEncoderPKBytes, err := encoderEcdh.GetPublicKey()
if err != nil {
fmt.Println("Error creating Encoder public key: "
+ err.Error() + " Code: " + strconv.Itoa(errorCreatingPK))
return errorCreatingPK, err
}
//----------------------------
// Get the Decoder public key
clientDecoderPKBytes, err := decoderEcdh.GetPublicKey()
if err != nil {
fmt.Println("Error creating Decoder public key: "
+ err.Error() + " Code: " + strconv.Itoa(errorCreatingPK))
return errorCreatingPK, err
}
//-----------------------------------------
// Base64 encode keys so we can send them
handshakeModel.ClientEncoderPublicKey =
base64.StdEncoding.EncodeToString(clientEncoderPKBytes)
handshakeModel.ClientDecoderPublicKey =
base64.StdEncoding.EncodeToString(clientDecoderPKBytes)
//----------------------------------
// Json encode our handshake model
handshakeString, err := json.Marshal(handshakeModel)
if err != nil {
fmt.Println("Error marshalling handshakeModel: "
+ err.Error() + " Code: " + strconv.Itoa(errorMarshalJson))
return errorMarshalJson, err
}
//----------------------------------
// Make Http and get return string
hsModelString, errorcode, err := MakeHttpCall(restAPIName+handshakeRoute,
"POST",
clientId,
jsonContent,
string(handshakeString))
if err != nil {
fmt.Println("Error making Http call: "
+ err.Error() + " Code: " + strconv.Itoa(errorcode))
return errorcode, err
}
//-----------------------------
// Marshal json back to class
hrBytes := []byte(hsModelString)
var serverResponse ResponseModel[HandshakeModel]
json.Unmarshal(hrBytes, &serverResponse)
if !serverResponse.Success {
fmt.Println("Error back from server: "
+ serverResponse.Message + " Code: " + strconv.Itoa(errorFromServer))
return errorFromServer, errors.New(serverResponse.Message)
}
//--------------------------------------------
// Base64 Decode Encoder public key to []byte
partnerEncoderPublicKeyb64 :=
make([]byte, base64.StdEncoding.DecodedLen(len(serverResponse.Data.ClientEncoderPublicKey)))
n, err := base64.StdEncoding.Decode(partnerEncoderPublicKeyb64,
[]byte(serverResponse.Data.ClientEncoderPublicKey))
if err != nil {
fmt.Println("Error base64 decode encoderPK: "
+ err.Error() + " Code: " + strconv.Itoa(errorDecodingPK))
return errorDecodingPK, err
}
partnerEncoderPublicKeyBytes := partnerEncoderPublicKeyb64[:n]
//--------------------------------------------
// Base64 Decode Decoder public key to []byte
partnerDecoderPublicKeyb64 :=
make([]byte, base64.StdEncoding.DecodedLen(len(serverResponse.Data.ClientDecoderPublicKey)))
n, err = base64.StdEncoding.Decode(partnerDecoderPublicKeyb64,
[]byte(serverResponse.Data.ClientDecoderPublicKey))
if err != nil {
fmt.Println("Error base64 decode decoderPK: "
+ err.Error() + " Code: " + strconv.Itoa(errorDecodingPK))
return errorDecodingPK, err
}
partnerDecoderPublicKeyBytes := partnerDecoderPublicKeyb64[:n]
//-------------------------------
// Create Encoder shared secret
enSSBytes, err :=
encoderEcdh.CreateSharedSecret(partnerEncoderPublicKeyBytes, nil)
if err != nil {
fmt.Println("Error creating Encoder shared secret: "
+ err.Error() + " Code: " + strconv.Itoa(errorCreatingSS))
return errorCreatingSS, err
}
//-----------------------------
// Create Decoder shared secret
deSSBytes, err := decoderEcdh.CreateSharedSecret(partnerDecoderPublicKeyBytes, nil)
if err != nil {
fmt.Println("Error creating Decoder shared secret: "
+ err.Error() + " Code: " + strconv.Itoa(errorCreatingSS))
return errorCreatingSS, err
}
//-------------------------
// Clear out container
encoderEcdh.ClearContainer()
decoderEcdh.ClearContainer()
//------------------------------------
// Check version and output to screen
//------------------------------------
mteVersion := mte.GetVersion()
fmt.Printf("Using Mte Version %s\n", mteVersion)
//--------------------------------
// Check license -- use constants
// If no license can be blank
//--------------------------------
if !mte.InitLicense(companyName, companyLicense) {
fmt.Println("There was an error attempting to initialize the MTE License.")
retcode = errorMteLicense
return 0, errors.New("There was an error attempting to initialize the MTE License.")
}
//---------------------------------
// Create MTE Encoder and Decoder
retcode, err := CreateMteEncoder(serverResponse.Data.TimeStamp, clientId, enSSBytes)
if err != nil {
fmt.Println("Error creating Encoder: "
+ err.Error() + " Code: " + strconv.Itoa(errorCreatingEncoder))
return retcode, err
}
retcode, err = CreateMteDecoder(serverResponse.Data.TimeStamp, clientId, deSSBytes)
if err != nil {
fmt.Println("Error creating Decoder: "
+ err.Error() + " Code: " + strconv.Itoa(errorCreatingDecoder))
return retcode, err
}
return 0, nil
}
Create MTE states
During the initial handshake process the MTE Encoder and MTE Decoder are created and the states are encrypted and stored to our memory cache. Both the server and the client use the same code. Below is a code sample of this process:
- CSharp
- Java
- Python
- Go
/// <summary>
/// Creates the mte states.
/// </summary>
/// <param name="personal">The personal.</param>
/// <param name="entropy">The entropy.</param>
/// <param name="nonce">The nonce.</param>
/// <returns>ResponseModel.</returns>
private static ResponseModel CreateMteStates(string personal,
byte[] encoderEntropy,
byte[] decoderEntropy,
ulong nonce)
{
ResponseModel response = new ResponseModel();
try
{
//--------------------
// Create MTE Encoder
//--------------------
MteEnc encoder = new MteEnc();
encoder.SetEntropy(encoderEntropy);
encoder.SetNonce(nonce);
MteStatus status = encoder.Instantiate(personal);
if (status != MteStatus.mte_status_success)
{
Console.WriteLine($"Error creating encoder: Status: " +
"{encoder.GetStatusName(status)} / {encoder.GetStatusDescription(status)}");
response.Message =
$"Error creating encoder: Status: " +
"{encoder.GetStatusName(status)} / {encoder.GetStatusDescription(status)}";
response.ResultCode = Constants.RC_MTE_ENCODE_EXCEPTION;
response.Success = false;
return response;
}
//------------------------
// Save and encrypt state
//------------------------
var encoderState = encoder.SaveStateB64();
var encryptedEncState = _enc.Encrypt(encoderState, personal, _encIV);
Constants.MteClientState.Store($"{Constants.EncoderPrefix}{personal}",
encryptedEncState,
TimeSpan.FromMinutes(Constants.ExpireMinutes));
//--------------------
// Create MTE Decoder
//--------------------
MteDec decoder = new MteDec();
decoder.SetEntropy(decoderEntropy);
decoder.SetNonce(nonce);
status = decoder.Instantiate(personal);
if (status != MteStatus.mte_status_success)
{
Console.WriteLine($"Error creating decoder: Status: " +
"{decoder.GetStatusName(status)} / {decoder.GetStatusDescription(status)}");
response.Message =
$"Error creating decoder: Status: " +
"{decoder.GetStatusName(status)} / {decoder.GetStatusDescription(status)}";
response.ResultCode = Constants.RC_MTE_DECODE_EXCEPTION;
response.Success = false;
return response;
}
//------------------------
// Save and encrypt state
//------------------------
var decodeState = decoder.SaveStateB64();
var encryptedDecState = _enc.Encrypt(decodeState, personal, _encIV);
Constants.MteClientState.Store($"{Constants.DecoderPrefix}{personal}",
encryptedDecState,
TimeSpan.FromMinutes(Constants.ExpireMinutes));
response.Success = true;
response.ResultCode = Constants.RC_SUCCESS;
response.Message = Constants.STR_SUCCESS;
}
catch (Exception ex)
{
response.Message = $"Exception creating MTE state. Ex: {ex.Message}";
response.ResultCode = Constants.RC_MTE_ENCODE_EXCEPTION;
response.Success = false;
}
return response;
}
/**
* Create Initial MTE states and save to cache
* @param personal --> current conversation id
* @param encoderEntropy --> encoder entropy
* @param decoderEntropy --> decoder entropy
* @param nonce --> MTE nonce
* @return
*/
private static ResponseModel CreateMteStates(String personal,
byte[] encoderEntropy,
byte[] decoderEntropy,
long nonce)
{
ResponseModel response = new ResponseModel();
try
{
//--------------------------
// Create encryption helper
//--------------------------
EncryptionHelper crypt = new EncryptionHelper();
//--------------------
// Create MTE Encoder
//--------------------
MteEnc encoder = new MteEnc();
encoder.setEntropy(encoderEntropy);
encoder.setNonce(nonce);
MteStatus status = encoder.instantiate(personal);
if (status != MteStatus.mte_status_success)
{
System.out.println("Error creating encoder: Status: " +
encoder.getStatusName(status) + " / " +
encoder.getStatusDescription(status));
response.Message =
"Error creating encoder: Status: " +
encoder.getStatusName(status) + " / " +
encoder.getStatusDescription(status);
response.ResultCode = Constants.RC_MTE_ENCODE_EXCEPTION;
response.Success = false;
return response;
}
//------------------------
// Save and encrypt state
//------------------------
String encoderState = encoder.saveStateB64();
String encryptedEncState = crypt.encrypt(encoderState,
EncryptionHelper.SHA256(personal, 64),
_encIV.toString());
_mteStateCacheHelper.Store(Constants.EncoderPrefix + personal, encryptedEncState);
//--------------------
// Create MTE Decoder
//--------------------
MteDec decoder = new MteDec();
decoder.setEntropy(decoderEntropy);
decoder.setNonce(nonce);
status = decoder.instantiate(personal);
if (status != MteStatus.mte_status_success)
{
System.out.println("Error creating decoder: Status: " +
decoder.getStatusName(status) + " / " + decoder.getStatusDescription(status));
response.Message =
"Error creating decoder: Status: " + decoder.getStatusName(status) +
" / " + decoder.getStatusDescription(status);
response.ResultCode = Constants.RC_MTE_DECODE_EXCEPTION;
response.Success = false;
return response;
}
//------------------------
// Save and encrypt state
//------------------------
String decoderState = decoder.saveStateB64();
String encryptedDecState = crypt.encrypt(decoderState,
EncryptionHelper.SHA256(personal, 64),
_encIV.toString());
_mteStateCacheHelper.Store(Constants.DecoderPrefix + personal, encryptedDecState);
response.Success = true;
response.ResultCode = Constants.RC_SUCCESS;
response.Message = Constants.STR_SUCCESS;
}catch(Exception ex) {
response.Message = "Exception creating MTE state. Ex: " + ex.getMessage();
response.ResultCode = Constants.RC_MTE_ENCODE_EXCEPTION;
response.Success = false;
}
return response;
}
def create_mte_states(personal: str, encoder_entropy: str, decoder_entropy: str, nonce: ULONG) -> ResponseModel:
"""
Creates the MTE states.
"""
response = ResponseModel()
# Create the MTE Encoder
encoder = MteEnc.fromdefault()
encoder.set_entropy(base64.b64decode(encoder_entropy))
encoder.set_nonce(nonce)
status = encoder.instantiate(personal)
if status != MteStatus.mte_status_success:
print ("Error creating Encoder: Status: {0} / {1}".format(encoder.get_status_name(status), encoder.get_status_description(status)))
response.message = "Error creating Encoder: Status: {0} / {1}".format(encoder.get_status_name(status), encoder.get_status_description(status))
response.result_code = Constants().RC_MTE_STATE_CREATION
response.success = False
return response
# Save and encrypt state.
encoder_state = encoder.save_state_b64()
encrypted_enc_state = _enc.encrypt(encoder_state, personal, _enc_IV)
_mte_client_state[Constants().ENCODER_PREFIX+personal] = encrypted_enc_state
# Create the MTE Decoder
decoder = MteDec.fromdefault()
decoder.set_entropy(base64.b64decode(decoder_entropy))
decoder.set_nonce(nonce)
status = decoder.instantiate(personal)
if status != MteStatus.mte_status_success:
print ("Error creating Decoder: Status: {0} / {1}".format(decoder.get_status_name(status), decoder.get_status_description(status)))
response.message = "Error creating Decoder: Status: {0} / {1}".format(decoder.get_status_name(status), decoder.get_status_description(status))
response.result_code = Constants().RC_MTE_STATE_CREATION
response.success = False
return response
# Save and encrypt state.
decoder_state = decoder.save_state_b64()
encrypted_dec_state = _enc.encrypt(decoder_state, personal, _enc_IV)
_mte_client_state[Constants().DECODER_PREFIX+personal] = encrypted_dec_state
response.success = True
response.result_code = Constants().RC_SUCCESS
response.message = Constants().STR_SUCCESS
return response
/**
* Creates the MTE Encoder and saves encrypted version to Cache
*/
func CreateMteEncoder(timestamp string, clientId string, encoderEntropy []byte) (out int, err error) {
encoder := mte.NewEncDef()
defer encoder.Destroy()
//----------------------------
// Parse nonce from timestamp
nonce, err := strconv.ParseUint(timestamp, 10, 64)
if err != nil {
fmt.Println(err.Error())
retcode = errorParsingUint
return 0, err
}
//--------------------
// Initialize Encoder
encoder.SetEntropy(encoderEntropy)
encoder.SetNonceInt(nonce)
status := encoder.InstantiateStr(clientId)
if status != mte.Status_mte_status_success {
fmt.Fprintf(os.Stderr, "Encoder instantiate error (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
return int(status), errors.New("encoder instantiate error ("
+ mte.GetStatusName(status) + "):" + mte.GetStatusDescription(status))
}
//----------------------
// Get the Encoder state
encoderState := encoder.SaveState()
//-----------------------------------------------
// Encrypt the Encoder state
// Creates a new byte array the size of the nonce
aesNonce := make([]byte, gcm.NonceSize())
//-----------------------------------------------------
// Populates our nonce with a cryptographically secure
// Random sequence
if _, err = io.ReadFull(crRand.Reader, aesNonce); err != nil {
fmt.Println(err)
retcode = errorEncryptingState
return 0, err
}
//-----------------------------
// Encrypt/Seal Encoder state
encryptedState := gcm.Seal(aesNonce, aesNonce, encoderState, nil)
//------------------------------
// Set encrypted state to Cache
stateCache.Set([]byte(encPrefix+clientId), encryptedState, cacheExpire)
return 0, nil
}
/**
* Creates the MTE Decoder and saves encrypted version to Cache
*/
func CreateMteDecoder(timestamp string, clientId string, decoderEntropy []byte) (out int, err error) {
decoder := mte.NewDecDef()
defer decoder.Destroy()
//----------------------------
// Parse nonce from timestamp
nonce, err := strconv.ParseUint(timestamp, 10, 64)
if err != nil {
fmt.Println(err.Error())
retcode = errorParsingUint
return 0, err
}
//--------------------
// Initialize Decoder
//--------------------
decoder.SetEntropy(decoderEntropy)
decoder.SetNonceInt(nonce)
status := decoder.InstantiateStr(clientId)
if status != mte.Status_mte_status_success {
fmt.Fprintf(os.Stderr, "Decoder instantiate error (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
return int(status), errors.New("decoder instantiate error ("
+ mte.GetStatusName(status) + "):" + mte.GetStatusDescription(status))
}
//-------------------------
// Get the Decoder state
decoderState := decoder.SaveState()
//-------------------------------------------------
// Encrypt state before saving in cache
// Creates a new byte array the size of the nonce
aesNonce := make([]byte, gcm.NonceSize())
//------------------------------------------------------
// Populates our nonce with a cryptographically secure
// Random sequence
if _, err = io.ReadFull(crRand.Reader, aesNonce); err != nil {
fmt.Println(err)
retcode = errorEncryptingState
return 0, err
}
//---------------------------------
// Encrypt/Seal the Decoder state
encryptedState := gcm.Seal(aesNonce, aesNonce, decoderState, nil)
//----------------------------------------------
// Set the encrypted Decoder state in the cache
stateCache.Set([]byte(decPrefix+clientId), encryptedState, cacheExpire)
return 0, nil
}
Restoring the MTE state Client side
The last step is for each client to send messages to the server encoded with their own instance of the MTE. The next example shows how to take the saved MTE state and restore it and then use the MTE to encode or decode a message.
- CSharp
- Java
- Python
- Go
/// <summary>
/// Contacts the server.
/// </summary>
/// <param name="rnd">The random.</param>
/// <param name="currentConversation">The current conversation.</param>
/// <param name="clientNum">The i.</param>
/// <param name="clients">The clients.</param>
/// <exception cref="System.ApplicationException">Error restoring the encoder mte state for
/// Client {i}: {encoder.GetStatusDescription(encoderStatus)}</exception>
/// <exception cref="System.ApplicationException">Error restoring the decoder mte state for
/// Client {i}: {decoder.GetStatusDescription(decoderStatus)}</exception>
/// <exception cref="System.ApplicationException"></exception>
private static async Task ContactServer(Random rnd,
string currentConversation,
int clientNum,
Dictionary<int, string> clients)
{
try
{
//-------------------------------------------------
// Randomly select number of trips between 1 and max number of trips
//-------------------------------------------------
int numberTrips = rnd.Next(1, _maxNumberOfTrips);
//---------------------------------------
// Send message selected number of trips
//---------------------------------------
for (int t = 0; t < numberTrips; t++)
{
//-------------------------------------
// Get the current client encoder state
//-------------------------------------
string encoderState =
Constants.MteClientState.Get($"{Constants.EncoderPrefix}{currentConversation}");
string decryptedEncState =
_enc.Decrypt(encoderState, currentConversation, _encIV);
//-------------------------------------
// Restore the Encoder ensure it works
//-------------------------------------
MteEnc encoder = new MteEnc();
MteStatus encoderStatus = encoder.RestoreStateB64(decryptedEncState);
if (encoderStatus != MteStatus.mte_status_success)
{
Console.WriteLine($"Error restoring the encoder mte state for Client " +
"{clientNum}: {encoder.GetStatusDescription(encoderStatus)}");
throw new ApplicationException($"Error restoring the encoder mte state for Client " +
"{clientNum}: {encoder.GetStatusDescription(encoderStatus)}");
}
//-------------------------------------
// Get the current client decoder state
//-------------------------------------
string decoderState =
Constants.MteClientState.Get($"{Constants.DecoderPrefix}{currentConversation}");
string decryptedDecState =
_enc.Decrypt(decoderState, currentConversation, _encIV);
//-------------------------------------
// Restore the Decoder ensure it works
//-------------------------------------
MteDec decoder = new MteDec();
MteStatus decoderStatus = decoder.RestoreStateB64(decryptedDecState);
if (decoderStatus != MteStatus.mte_status_success)
{
Console.WriteLine($"Error restoring the decoder mte state for Client " +
"{clientNum}: {decoder.GetStatusDescription(decoderStatus)}");
throw new ApplicationException($"Error restoring the decoder mte state for Client " +
"{clientNum}: {decoder.GetStatusDescription(decoderStatus)}");
}
//-------------------------
// Encode message to send
//-------------------------
string message = $"Hello from client {clientNum} for the {t + 1} time.";
string encodedPayload = encoder.EncodeB64(message);
Console.WriteLine($"Sending message '{message}' to multi client server.");
//-----------------------------------------------------------
// Send encoded message to server, putting clientId in header
//-----------------------------------------------------------
string multiClientResponse =
MakeHttpCall($"{_restAPIName}/api/multiclient",
HttpMethod.Post,
currentConversation,
_textContentType,
encodedPayload).Result;
//----------------------
// deserialize response
//----------------------
ResponseModel<string> serverResponse =
JsonSerializer.Deserialize<ResponseModel<string>>(multiClientResponse, _jsonOptions);
if (!serverResponse.Success)
{
if (serverResponse.ResultCode.Equals(Constants.RC_MTE_STATE_NOT_FOUND,
StringComparison.InvariantCultureIgnoreCase))
{
//-------------------------------------------------------------------------
// the server does not have this client's state - we should "re-handshake"
//-------------------------------------------------------------------------
bool handshakeIsSuccessful = HandshakeWithServer(clientNum, clients, currentConversation);
if (!handshakeIsSuccessful)
{
Console.WriteLine($"Error from server for client " +
"{clientNum}: {serverResponse.Message}");
throw new ApplicationException();
}
//-----------------------------------------------------------------
// break out of this loop so we can contact again after handshake
//-----------------------------------------------------------------
return;
}
}
//---------------------------------------------------
// If this was successful save the new encoder state
//---------------------------------------------------
encoderState = encoder.SaveStateB64();
var encryptedEncState = _enc.Encrypt(encoderState, currentConversation, _encIV);
Constants.MteClientState.Store($"{Constants.EncoderPrefix}{currentConversation}",
encryptedEncState,
TimeSpan.FromMinutes(Constants.ExpireMinutes));
//-----------------------------
// decode the incoming message
//-----------------------------
string decodedMessage = decoder.DecodeStrB64(serverResponse.Data, out decoderStatus);
if (decoderStatus != MteStatus.mte_status_success)
{
Console.WriteLine($"Error restoring the decoder mte state for Client " +
"{clientNum}: {decoder.GetStatusDescription(decoderStatus)}");
throw new ApplicationException($"Error restoring the decoder mte state for Client " +
"{clientNum}: {decoder.GetStatusDescription(decoderStatus)}");
}
//----------------------------------------
// If decode is successful save new state
//----------------------------------------
decoderState = decoder.SaveStateB64();
var encryptedDecState = _enc.Encrypt(decoderState, currentConversation, _encIV);
Constants.MteClientState.Store($"{Constants.DecoderPrefix}{currentConversation}",
encryptedDecState,
TimeSpan.FromMinutes(Constants.ExpireMinutes));
//-------------------------------------
// Output incoming message from server
//-------------------------------------
Console.WriteLine($"Received '{decodedMessage}' from multi-client server.\n\n");
// Sleep between each call a random amount of time
// between 10 and 100 milli-seconds
Thread.Sleep(rnd.Next(0, 100));
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
/**
* Contact Server will send an encoded message to the server
* then decode what comes back
* @param rnd -->Random generator for number of trips
* @param currentConversation -->Client conversation
* @param clientNum --> current client number
* @param clients --> client hash map
*/
private static void ContactServer(Random rnd,
String currentConversation,
int clientNum,
HashMap<Integer, String> clients){
try {
//--------------------------
// Create encryption helper
//--------------------------
EncryptionHelper crypt = new EncryptionHelper();
//-------------------------------------------------
// Randomly select number of trips between 1 and max number of trips
//-------------------------------------------------
int numberTrips = rnd.nextInt(1, _maxNumberOfTrips);
//---------------------------------------
// Send message selected number of trips
//---------------------------------------
for (int t = 0; t < numberTrips; t++)
{
//-------------------------------------
// Get the current client encoder state
//-------------------------------------
String encryptedEncState = _mteStateCacheHelper.Get(Constants.EncoderPrefix + currentConversation);
if(encryptedEncState == null || encryptedEncState == "") {
throw new Exception("Cannot find encryted Encoder State for " + currentConversation);
}
String encoderState = crypt.decrypt(encryptedEncState,
EncryptionHelper.SHA256(currentConversation, 64),
_encIV.toString());
//-------------------------------------
// Restore the Encoder ensure it works
//-------------------------------------
MteEnc encoder = new MteEnc();
MteStatus encoderStatus = encoder.restoreStateB64(encoderState);
if (encoderStatus != MteStatus.mte_status_success)
{
System.out.println("Error restoring the encoder mte state for Client " +
clientNum +": " + encoder.getStatusDescription(encoderStatus));
throw new Exception("Error restoring the encoder mte state for Client " +
clientNum + ": " + encoder.getStatusDescription(encoderStatus));
}
//-------------------------
// Encode message to send
//-------------------------
String message = "Hello from client " + clientNum + " for the " + (t + 1) + " time.";
StrStatus encodedPayload = encoder.encodeB64(message);
if(encodedPayload.status != MteStatus.mte_status_success) {
System.out.println("Error encoding the message: " +
encoder.getStatusDescription(encodedPayload.status));
throw new Exception("Error restoring the decoder mte state for Client " +
clientNum + ": " + encoder.getStatusDescription(encodedPayload.status));
}
System.out.println("Sending message " + message + "to multi-client server.");
//-----------------------------------------------------------
// Send encoded message to server, putting clientId in header
//-----------------------------------------------------------
String multipleClientResponse = MakeHttpCall(_restAPIName + "/api/multiclient",
"POST",
currentConversation,
_textContentType,
encodedPayload.str);
//----------------------
// deserialize response
//----------------------
Type multipClientResponseType = new TypeToken<ResponseModel<String>>() {}.getType();
ResponseModel<String> serverResponse = _gson.fromJson(multipleClientResponse, multipClientResponseType);
if(!serverResponse.Success) {
if(serverResponse.ResultCode.equalsIgnoreCase(Constants.RC_MTE_STATE_NOT_FOUND)) {
//-------------------------------------------------------------------------
// the server does not have this client's state - we should "re-handshake"
//-------------------------------------------------------------------------
boolean handshakeIsSuccessful = HandshakeWithServer(clientNum, clients, currentConversation);
if (!handshakeIsSuccessful)
{
System.out.println("Error from server for client " +
clientNum + ": " + serverResponse.Message);
throw new Exception("Error from server for client " +
clientNum + ": " + serverResponse.Message);
}
//-----------------------------------------------------------------
// break out of this loop so we can contact again after handshake
//-----------------------------------------------------------------
return;
}
}
//---------------------------------------------------
// If this was successful save the new encoder state
//---------------------------------------------------
encoderState = encoder.saveStateB64();
encryptedEncState = crypt.encrypt(encoderState,
EncryptionHelper.SHA256(currentConversation, 64),
_encIV.toString());
_mteStateCacheHelper.Store(Constants.EncoderPrefix + currentConversation, encryptedEncState);
//-------------------------------------
// Get the current client decoder state
//-------------------------------------
String encryptedDecState = _mteStateCacheHelper.Get(Constants.DecoderPrefix + currentConversation);
if(encryptedDecState == null || encryptedDecState == "") {
throw new Exception("Cannot find encryted Decoder State for " +
currentConversation);
}
String decoderState = crypt.decrypt(encryptedDecState,
EncryptionHelper.SHA256(currentConversation, 64),
_encIV.toString());
//-------------------------------------
// Restore the Decoder ensure it works
//-------------------------------------
MteDec decoder = new MteDec();
MteStatus decoderStatus = decoder.restoreStateB64(decoderState);
if (decoderStatus != MteStatus.mte_status_success)
{
System.out.println("Error restoring the decoder mte state for Client " +
clientNum +": " + decoder.getStatusDescription(decoderStatus));
throw new Exception("Error restoring the decoder mte state for Client " +
clientNum + ": " + decoder.getStatusDescription(decoderStatus));
}
//-----------------------------
// decode the incoming message
//-----------------------------
StrStatus decodedMessage = decoder.decodeStrB64(serverResponse.Data);
if(decodedMessage.status != MteStatus.mte_status_success) {
System.out.println("Error decoding the message: " +
decoder.getStatusDescription(decodedMessage.status));
throw new Exception("Error decoding the message from the server for " +
clientNum + ": " + decoder.getStatusDescription(decodedMessage.status));
}
//----------------------------------------
// If decode is successful save new state
//----------------------------------------
decoderState = decoder.saveStateB64();
encryptedDecState = crypt.encrypt(decoderState,
EncryptionHelper.SHA256(currentConversation, 64),
_encIV.toString());
_mteStateCacheHelper.Store(Constants.DecoderPrefix + currentConversation, encryptedDecState);
// Sleep between each call a random amount of time
// between 10 and 100 milli-seconds
Thread.sleep(rnd.nextInt(0, 100));
}// end if statement
}catch (Exception ex) {
ex.printStackTrace();
System.out.println("Exception contacting server: "
+ ex.getMessage());
}
return;
}
def contact_server(current_conversation: str, client_num: int):
"""
Contacts the server.
"""
# Randomly select number of trips between 1 and max number of trips.
number_trips = randrange(1, MAX_NUMBER_OF_TRIPS)
# Send message selected number of trips.
for t in range (0, number_trips):
# Get the current client Encoder state.
encoder_state = _mte_client_state.get(Constants().ENCODER_PREFIX + current_conversation)
decrypted_enc_state = _enc.decrypt(encoder_state, current_conversation, _enc_IV)
# Restore the Encoder and ensure it works.
encoder = MteEnc.fromdefault()
encoder_status = encoder.restore_state_b64(decrypted_enc_state)
if encoder_status != MteStatus.mte_status_success:
print("Error restoring the Encoder MTE state for Client {0}: {1}".format(client_num, encoder.get_status_description(encoder_status)))
raise exception("Error restoring the Encoder MTE state for Client {0}: {1}".format(client_num, encoder.get_status_description(encoder_status)))
# Get the current client Decoder state.
decoder_state = _mte_client_state.get(Constants().DECODER_PREFIX + current_conversation)
decrypted_dec_state = _enc.decrypt(decoder_state, current_conversation, _enc_IV)
# Restore the Decoder and ensure it works.
decoder = MteDec.fromdefault()
decoder_status = decoder.restore_state_b64(decrypted_dec_state)
if decoder_status != MteStatus.mte_status_success:
print("Error restoring the Decoder MTE state for Client {0}: {1}".format(client_num, decoder.get_status_description(decoder_status)))
raise exception("Error restoring the Decoder MTE state for Client {0}: {1}".format(client_num, decoder.get_status_description(decoder_status)))
# Encode message to send.
message = "Hello from client {0} for the {1} time.".format(client_num, t+1)
encoded_payload, encode_status = encoder.encode_b64(message)
if encoder_status != MteStatus.mte_status_success:
print ("Error encoding the message for Client {0}: {1}".format(client_num, encoder.get_status_description(encode_status)))
raise exception("Error encoding the message for Client {0}: {1}".format(client_num, encoder.get_status_description(encode_status)))
print ("Sending message {0} to multi client server.\n".format(message))
# Send encoded message to server, putting client_id in header.
url = Constants().REST_API_NAME + "/api/multiclient"
payload = encoded_payload
headers = {
"Content-Type": TEXT_CONTENT_TYPE,
"accept": "*/*",
"Content-Length": str(len(encoded_payload)),
Constants().CLIENT_ID_HEADER: current_conversation
}
multi_client_response = requests.post(
url=url, data=payload, headers=headers)
# Deserialize response.
server_response = multi_client_response.json()
if server_response['Success'] == False:
# Check if we need to re-handshake.
if server_response['ResultCode'] == Constants().RC_MTE_STATE_NOT_FOUND:
# The server does not thave this client's state - we should re-handshake.
handshake_is_successful = handshake_with_server(client_num, current_conversation)
if handshake_is_successful == False:
print ("Error from server for client {0}: {1}".format(client_num, server_response['Message']))
# Break out of loop so we can contact again after handshake.
raise Exception("Error from server for client {0}: {1}".format(client_num, server_response['Message']))
# If this was successful, save the new Encoder state.
encoder_state = encoder.save_state_b64()
encrypted_enc_state = _enc.encrypt(encoder_state, current_conversation, _enc_IV)
_mte_client_state[Constants().ENCODER_PREFIX+current_conversation] = encrypted_enc_state
# Decode the incoming message.
decoded_message, decoder_status = decoder.decode_str_b64(server_response['Data'])
if decoder.status_is_error(decoder_status):
print ("Error decoding the message for Client {0}: {1}".format(client_num, decoder.get_status_description(decoder_status)))
raise exception("Error decoding the message for Client {0}: {1}".format(client_num, decoder.get_status_description(decoder_status)))
# If decode is successful, save the new Decoder state.
decoder_state = decoder.save_state_b64()
encrypted_dec_state = _enc.encrypt(decoder_state, current_conversation, _enc_IV)
_mte_client_state[Constants().DECODER_PREFIX+current_conversation] = encrypted_dec_state
print ("Received {0} from multi-client server.\n".format(decoded_message))
# Sleep between each call a random amount of time.
time.sleep(randrange(0,100)/1000)
/**
* Send MTE Encoded message to server
*/
func SendMultiToServer(clientId string, clientNum int, wg *sync.WaitGroup) {
//-------------------------------------------------
// Make sure done is called when this is finsihed
defer wg.Done()
//--------------------------------------------
// Get random number of times to send messages
randNum := mrand.Intn(maxNumTrips-1) + 1
//-----------------
// Create Encoder
encoder := mte.NewEncDef()
defer encoder.Destroy()
//--------------------------------------------------
// Get the Encoder state from the cache and decrypt
encoderState, err := stateCache.Get([]byte(encPrefix + clientId))
nonceSize := gcm.NonceSize()
if len(encoderState) < nonceSize {
fmt.Println(err)
retcode = errorRetrievingState
return
}
aesNonce, encoderState := encoderState[:nonceSize], encoderState[nonceSize:]
decryptedState, err := gcm.Open(nil, aesNonce, encoderState, nil)
if err != nil {
fmt.Println(err)
retcode = errorDecryptingState
return
}
//---------------------------
// Restore the Encoder state
encoderStatus := encoder.RestoreState(decryptedState)
if encoderStatus != mte.Status_mte_status_success {
errorMessage := "Encoder restore error ("
+ mte.GetStatusName(encoderStatus) + ", "
+ mte.GetStatusDescription(encoderStatus) + ")"
fmt.Println(errorMessage)
retcode = errorRestoringState
return
}
//------------------------
// Create the MTE Decoder
decoder := mte.NewDecDef()
defer decoder.Destroy()
//-----------------------------------
// Get the Decoder state and decrypt
decoderState, err := stateCache.Get([]byte(decPrefix + clientId))
nonceSize = gcm.NonceSize()
if len(decoderState) < nonceSize {
fmt.Println(err)
retcode = errorRetrievingState
return
}
aesNonce, decoderState = decoderState[:nonceSize], decoderState[nonceSize:]
decryptedState, err = gcm.Open(nil, aesNonce, decoderState, nil)
if err != nil {
fmt.Println(err)
retcode = errorDecryptingState
return
}
//---------------------------
// Restore the Decoder state
decoderStatus := decoder.RestoreState(decryptedState)
if decoderStatus != mte.Status_mte_status_success {
errorMessage := "Decoder restore error ("
+ mte.GetStatusName(decoderStatus) + ", "
+ mte.GetStatusDescription(decoderStatus) + ")"
fmt.Println(errorMessage)
retcode = errorRestoringState
return
}
//---------------------------------------------------------------
// Send message to server random number of times for this client
for i := 1; i <= randNum; i++ {
//----------------------
// Set message content
message := "Hello from client " + strconv.Itoa(clientNum) + " : "
+ clientId + " for the " + strconv.Itoa(i) + " time"
//----------------
// Encode message
encoded, encoderStatus := encoder.EncodeStrB64(message)
if encoderStatus != mte.Status_mte_status_success {
errorMessage := "Encode error " + mte.GetStatusName(encoderStatus)
+ " , " + mte.GetStatusDescription(encoderStatus)
fmt.Println(errorMessage)
retcode = errorEncodingData
return
}
//------------------------------------
// Make Http Call to send to server
hsModelString, errorcode, err := MakeHttpCall(restAPIName+multiClientRoute,
"POST",
clientId,
textContent,
encoded)
if err != nil {
errorMessage := "Error making Http call: "
+ err.Error() + " Code: " + strconv.Itoa(errorcode)
fmt.Println(errorMessage)
retcode = errorcode
return
}
//-----------------------------
// Marshal json back to class
hrBytes := []byte(hsModelString)
var serverResponse ResponseModel[string]
json.Unmarshal(hrBytes, &serverResponse)
if !serverResponse.Success {
errorMessage := "Error back from server: "
+ serverResponse.Message + " Code: " + strconv.Itoa(errorFromServer)
fmt.Println(errorMessage)
retcode = errorMarshalJson
return
}
//-----------------------
// Decode return message
decodedMessage, decoderStatus := decoder.DecodeStrB64(serverResponse.Data)
if mte.StatusIsError(decoderStatus) {
errorMessage := "Decode error " + mte.GetStatusName(decoderStatus)
+ " , " + mte.GetStatusDescription(decoderStatus)
fmt.Println(errorMessage)
retcode = errorDecodingData
return
}
//----------------------------------------
// Print out message received from server
fmt.Println("Received '" + decodedMessage + "' from multi-client server.")
}
//--------------------
// save Encoder state
encoderState = encoder.SaveState()
//-------------------------
// Delete from cache first
stateCache.Del([]byte(encPrefix + clientId))
//------------------------------------
// Encrypt state to put back in cache
// Creates a new byte array the size of the nonce
aesNonce = make([]byte, gcm.NonceSize())
//-----------------------------------------------------
// Populates our nonce with a cryptographically secure
// Random sequence
if _, err = io.ReadFull(crRand.Reader, aesNonce); err != nil {
fmt.Println(err)
retcode = errorEncryptingState
return
}
//---------------------------------------
// Seal/Encrpyt the actual Encoder State
encryptedState := gcm.Seal(aesNonce, aesNonce, encoderState, nil)
//-------------------------------------------
// Update cache with encrypted Encoder State
stateCache.Set([]byte(encPrefix+clientId), encryptedState, cacheExpire)
//---------------------
// Save Decoder state
decoderState = decoder.SaveState()
//-------------------------
// Delete from cache first
stateCache.Del([]byte(decPrefix + clientId))
//------------------------------------
// Encrypt state to put back in cache
// Creates a new byte array the size of the nonce
aesNonce = make([]byte, gcm.NonceSize())
//-----------------------------------------------------
// Populates our nonce with a cryptographically secure
// Random sequence
if _, err = io.ReadFull(crRand.Reader, aesNonce); err != nil {
fmt.Println(err)
retcode = errorEncryptingState
return
}
//---------------------------------------
// Seal/Encrpyt the actual Decoder State
encryptedState = gcm.Seal(aesNonce, aesNonce, decoderState, nil)
//-------------------------------------------
// Update cache with encrypted Encoder State
stateCache.Set([]byte(decPrefix+clientId), encryptedState, cacheExpire)
}
Full Client Side Sample
Here is the entire console side application code.
Full Server Side API
The server side API is only written in CSharp and not in all the other languages. All of the client side console applications can be successfully run against the Server Side API. The server includes other projects as well, below I will only include files that include the multiple client example.