Skip to main content

MTE Sequencing Verifier Code Samples

Purpose

Samples expand on our "Examples" by providing longer snippets of code demonstrating the entire processes. The objective of an MTE Sequencing Verifier "Samples" is to provide full samples of code of how to use the MTE Sequencing functions.

The sequencing verifier only affects the MTE decoder and should be enabled when lossy or asynchronous (out-of-order) communication is possible. The verifier has three different modes of operation (verification only mode, forward only mode, and async mode), determined by the sequence window setting in the decoder. For more information, please see the official MTE developer guides.

Encoder Creation

The encoder for sequencing is going to be the same no matter which sequencing we will use. Here is a quick sample of how to create the encoder for each example below.

// Status.
MteStatus status;

// Inputs.
string[] inputs = {
"message 1",
"message 2",
"message 3",
"message 4"
};

// Personalization string.
string personal = "demo";

// Initialize MTE license. If a license code is not required (e.g., trial
// mode), this can be skipped. This demo attempts to load the license
// info from the environment if required.
MteBase baseObj = new MteBase();
if (!baseObj.InitLicense("YOUR_COMPANY", "YOUR_LICENSE")) {
string company = Environment.GetEnvironmentVariable("MTE_COMPANY");
string license = Environment.GetEnvironmentVariable("MTE_LICENSE");
if (company == null || license == null ||
!baseObj.InitLicense(company, license)) {
status = MteStatus.mte_status_license_error;
Console.Error.WriteLine("License init error ({0}): {1}",
baseObj.GetStatusName(status),
baseObj.GetStatusDescription(status));
return (int)status;
}
}

// Create the Encoder.
MteEnc encoder = new MteEnc();

// Create all-zero entropy for this demo. The nonce will also be set to 0.
// This should never be done in real applications.
int entropyBytes = encoder.GetDrbgsEntropyMinBytes(encoder.GetDrbg());
byte[] entropy = new byte[entropyBytes];

// Instantiate the Encoder.
encoder.SetEntropy(entropy);
encoder.SetNonce(0);
status = encoder.Instantiate(personal);
if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Encoder instantiate error ({0}): {1}",
encoder.GetStatusName(status),
encoder.GetStatusDescription(status));
return (int)status;
}

// Encode the inputs.
string[] encodings = new string[inputs.Length];
for (int i = 0; i < inputs.Length; ++i) {
encodings[i] = encoder.EncodeB64(inputs[i], out status);
if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Encode error ({0}): {1}",
encoder.GetStatusName(status),
encoder.GetStatusDescription(status));
return (int)status;
}
Console.WriteLine("Encode #{0}: {1} -> {2}",
i,
inputs[i],
encodings[i]);
}

Verification-Only

In verification-only mode, which is enabled by setting the sequence window to 0, the sequence number is checked before decoding is attempted and if it is not the expected number, no decode is attempted and an error is returned. This may be useful in cases where missing data is not acceptable (e.g., real-time commands to a robot) and needs to be detected. For more information, please see the official MTE developer guides.

The following sample will highlight how the verification-only sequencing mode works by decoding the input messages in the following order:

  • Message 1 – success
  • Message 1 – error -- repeat message
  • Message 3 – error -- message 1 expected
  • Message 2 – success
  • Message 3 – success
  • Message 4 – success
// Create Decoder with Verification-only sequencing
// When constructing an MteDec the second argument is
// the sequence window (the first is the timestamp window)
MteDec decoderV = new MteDec(0, 0);

// Instantiate the Decoder.
decoderV.SetEntropy(entropy);
decoderV.SetNonce(0);
status = decoderV.Instantiate(personal);
if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decoder instantiate error ({0}): {1}",
decoderV.GetStatusName(status),
decoderV.GetStatusDescription(status));
return (int)status;
}

// Output that decoding is in verification-only sequencing mode
Console.WriteLine("\nVerification-only mode (sequence window = 0):");

// Decode the first message
// Output: Decode #1: mte_status_success, message 1
decoded = decoderV.DecodeStrB64(encodings[0], out status);
Console.WriteLine("Decode #1: {0}, {1}",
decoderV.GetStatusName(status),
decoded);

// Try to decode the first message again -- out of sequence, should not work
// Output: Decode #1: mte_status_seq_outside_window,
decoded = decoderV.DecodeStrB64(encodings[0], out status);
Console.WriteLine("Decode #1: {0}, {1}",
decoderV.GetStatusName(status),
decoded);

// Decode the third message -- out of sequence should not work
// Output: Decode #3: mte_status_seq_outside_window,
decoded = decoderV.DecodeStrB64(encodings[2], out status);
Console.WriteLine("Decode #3: {0}, {1}",
decoderV.GetStatusName(status),
decoded);

// Decode the second message
// Output: Decode #2: mte_status_success, message 2
decoded = decoderV.DecodeStrB64(encodings[1], out status);
Console.WriteLine("Decode #2: {0}, {1}",
decoderV.GetStatusName(status),
decoded);

