Skip to main content

MTE Core Code Examples

Purpose

The objective of an MTE Core "Examples" is to provide short examples of how to use the MTE Core Encoder and MTE Core Decoder.

MTE Core Encoder

Create MTE Core Encoder

The MTE Core Encoder will be created using default options. The default options will set preferred security options recommended by Eclypses. Custom options should only be used in special circumstances and after reading and understanding how to select the best options for a given situation. More information about how to select these options can be found in the official MTE Developer Guides.

Create Default Encoder

// Create MTE Core Encoder with defaults
MteEnc mteEncoder = new MteEnc();

// Need entropy, nonce and personalization string
// These values should be unique and entropy must be treated like encryption keys!
// The following personalization string and nonce values are for
// demonstration only and should not be used in a production environment
string personalizationString = "MySecretPersonalizationStringGoesHere";
long nonce = 12345678;

// *** IMPORTANT NOTE ***
// Entropy is critical to security and should be created and handled like encryption keys.
// To permit decoding of encoded value, Encoder and Decoder must use identical Entropy, Nonce and
// Personalization String as well as Options . See Developer Guides for more information.

// Check how long of entropy we need.
// This example fills entropy with at string of zeros
// this should NOT be used in a production environment
int entropyMinBytes = mteEncoder.GetDrbgsEntropyMinBytes(mteEncoder.GetDrbg());
string entropy = (entropyMinBytes > 0)
? new String('0', entropyMinBytes)
: string.Empty;

// Set encoder entropy and nonce
mteEncoder.SetEntropy(Encoding.UTF8.GetBytes(entropy));
mteEncoder.SetNonce(nonce);

// Initialize MTE encoder
MteStatus encoderStatus = mteEncoder.Instantiate(personalizationString);
if(encoderStatus !=MteStatus.mte_status_success)
{
// MTE cannot continue so handle failure appropriately
// Below is just an example
throw new ApplicationException($"Failed to initialize the MTE encoder engine." +
$"Status: {mteEncoder.GetStatusName(encoderStatus)} / " +
$"{mteEncoder.GetStatusDescription(encoderStatus)}");
}

Encoding to a base64 string or byte[]

Use the following methods to encode a string or a byte[]. The samples below display all the options that can be used to encode, only one method needs to be used to encode the data. The developer should select the method that works with the type of data that is used.

// Example value to be encoded
string inputString = "What I want to be encoded goes here";
byte[] bytesToBeEncoded = Encoding.ASCII.GetBytes(inputString);

// initialize status
MteStatus encoderStatus;

// Below are 4 different examples of how to encode
// ONLY ONE needs to be used!!!
// Encode byte[] to a base64 string
string encodedBytesAsString = mteEncoder.EncodeB64(bytesToBeEncoded, out encoderStatus);
if(encoderStatus != MteStatus.mte_status_success)
{
// Handle encode failure appropriately
// Below is only an example
throw new Exception("Failed to encode. Status: "
+ mteEncoder.GetStatusName(encoderStatus)+ " / "
+ mteEncoder.GetStatusDescription(encoderStatus));
}
// Encode string to a base64 string
string encodedStringAsString = mteEncoder.EncodeStrB64(inputString, out encoderStatus);
if(encoderStatus != MteStatus.mte_status_success)
{
// Handle encode failure appropriately
// Below is only an example
throw new Exception("Failed to encode. Status: "
+ mteEncoder.GetStatusName(encoderStatus)+ " / "
+ mteEncoder.GetStatusDescription(encoderStatus));
}
// Encode byte[] to a byte[]
byte[] encodedBytesAsBytes = mteEncoder.Encode(bytesToBeEncoded, out encoderStatus);
if(encoderStatus != MteStatus.mte_status_success)
{
// Handle encode failure appropriately
// Below is only an example
throw new Exception("Failed to encode. Status: "
+ mteEncoder.GetStatusName(encoderStatus)+ " / "
+ mteEncoder.GetStatusDescription(encoderStatus));
}
// Encode string to a byte[]
byte[] encodedStringAsBytes = mteEncoder.EncodeStr(inputString, out encoderStatus);
if(encoderStatus != MteStatus.mte_status_success)
{
// Handle encode failure appropriately
// Below is only an example
throw new Exception("Failed to encode. Status: "
+ mteEncoder.GetStatusName(encoderStatus)+ " / "
+ mteEncoder.GetStatusDescription(encoderStatus));
}

