Skip to main content

MTE Managed Key Encryption Add-On Code Samples

Purpose

Samples expand on our "Examples" by providing longer snippets of code demonstrating the entire processes. The objective of an MTE Managed Key Encryption Add-On "Samples" is to provide full samples of code of how to use the MTE Managed Key Encryption Encoder Add-On and MTE Managed Key Encryption Decoder Add-On.

The Managed Key Encryption (MKE) Add-On replaces the core encoder and decoder, which only do tokenization, with an encoder and decoder that combine standard encryption with tokenization. This allows much larger data to take advantage of the MTE technology without significantly increasing the data size.

In this example an input message is being encoded and decoded within a single program but in actual implementations the encoder and decoder would be on separate endpoints. By having both the Encoder and Decoder within one application it allows for the simplest working demonstration for interacting with the MTE. For more information, please see the official MTE developer guides.

MTE Managed Key Encryption (MKE)

MTE MKE Encode and Decode

This sample simply prompts for input and other MKE settings then encodes and then decodes the input using the settings that were selected.

using System;
using System.Text;

namespace MTE {
class demoCsMke {
// The timestamp window and sequencing window are hard coded for this
// demo.
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;
MteCiphers cipher;
MteHashes hash;

// 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());

// Get the cipher.
Console.Write("Ciphers:");
for (int i = 1; i < baseObj.GetCiphersCount(); ++i) {
Console.Write(" {0}", baseObj.GetCiphersName((MteCiphers)i));
}
Console.WriteLine();
Console.Write("Enter the cipher> ");
cipher = baseObj.GetCiphersAlgo(Console.ReadLine());

// Get the hash.
Console.Write("Hashes:");
for (int i = 1; i < baseObj.GetHashesCount(); ++i) {
Console.Write(" {0}", baseObj.GetHashesName((MteHashes)i));
}
Console.WriteLine();
Console.Write("Enter the hash> ");
hash = baseObj.GetHashesAlgo(Console.ReadLine());
} else {
drbg = baseObj.GetDefaultDrbg();
tokBytes = baseObj.GetDefaultTokBytes();
verifiers = baseObj.GetDefaultVerifiers();
cipher = baseObj.GetDefaultCipher();
hash = baseObj.GetDefaultHash();
}

// 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 = baseObj.GetDrbgsEntropyMinBytes(drbg);
byte[] entropy = new byte[entropyBytes];

// Create the Encoder.
MteMkeEnc encoder = new MteMkeEnc(drbg,
tokBytes,
verifiers,
cipher,
hash);
encoder.SetEntropy(entropy);
encoder.SetNonce(0);
status = encoder.Instantiate(personal);
if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Encoder instantiate error ({0}): " +
encoder.GetStatusDescription(status),
encoder.GetStatusName(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.
MteMkeDec decoder = new MteMkeDec(drbg,
tokBytes,
verifiers,
cipher,
hash,
timestampWindow,
sequenceWindow);
decoder.SetEntropy(entropy);
decoder.SetNonce(0);
status = decoder.Instantiate(personal);
if (status != MteStatus.mte_status_success) {
Console.Error.WriteLine("Decoder instantiate error ({0}): " +
decoder.GetStatusDescription(status),
decoder.GetStatusName(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);

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

MTE MKE Encode Chunking

Here is a code sample of using the MKE Chunking methods to read in a file and encode the contents and write the contents to a different file.

Chunking mode of MKE is useful when you are securing a very large piece of data and don’t want to wait for the entire piece of data to be encoded before sending, or need to break up the data in order to send it. Chunking allows you to break a piece of data into smaller predetermined sized pieces and encode then systematically until the entire larger piece of data is encoded. For more information, please see the official MTE developer guides.

//-----------------------
// Set encoded file name
//-----------------------
string encodedFileName = "encodedText";

//-----------------------------------
// Create default MTE MKE and Status
//-----------------------------------
MteMkeEnc mkeEncoder = new MteMkeEnc();
MteStatus encoderStatus;

//------------------------------------------------------------------------
// Set identifier
// These values should 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 identifier = "demo";

string fPath = string.Empty;
//--------------------------------------------------
// Prompt for path till we have one and it is valid
//--------------------------------------------------
while (string.IsNullOrWhiteSpace(fPath) || !File.Exists(fPath))
{
//------------------------------------
// Prompting message for file to copy
//------------------------------------
Console.WriteLine("Please enter path to file\n");

fPath = Console.ReadLine();
//-------------------------------
// Check to make sure file exits
//-------------------------------
if (!File.Exists(fPath))
{
Console.WriteLine($"File at the path '{fPath}' does not exist");
}
}
//----------------------------------------
// Set the correct extension for the file
//----------------------------------------
encodedFileName = $"{encodedFileName}{Path.GetExtension(fPath)}";

//---------------------------------------------------------------------
// Check how long entropy we need, set default all 0's
// should be treated like encryption keys - this is just example
//---------------------------------------------------------------------
int entropyMinBytes = mkeEncoder.GetDrbgsEntropyMinBytes(mkeEncoder.GetDrbg());
string entropy = (entropyMinBytes > 0) ? new String('0', entropyMinBytes) : entropy;

//--------------------------------
// Set MKE values for the Encoder
//--------------------------------
mkeEncoder.SetEntropy(Encoding.UTF8.GetBytes(entropy));
mkeEncoder.SetNonce(0);

//-------------------------
// Initialize MKE Encoder
//-------------------------
encoderStatus = mkeEncoder.Instantiate(identifier);
if (encoderStatus != MteStatus.mte_status_success)
{
throw new ApplicationException($"Failed to initialize the MTE encoder engine. Status: " +
$"{mkeEncoder.GetStatusName(encoderStatus)} / {mkeEncoder.GetStatusDescription(encoderStatus)}");
}
//-----------------------------
// Initialize chunking session
//-----------------------------
encoderStatus = mkeEncoder.StartEncrypt();
if(encoderStatus != MteStatus.mte_status_success)
{
throw new Exception("Failed to start encode chunk. Status: "
+ mkeEncoder.GetStatusName(encoderStatus)+ " / "
+ mkeEncoder.GetStatusDescription(encoderStatus));
}
//-------------------------------------------------------
// Before we start we want to delete any files
// that are already there in order to create new ones
//-------------------------------------------------------
if (File.Exists(encodedFileName))
{
File.Delete(encodedFileName);
}
//------------------------------------
// Read file in and encode using MKE
//------------------------------------
using (FileStream stream = File.OpenRead(fPath))
using (FileStream writeStream = File.OpenWrite(encodedFileName))
{
BinaryReader reader = new BinaryReader(stream);
BinaryWriter writer = new BinaryWriter(writeStream);

//-----------------------------------
// Create a buffer to hold the bytes
//-----------------------------------
byte[] buffer = new Byte[1024];
int bytesRead;
//------------------------------------------
// While the read method returns bytes
// Keep writing them to the output stream
//------------------------------------------
while ((bytesRead = stream.Read(buffer, 0, 1024)) > 0)
{
//-------------------------------
// Encode the data in place
// encoded data put back in buffer
//-------------------------------
MteStatus chunkStatus = mkeEncoder.EncryptChunk(buffer, 0, bytesRead);
if(chunkStatus != MteStatus.mte_status_success)
{
throw new Exception("Failed to encode chunk. Status: "
+ mkeEncoder.GetStatusName(chunkStatus)+ " / "
+ mkeEncoder.GetStatusDescription(chunkStatus));
}
writeStream.Write(buffer, 0, bytesRead);
}
//-----------------------------
// Finish the chunking session
//-----------------------------
byte[] finalEncodedChunk = mkeEncoder.FinishEncrypt(out MteStatus finishStatus);
if(finishStatus != MteStatus.mte_status_success)
{
throw new Exception("Failed to finish encode chunk. Status: "
+ mkeEncoder.GetStatusName(finishStatus)+ " / "
+ mkeEncoder.GetStatusDescription(finishStatus));
}
//-----------------------------------
// Append the final data to the file
//-----------------------------------
writeStream.Write(finalEncodedChunk, 0, finalEncodedChunk.Length);
}

MTE MKE Decode Chunking

The decoding is slightly different than the encoding. Because each decoded chunk may not be the same size as the encoded chunk, the amount is returned instead of left in the same variable. Here is a code example of how to use the MKE Decode Chunking methods. This sample takes the contents of the file that was created above and decodes the text and saves it in a different file.

string encodedFileName = "encodedText";
string decodedFileName = "decodedText";

//-----------------------------------------
// Get fPath from prompt in encoded sample
//-----------------------------------------
encodedFileName = $"{encodedFileName}{Path.GetExtension(fPath)}";
decodedFileName = $"{decodedFileName}{Path.GetExtension(fPath)}";
//--------------------------------
// Create default MTE MKE Decoder
//--------------------------------
MteMkeDec mkeDecoder = new MteMkeDec();
//---------------------------------------------------------------------------
// Set identifier (must be same as encoder)
// These values should 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 identifier = "demo";
//---------------------------------------------------------------
// Check how long entropy we need, set default all 0's
// should be treated like encryption keys - this is just example
//---------------------------------------------------------------
int entropyMinBytes = mkeDecoder.GetDrbgsEntropyMinBytes(mkeDecoder.GetDrbg());
string entropy = (entropyMinBytes > 0) ? new String('0', entropyMinBytes) : entropy;

//---------------------------------
// Set MKE values for the Decoder
//---------------------------------
mkeDecoder.SetEntropy(Encoding.UTF8.GetBytes(entropy));
mkeDecoder.SetNonce(0);
//------------------------
// Initialize the Decoder
//------------------------
decoderStatus = mkeDecoder.Instantiate(identifier);
if (decoderStatus != MteStatus.mte_status_success)
{
throw new ApplicationException($"Failed to initialize the MTE decoder engine. "
+ $"Status: {mkeDecoder.GetStatusName(encoderStatus)} / "
+ $"{mkeDecoder.GetStatusDescription(encoderStatus)}");
}
//-----------------------------
// Initialize chunking session
//-----------------------------
MteStatus decoderStatus = mkeDecoder.StartDecrypt();
if(decoderStatus != MteStatus.mte_status_success)
{
throw new Exception("Failed to start decode chunk. Status: "
+ mkeDecoder.GetStatusName(decoderStatus)+ " / "
+ mkeDecoder.GetStatusDescription(decoderStatus));
}
//------------------------------------
// Read file in and decode using MKE
//------------------------------------
using (FileStream stream = File.OpenRead("encoded.txt"))
using (FileStream writeStream = File.OpenWrite("decoded.txt"))
{
BinaryReader reader = new BinaryReader(stream);
BinaryWriter writer = new BinaryWriter(writeStream);
//-----------------------------------
// Create a buffer to hold the bytes
//-----------------------------------
byte[] buffer = new Byte[1024];
int bytesRead;
//----------------------------------------
// While the read method returns bytes
// Keep writing them to the output stream
//----------------------------------------
while ((bytesRead = stream.Read(buffer, 0, 1024)) > 0)
{
//-------------------------------------------
// Ensure we are only decoding what was read
//-------------------------------------------
byte[] decodedData = new byte[0];
if (bytesRead == buffer.Length)
{
decodedData = _mkeDecoder.DecryptChunk(buffer);
}
else
{
//------------------------------------------
// Find out what the decoded length will be
//------------------------------------------
var cipherBlocks = _mkeDecoder.GetCiphersBlockBytes(_mkeDecoder.GetCipher());
int buffBytes = bytesRead - cipherBlocks;
//----------------------------------
// Allocate buffer for decoded data
//----------------------------------
decodedData = new byte[buffBytes];
int decryptError = _mkeDecoder.DecryptChunk(buffer, 0, bytesRead, decodedData, 0);
if (decryptError < 0)
{
throw new ApplicationException("Error decoding data.");
}
}
writeStream.Write(decodedData, 0, decodedData.Length);
}
//-----------------------------
// Finish the chunking session
//-----------------------------
byte[] finalDecodedChunk = mkeDecoder.FinishDecrypt(out MteStatus finishStatus);
if(finishStatus != MteStatus.mte_status_success)
{
throw new Exception("Failed to finish decode chunk. Status: "
+ mkeDecoder.GetStatusName(finishStatus)+ " / "
+ mkeDecoder.GetStatusDescription(finishStatus));
}
//-----------------------------------------------------------------------
// Check if there is additional bytes if not initialize empty byte array
//-----------------------------------------------------------------------
if(finalDecodedChunk.Length <=0) { finalDecodedChunk = new byte[0]; }
//------------------------------------
// Append the final data to the file
//------------------------------------
writeStream.Write(finalDecodedChunk, 0, finalDecodedChunk.Length);
}

Full Chunking Sample Project

Eclypses has developed full sample projects demonstrating chunking.

Full C Sample

Full C++ Sample

Full C# Sample

Full Java Sample

Full Python Sample

Full Go Sample