// Decode the third message
// Output: Decode #3: mte_status_success, message 3
decoded = decoderV.DecodeStrB64(encodings[2], out status);
Console.WriteLine("Decode #3: {0}, {1}",
decoderV.GetStatusName(status),
decoded);

// Decode the fourth message
// Output: Decode #4: mte_status_success, message 4
decoded = decoderV.DecodeStrB64(encodings[3], out status);
Console.WriteLine("Decode #4: {0}, {1}",
decoderV.GetStatusName(status),
decoded);

Forward-Only

In forward-only mode, which is enabled by setting the sequence window to a positive number, the sequence number is checked before decoding and if it is ahead of the expected number and within the window, a catch-up algorithm is invoked to skip over the missing messages in order to successfully decode the current message. This may be useful in cases where missing data is acceptable (e.g., streaming video dropping some frames) and the desire is to just get what comes through. For more information, please see the official MTE developer guides.

If the catch-up still results in a decode failure, the state is rolled back as if the decode had not been attempted, with the assumption that the message was corrupt.

If the sequence number was outside the window, an error is returned before attempting to decode.

This mode requires that all messages are the same length, so MTE can know how to get back in sync. There are many ways to ensure this, including add-ons like Fixed-Length and Managed-Key Encryption, or the SDK user may have their own way of knowing the input is always the same length. The Fixed-Length Add-On always produces messages of the same length. The Managed-Key Encryption Add-On always produces fixed-length (for sequencing purposes) messages while at the same time allowing variable-length data.

The following sample will highlight how the verification-only sequencing mode works by decoding the input messages in the following order:

  • Message 1 – success
  • Message 1 – error -- repeat message
  • Corrupt Message 3 – error -- corrupted message
  • Message 3 – success (ahead of what is expected but within window)
  • Message 2 – error -- behind expected sequence number
  • Message 3 – error -- repeat message
  • Message 4 – success
// Create Forward-only Decoder
// For this sample sequence window is being set to 2
MteDec decoderF = new MteDec(0, 2);

// Instantiate the Decoder
decoderF.SetEntropy(entropy);
decoderF.SetNonce(0);
status = decoderF.Instantiate(personal);
if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decoder instantiate error ({0}): {1}",
decoderV.GetStatusName(status),
decoderV.GetStatusDescription(status));
return (int)status;
}

// String to decode to.
string decoded;

// Create the corrupt version of message #2.
// Doing this to ensure decode fails
char first = encodings[2][0];
++first;
string corrupt =
encodings[2].Substring(1).Insert(0, new string(first, 1));

// Output that decoding is in forward-only sequencing mode
Console.WriteLine("\nForward-only mode (sequence window = 2):");

// Decode first message
// Output: Decode #1: mte_status_success, message 1
decoded = decoderF.DecodeStrB64(encodings[0], out status);
Console.WriteLine("Decode #1: {0}, {1}",
decoderF.GetStatusName(status),
decoded);

// Decode first message again -- out of sequence, should not work
// Output: Decode #1: mte_status_seq_outside_window,
decoded = decoderF.DecodeStrB64(encodings[0], out status);
Console.WriteLine("Decode #1: {0}, {1}",
decoderF.GetStatusName(status),
decoded);

// Decode corrupt message,
// Try to decode the corrupted second message -- should not work
// Output: Corrupt #3: mte_status_seq_mismatch,
decoded = decoderF.DecodeStrB64(corrupt, out status);
Console.WriteLine("Corrupt #3: {0}, {1}",
decoderF.GetStatusName(status),
decoded);

// Decode third message (within sequence window)
// Output: Decode #3: mte_status_success, message 3
decoded = decoderF.DecodeStrB64(encodings[2], out status);
Console.WriteLine("Decode #3: {0}, {1}",
decoderF.GetStatusName(status),
decoded);

// Decode non-corrupted second message
// (after already decoding third -- out of sequence)
// Output: Decode #2: mte_status_seq_outside_window,
decoded = decoderF.DecodeStrB64(encodings[1], out status);
Console.WriteLine("Decode #2: {0}, {1}",
decoderF.GetStatusName(status),
decoded);

// Decode third message again -- out of sequence, should not work
// Output: Decode #3: mte_status_seq_outside_window,
decoded = decoderF.DecodeStrB64(encodings[2], out status);
Console.WriteLine("Decode #3: {0}, {1}",
decoderF.GetStatusName(status),
decoded);

// Decode fourth message
// Output: Decode #4: mte_status_success, message 4
decoded = decoderF.DecodeStrB64(encodings[3], out status);
Console.WriteLine("Decode #4: {0}, {1}",
decoderF.GetStatusName(status),
decoded);

Async