Encoder State

The encoder state can be saved and restored with either byte[] or a base64 string using the following methods. Below are several examples of how to use it, based on your data type you only need to use one of the following examples.

// Save and restore Encoder state with bytes
// Get byte[] of encoder state
byte[] encoderByteState = mteEncoder.SaveState();

// Restore Encoder with byte[] state
MteStatus encoderStatus = mteEncoder.RestoreState(encoderByteState);
if(encoderStatus != MteStatus.mte_status_success)
{
// Encoder restore failed, handle appropriately
// Below is only an example
throw new Exception("Failed to restore Encoder state. Status: "
+ mteEncoder.GetStatusName(encoderStatus)+ " / "
+ mteEncoder.GetStatusDescription(encoderStatus));
}
// Save and restore Encoder state with string
// Get string of Encoder state
string encoderStrState = mteEncoder.SaveStateB64();

// Restore Encoder with string state
MteStatus encoderStatus = mteEncoder.RestoreStateB64(encoderStrState);
if(encoderStatus != MteStatus.mte_status_success)
{
// Encoder restore failed, handle appropriately
// Below is only an example
throw new Exception("Failed to restore encoder state. Status: "
+ mteEncoder.GetStatusName(encoderStatus)+ " / "
+ mteEncoder.GetStatusDescription(encoderStatus));
}

Additional options for Encoder State

The Core MTE encoder state and the MTE MKE encoder state are interchangeable. This means, the encoder state can be restored to a MTE Core OR an MTE MKE. The MTE used should be created using the same options for this to work correctly. The security of the MTE Core can be used for a password then the MTE MKE can be used on larger data in the same application without having to create multiple instances of the MTE.

Reseeding Interval

There are a limited amount of random numbers a DRBG can produce before it must be reseeded. This is called the reseed interval. The DRBG will stop functioning in order to protect the security of the application. When the MTE reaches it's reseed interval the MTE will return a status of "mte_status_drbg_seedlife_reached".

The developer can use the reseed count and the reseed interval to determine if the seed life is ending. We recommend reseeding the MTE before the seed life ends in order to prevent the loss of any data. Reseeding the MTE can be done by re-initializing the MTE with a new entropy value and new nonce. Both sides, the Encoder and Decoder, must be re-initialized at the same time to stay in sync.

The example below checks for 90% usage before re-initializing. For DRBGs with large reseed interval, 90% is a good number. To determine a good percentage the size of the data transmission should be used. For small data transmissions a value much closer to 100% can be used; for larger data transmissions or smaller reseed intervals, a smaller percentage should be used to ensure the end of the seed life is not hit.


//--------------------------------------
// Get the Encoder DRBG reseed counter
// This is the MTE's current seed count
ulong currentSeed = mteEncoder.GetReseedCounter();

//------------------------------------------
// Get the Encoder DRBG max reseed interval
ulong maxSeed = mteBase.GetDrbgsReseedInterval(mteEncoder.GetDrbg());

//---------------------------------------------------------
// If the current seed is greater than 90% of the max seed
// Uninstantiate the MTE then Reinitialize the MTE
// with a new entropy and nonce to reseed
if (currentSeed > (maxSeed * 0.9)){
//---------------------------
// Uninstantiate the Encoder
MteStatus encoderStatus = mteEncoder.Uninstantiate();
if(encoderStatus != MteStatus.mte_status_success) {
//-------------------------------------------------
// MTE was not uninstantiated as desired so handle
// failure appropriately, below is only an example
throw new Exception("Failed to uninstantiate Encoder. Status: "
+ mteEncoder.GetStatusName(encoderStatus)+ " / "
+ mteEncoder.GetStatusDescription(encoderStatus));
}
//---------------------------------------
// Re-handshake to get new entropy value
// AND new nonce value
// Full code sample not here, to see example
// please see Diffie-Hellman Key Exchange
HandshakeModel handshake = MethodToHandshake();

//-------------------------------
// Set Encoder entropy and nonce
mteEncoder.SetEntropy(Encoding.UTF8.GetBytes(handshake.NewEncoderEntropy));
mteEncoder.SetNonce(handshake.NewNonce);
//------------------------
// Initialize MTE Encoder
MteStatus encoderStatus = mteEncoder.Instantiate(personalizationString);
if(encoderStatus !=MteStatus.mte_status_success) {
//-----------------------------------------------------
// MTE cannot continue so handle failure appropriately
// Below is just an example
throw new ApplicationException($"Failed to initialize the MTE Encoder engine." +
$"Status: {mteEncoder.GetStatusName(encoderStatus)} / " +
$"{mteEncoder.GetStatusDescription(encoderStatus)}");
}
}

