Skip to main content

MTE Callback Code Samples

Purpose

Samples expand on our "Examples" by providing longer snippets of code demonstrating entire processes. This code snippet demonstrates how to use the MTE Callback functions.

Callbacks are a great way to handle the nonce, entropy or timestamp settings if the program has to wait for something else to finish first. Callbacks also make sure that a function will not run before a task is completed.

In the sample below the entropy, nonce, and timestamp callbacks will prompt the user to manually enter the information on a console and read what it entered. This is for demonstration purposes to show the callbacks in use and should not be used in a real application. For more information, please see the official MTE developer guides.

Entropy, Nonce and Timestamp Callback

Here is an example of how to use the entropy, nonce and timestamp callbacks.

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace MTE {
class CallbackSample {

class Cbs : MteEntropyCallback, MteNonceCallback, MteTimestampCallback {
~Cbs() {
if (myEntropyHandle.IsAllocated) {
myEntropyHandle.Free();
}
}

// Callbacks that will get entropy, nonce, and timestamp from stdin.
// THIS IS NOT A SECURE WAY TO CAPTURE THESE ITEMS AND IS ONLY FOR
// DEMONSTRATION PURPOSES.
public MteStatus EntropyCallback(int minEntropy,
int minLength,
UInt64 maxLength,
byte[] entropyInput,
ref UInt64 eiBytes,
out IntPtr entropyLong) {
// Set the long entropy to null in case we don't need it.
entropyLong = IntPtr.Zero;

// Display a prompt.
Console.Write("Enter {0}-{1} bytes of entropy> ", minLength, maxLength);

// Get a line of input.
string entropyStdin = Console.ReadLine();
byte[] entropy8 = UTF8Encoding.UTF8.GetBytes(entropyStdin.ToString());

// If the input was less than the minimum required, we must return an
// error.
if (entropy8.Length < minLength) {
return MteStatus.mte_status_drbg_catastrophic;
}

// Set the actual entropy length. It cannot exceed the maximum required.
int buffBytes = (int)eiBytes;
eiBytes = Math.Min((UInt64)entropy8.Length, maxLength);

// If the length is greater than the length of the provided buffer, we
// have to create our own buffer instead.
if ((int)eiBytes > buffBytes) {
if (myEntropyHandle.IsAllocated) {
myEntropyHandle.Free();
}
myEntropyHandle = GCHandle.Alloc(entropy8, GCHandleType.Pinned);
entropyLong = myEntropyHandle.AddrOfPinnedObject();
} else {
// Copy the entropy to the buffer and we got it successfully.
Array.Copy(entropy8, entropyInput, (int)eiBytes);
}

// Success.
return MteStatus.mte_status_success;
}
public void NonceCallback(int minLength,
int maxLength,
byte[] nonce,
out int nBytes) {

// Display a prompt.
Console.Write("Enter the nonce (decimal digits only)> ");

// Get the nonce.
UInt64 u64 = Convert.ToUInt64(Console.ReadLine());

// Copy the nonce in little-endian format to the nonce buffer.
int nCopied = Math.Min(nonce.Length, sizeof(UInt64));
for (int i = 0; i < nCopied; ++i) {
nonce[i] = (byte)(u64 >> (i * 8));
}

// If the minimum length is greater than the size of the nonce we got,
// fill up to that length with zeros.
if (nCopied < minLength) {
for (int i = nCopied; i < minLength; ++i) {
nonce[i] = 0;
}
nBytes = minLength;
} else {
nBytes = nCopied;
}
}
public UInt64 TimestampCallback() {

// Display a prompt.
Console.Write("Enter the timestamp (decimal digits only)> ");

// Get the timestamp.
string timestampStr = Console.ReadLine();
return Convert.ToUInt64(timestampStr);
}
private GCHandle myEntropyHandle;
}

// The timestamp window and sequencing window
private const UInt64 timestampWindow = 1;
private const Int32 sequenceWindow = 0;

static int Main(string[] args) {
// Status.
MteStatus status = MteStatus.mte_status_success;

// Options.
MteDrbgs drbg;
int tokBytes;
MteVerifiers verifiers;

// 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;
}
}

// Get the input data.
Console.Write("Enter the data to encode> ");
string input = Console.ReadLine();

// Get the personalization string.
Console.Write("Enter the personalization> ");
string personal = Console.ReadLine();

// Set up the options to use the buildtime options if the library is built
// for that; otherwise prompt for the options.
if (baseObj.HasRuntimeOpts()) {
// Get the DRBG.
Console.Write("DRBGs:");
for (int i = 1; i < baseObj.GetDrbgsCount(); ++i) {
Console.Write(" {0}", baseObj.GetDrbgsName((MteDrbgs)i));
}
Console.WriteLine();
Console.Write("Enter the DRBG> ");
drbg = baseObj.GetDrbgsAlgo(Console.ReadLine());

// Get the token size.
Console.Write("Enter the token size in bytes> ");
tokBytes = Convert.ToInt32(Console.ReadLine());

// Get the verifiers.
Console.Write("Verifiers:");
for (int i = 0; i < baseObj.GetVerifiersCount(); ++i) {
Console.Write(" {0}", baseObj.GetVerifiersName((MteVerifiers)i));
}
Console.WriteLine();
Console.Write("Enter the verifiers> ");
verifiers = baseObj.GetVerifiersAlgo(Console.ReadLine());
} else {
drbg = baseObj.GetDefaultDrbg();
tokBytes = baseObj.GetDefaultTokBytes();
verifiers = baseObj.GetDefaultVerifiers();
}

// Create the callbacks to get entropy, nonce, and timestamp from stdin.
Cbs cbs = new Cbs();

// Create the Encoder.
MteEnc encoder = new MteEnc(drbg, tokBytes, verifiers);
encoder.SetEntropyCallback(cbs);
encoder.SetNonceCallback(cbs);
encoder.SetTimestampCallback(cbs);
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 input.
string encoded = encoder.EncodeB64(input, out status);
if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Encode error ({0}): {1}",
encoder.GetStatusName(status),
encoder.GetStatusDescription(status));
return (int)status;
}

// Display the encoded message.
Console.WriteLine("Base64 message: {0}", encoded);

// Create the Decoder.
MteDec decoder = new MteDec(drbg,
tokBytes,
verifiers,
timestampWindow,
sequenceWindow);
decoder.SetEntropyCallback(cbs);
decoder.SetNonceCallback(cbs);
decoder.SetTimestampCallback(cbs);
status = decoder.Instantiate(personal);
if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decoder instantiate error ({0}): {1}",
decoder.GetStatusName(status),
decoder.GetStatusDescription(status));
return (int)status;
}

// Decode the message.
string decoded = decoder.DecodeStrB64(encoded, out status);
if (decoder.StatusIsError(status)) {
Console.Error.WriteLine("Decode error ({0}): {1}",
decoder.GetStatusName(status),
decoder.GetStatusDescription(status));
return (int)status;
} else if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decode warning ({0}): {1}",
decoder.GetStatusName(status),
decoder.GetStatusDescription(status));
}

// Output the decoded data.
Console.WriteLine("Decoded data: {0}", decoded);

// Output decode info.
Console.WriteLine("Encode timestamp: {0}", decoder.GetEncTs());
Console.WriteLine("Decode timestamp: {0}", decoder.GetDecTs());
Console.WriteLine("Messages skipped: {0}", decoder.GetMsgSkipped());

// Compare the decoded data against the original data.
if (decoded == input) {
Console.WriteLine("The original data and decoded data match.");
} else {
Console.WriteLine("The original data and decoded data DO NOT match.");
return -1;
}

// Success.
return 0;
}
}
}