In async mode, which is enabled by setting the sequence window to a negative number, the sequence number is checked before decoding and if it is ahead of the expected number and within the window, a catch-up algorithm is invoked to skip ahead to the current message, and the state is always rolled back to allow messages to be decoded out of order, as long as they are within the window. This is useful in any situation where out-of-order processing may occur (e.g., a web server handling async requests from a browser). The sequencing window continuously moves forward once all sequence numbers within the window have been seen or a sequence number is far enough behind that is assumed the packet was lost. For more information, please see the official MTE developer guides.

If the sequence number was outside the window, an error is returned before attempting to decode.

This mode requires that all messages are the same length, so MTE can know how to get back in sync. There are many ways to ensure this, including add-ons like Fixed-Length and Managed-Key Encryption, or the SDK user may have their own way of knowing the input is always the same length. The Fixed-Length Add-On always produces messages of the same length. The Managed-Key Encryption Add-On always produces fixed-length (for sequencing purposes) messages while at the same time allowing variable-length data.

The following sample will highlight how the verification-only sequencing mode works by decoding the input messages in the following order:

  • Message 1 – success
  • Message 1 – error -- repeat message
  • Corrupt Message 3 – error -- corrupted message
  • Message 3 – success (ahead of expected but within window)
  • Message 2 – success (behind expected but within window) Message 2 – error -- repeat message
  • Message 4 – success

Restore MTE state to show decoding in different order

  • Message 4 – success
  • Message 1 – error -- too far behind expected sequence
  • Message 3 – success
  • Message 2 – success
//For this sample sequence window is being set to -2
MteDec decoderA = new MteDec(0, -2);

// Instantiate the Decoder
decoderA.SetEntropy(entropy);
decoderA.SetNonce(0);
status = decoderA.Instantiate(personal);

if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decoder instantiate error ({0}): {1}",
decoderV.GetStatusName(status),
decoderV.GetStatusDescription(status));
return (int)status;
}

// Save the async Decoder state.
byte[] dsaved = decoderA.SaveState();

// String to decode to.
string decoded;

// Create the corrupt version of message #2.
// Doing this so we can intentionally fail
char first = encodings[2][0];
++first;
string corrupt =
encodings[2].Substring(1).Insert(0, new string(first, 1));

// Output that decoding is in Async sequencing mode
Console.WriteLine("\nAsync mode (sequence window = -2):");

// Decode the first message
// Output: Decode #1: mte_status_success, message 1
decoded = decoderA.DecodeStrB64(encodings[0], out status);
Console.WriteLine("Decode #0: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

// Try to decode the first message again -- out of sequence, should not work
// Output: Decode #0: mte_status_seq_outside_window,
decoded = decoderA.DecodeStrB64(encodings[0], out status);
Console.WriteLine("Decode #1: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

// Try to decode the corrupted second message -- should not work
// Output: Corrupt #3: mte_status_seq_mismatch,
decoded = decoderA.DecodeStrB64(corrupt, out status);
Console.WriteLine("Corrupt #3: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

// Decode third message
// Output: Decode #3: mte_status_success, message 3
decoded = decoderA.DecodeStrB64(encodings[2], out status);
Console.WriteLine("Decode #3: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

// Decode second message (async should work because we have NOT decoded yet)
// Output: Decode #2: mte_status_success, message 2
decoded = decoderA.DecodeStrB64(encodings[1], out status);
Console.WriteLine("Decode #2: {0}, {1}",
decoderA.GetStatusName(status),
decoded);


// Decode third message again (since after message 1 and 2 different error)
// Output: Decode #3: mte_status_seq_outside_window,
decoded = decoderA.DecodeStrB64(encodings[2], out status);
Console.WriteLine("Decode #3: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

// Decode fourth message
// Output: Decode #4: mte_status_success, message 4
decoded = decoderA.DecodeStrB64(encodings[3], out status);
Console.WriteLine("Decode #4: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

// Restore and decode again in a different order.
decoderA.RestoreState(dsaved);
Console.WriteLine("\nAsync mode (sequence window = -2):");

// Decode fourth message first
// Output: Decode #4: mte_status_success, message 4
decoded = decoderA.DecodeStrB64(encodings[3], out status);
Console.WriteLine("Decode #4: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

// Decode first message (error - sequence window too large)
// Output: Decode #1: mte_status_seq_outside_window,
decoded = decoderA.DecodeStrB64(encodings[0], out status);
Console.WriteLine("Decode #1: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

// Decode third message (inside sequence window)
// Output: Decode #3: mte_status_success, message 3
decoded = decoderA.DecodeStrB64(encodings[2], out status);
Console.WriteLine("Decode #3: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

// Decode non-corrupted second message (still inside sequence window)
// Output: Decode #2: mte_status_success, message 2
decoded = decoderA.DecodeStrB64(encodings[1], out status);
Console.WriteLine("Decode #2: {0}, {1}",
decoderA.GetStatusName(status),
decoded);

Full Sequencing Sample Project

Eclypses has developed full sample projects demonstrating using MTE sequencing.

Full C Sample

Full C++ Sample

Full C# Sample

Full Java Sample

Full Swift Sample

Full Objective C Sample

Full Python Sample

Full Go Sample