Uninstantiate Encoder

Uninstantiate encoder, this will zeroize the DRBG state and returns the status.

// Uninstantiate the Encoder
MteStatus encoderStatus = mteEncoder.Uninstantiate();
if(encoderStatus != MteStatus.mte_status_success)
{
// MTE was not uninstantiated as desired so handle failure appropriately
// Below is only an example
throw new Exception("Failed to uninstantiate Encoder. Status: "
+ mteEncoder.GetStatusName(encoderStatus)+ " / "
+ mteEncoder.GetStatusDescription(encoderStatus));
}

MTE Core Decoder

Create MTE Core Decoder

The MTE Core Decoder will be created using default options. The default options will set preferred security options recommended by Eclypses. Custom options should only be used in special circumstances and after reading and understanding how to select the best options for a given situation. More information about how to select these options can be found in the official MTE Developer Guides.

Create Default Decoder

// Create MTE Core Decoder with defaults
MteDec mteDecoder = new MteDec();

// Need entropy, nonce and personalization string
// These values should be unique and entropy must be treated like encryption keys!
// The following personalization string and nonce values are for
// demonstration only and should not be used in a production environment
string personalizationString = "MySecretPersonalizationStringGoesHere";
long nonce = 12345678;

// *** IMPORTANT NOTE ***
// Entropy is critical to security and should be created and handled like encryption keys.
// To permit decoding of encoded value, Encoder and Decoder must use identical Entropy, Nonce and
// Personalization String as well as Options . See Developer Guides for more information.

// Check how long of entropy we need.
// This example fills entropy with at string of zeros
// this should NOT be used in a production environment
int entropyMinBytes = mteDecoder.GetDrbgsEntropyMinBytes(mteDecoder.GetDrbg());
string entropy = (entropyMinBytes > 0)
? new String('0', entropyMinBytes)
: string.Empty;

// Set Decoder entropy and nonce
mteDecoder.SetEntropy(Encoding.UTF8.GetBytes(entropy));
mteDecoder.SetNonce(nonce);

// Initialize MTE Decoder
MteStatus decoderStatus = mteDecoder.Instantiate(personalizationString);
if(decoderStatus != MteStatus.mte_status_success)
{
// MTE cannot continue so handle failure appropriately
// Below is just an example
throw new ApplicationException($"Failed to initialize the MTE Decoder engine." +
$"Status: {mteDecoder.GetStatusName(decoderStatus)} / " +
$"{mteDecoder.GetStatusDescription(decoderStatus)}");
}

Decoding string or byte[]

Use the following methods to decode a string or a byte[] to the original value. The samples below display all the options that can be used to decode, only one method needs to be used to decode the data. The developer should select the method that works with the type of data that is used.

// initialize status
MteStatus decoderStatus;

// Below are 4 different examples of how to decode
// ONLY ONE needs to be used!!!
// Decode byte[] to a base64 string
string decodedBytesAsString = mteDecoder.DecodeStr(encodedBytes, out decoderStatus);
if (mteDecoder.StatusIsError(decoderStatus)) {
// Unable to decode, this checks for errors, handle failure appropriately
// Below is only an example
Console.Error.WriteLine("Decode error ({0}): {1}",
mteDecoder.GetStatusName(decoderStatus),
mteDecoder.GetStatusDescription(decoderStatus));
return (int)status;
// This catches Decoder warnings, the decode process was successful
// But depending on the type of security needed these may be ignored
// Please see Developer Guide for more details.
} else if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decode warning ({0}): {1}",
mteDecoder.GetStatusName(decoderStatus),
mteDecoder.GetStatusDescription(decoderStatus));
}
// Decode string to a base64 string
string decodedStringAsString = mteDecoder.DecodeStrB64(encodedBase64String, out decoderStatus);
if (mteDecoder.StatusIsError(decoderStatus)) {
// Unable to decode, this checks for errors, handle failure appropriately
// Below is only an example
Console.Error.WriteLine("Decode error ({0}): {1}",
mteDecoder.GetStatusName(decoderStatus),
mteDecoder.GetStatusDescription(decoderStatus));
return (int)status;
// This catches Decoder warnings, the decode process was successful
// But depending on the type of security needed these may be ignored
// Please see Developer Guide for more details.
} else if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decode warning ({0}): {1}",
mteDecoder.GetStatusName(decoderStatus),
mteDecoder.GetStatusDescription(decoderStatus));
// Decode byte[] to a byte[]
byte[] decodedBytes = mteDecoder.Decode(encodedBytes, out decoderStatus);
if (mteDecoder.StatusIsError(decoderStatus)) {
// Unable to decode, this checks for errors, handle failure appropriately
// Below is only an example
Console.Error.WriteLine("Decode error ({0}): {1}",
mteDecoder.GetStatusName(decoderStatus),
mteDecoder.GetStatusDescription(decoderStatus));
return (int)status;
// This catches Decoder warnings, the decode process was successful
// But depending on the type of security needed these may be ignored
// Please see Developer Guide for more details.
} else if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decode warning ({0}): {1}",
mteDecoder.GetStatusName(decoderStatus),
mteDecoder.GetStatusDescription(decoderStatus));
// Decode string to a byte[]
byte[] decodedStringAsBytes = mteDecoder.DecodeB64(encodedBase64String, out decoderStatus);
if (mteDecoder.StatusIsError(decoderStatus)) {
// Unable to decode, this checks for errors, handle failure appropriately
// Below is only an example
Console.Error.WriteLine("Decode error ({0}): {1}",
mteDecoder.GetStatusName(decoderStatus),
mteDecoder.GetStatusDescription(decoderStatus));
return (int)status;
// This catches Decoder warnings, the decode process was successful
// But depending on the type of security needed these may be ignored
// Please see Developer Guide for more details.
} else if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decode warning ({0}): {1}",
mteDecoder.GetStatusName(decoderStatus),
mteDecoder.GetStatusDescription(decoderStatus));

Decoder State

The decoder state can be saved and restored with either byte[] or a base64 string using the following methods. Below are several examples of how to use it, based on your data type you only need to use one of the following examples.

// Save and restore Decoder state with bytes
// Get byte[] of decoder state
byte[] decoderByteState = mteDecoder.SaveState();

// Restore Decoder with byte[] state
MteStatus decoderStatus = mteDecoder.RestoreState(decoderByteState);
if(decoderStatus != MteStatus.mte_status_success)
{
// Decoder restore failed, handle appropriately
// Below is only an example
throw new Exception("Failed to restore Decoder state. Status: "
+ mteDecoder.GetStatusName(decoderStatus)+ " / "
+ mteDecoder.GetStatusDescription(decoderStatus));
}
// save and restore Decoder state with string
// Get string of Decoder state
string decoderStrState = mteDecoder.SaveStateB64();

// Restore Decoder with string state
MteStatus decoderStatus = mteDecoder.RestoreStateB64(decoderStrState);
if(decoderStatus != MteStatus.mte_status_success)
{
// Decoder restore failed, handle appropriately
// Below is only an example
throw new Exception("Failed to restore Decoder state. Status: "
+ mteDecoder.GetStatusName(decoderStrStatus)+ " / "
+ mteDecoder.GetStatusDescription(decoderStrStatus));
}

Additional options for Decoder State

The Core MTE decoder state and the MTE MKE decoder state are interchangeable. This means, the decoder state can be restored to a MTE Core OR an MTE MKE. The MTE used should be created using the same options for this to work correctly. The security of the MTE Core can be used for a password then the MTE MKE can be used on larger data in the same application without having to create multiple instances of the MTE.

Reseeding Interval

There are a limited amount of random numbers a DRBG can produce before it must be reseeded. This is called the reseed interval. The DRBG will stop functioning in order to protect the security of the application. When the MTE reaches it's reseed interval the MTE will return a status of "mte_status_drbg_seedlife_reached".

The developer can use the reseed count and the reseed interval to determine if the seed life is ending. We recommend reseeding the MTE before the seed life ends in order to prevent the loss of any data. Reseeding the MTE can be done by re-initializing the MTE with a new entropy value and new nonce. Both sides, the Encoder and Decoder, must be re-initialized at the same time to stay in sync.

The example below checks for 90% usage before re-initializing. For DRBGs with large reseed interval, 90% is a good number. To determine a good percentage the size of the data transmission should be used. For small data transmissions a value much closer to 100% can be used; for larger data transmissions or smaller reseed intervals, a smaller percentage should be used to ensure the end of the seed life is not hit.

//--------------------------------------
// Get the Decoder DRBG reseed counter
// This is the MTE's current seed count
ulong currentSeed = mteDecoder.GetReseedCounter();

//------------------------------------------
// Get the Decoder DRBG max reseed interval
ulong maxSeed = mteBase.GetDrbgsReseedInterval(mteDecoder.GetDrbg());

//---------------------------------------------------------
// If the current seed is greater than 90% of the max seed
// Uninstantiate the MTE then Reinitialize the MTE
// with a new entropy and nonce to reseed
if (currentSeed > (maxSeed * 0.9)) {
//---------------------------
// Uninstantiate the Decoder
MteStatus decoderStatus = mteDecoder.Uninstantiate();
if(decoderStatus != MteStatus.mte_status_success) {
//-------------------------------------------------
// MTE was not uninstantiated as desired so handle
// failure appropriately, below is only an example
throw new Exception("Failed to uninstantiate Decoder. Status: "
+ mteDecoder.GetStatusName(decoderStatus)+ " / "
+ mteDecoder.GetStatusDescription(decoderStatus));
}
//---------------------------------------
// Re-handshake to get new entropy value
// AND new nonce value
// Full code sample not here, to see example
// please see Diffie-Hellman Key Exchange
HandshakeModel handshake = MethodToHandshake();

//-------------------------------
// Set Decoder entropy and nonce
mteDecoder.SetEntropy(Encoding.UTF8.GetBytes(handshake.NewEncoderEntropy));
mteDecoder.SetNonce(handshake.NewNonce);
//------------------------
// Initialize MTE Decoder
MteStatus decoderStatus = mteDecoder.Instantiate(personalizationString);
if(decoderStatus !=MteStatus.mte_status_success) {
//-----------------------------------------------------
// MTE cannot continue so handle failure appropriately
// Below is just an example
throw new ApplicationException($"Failed to initialize the MTE Decoder engine." +
$"Status: {mteDecoder.GetStatusName(decoderStatus)} / " +
$"{mteDecoder.GetStatusDescription(decoderStatus)}");
}
}

Get Timestamps from Decoder

After an MTE packet has been sent, the MTE decoder has the encoded timestamp value as well as the decoded timestamp value. They can be retrieved using the following code:

// Get the Encode timestamp
ulong encoderTs = mteDecoder.GetEncTs();
// Get the Decode timestamp
ulong decoderTs = mteDecoder.GetDecTs();

Get Messages Skipped from Decoder

After an MTE packet has been sent, the MTE decoder has the number of messages that were skipped. This can be retrieved using the following code:

// Get the number of messages skipped.
uint32_t decoder_msg_skipped = d_args.msg_skipped;

Uninstantiate Decoder

Uninstantiate decoder, this will zeroize the DRBG state and returns the status.

// Uninstantiate the Decoder
MteStatus decoderStatus = mteDecoder.Uninstantiate();
if(decoderStatus != MteStatus.mte_status_success)
{
// MTE was not uninstantiated as desired so handle failure appropriately
// Below is only an example
throw new Exception("Failed to uninstantiate Decoder. Status: "
+ mteDecoder.GetStatusName(decoderStatus)+ " / "
+ mteDecoder.GetStatusDescription(decoderStatus));
}