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.
- C
- C++
- CSharp
- Java
- Swift
- ObjC
- Python
- Go
static char ei_buff[1024 * 1024];
static mte_status ei_cb(void *context, mte_drbg_ei_info *info)
{
MTE_SIZE_T input_bytes;
(void)context;
/* Get the entropy. */
printf("Enter %u-%lu bytes of entropy> ",
(unsigned)info->min_length,
(unsigned long)info->max_length);
fflush(stdout);
(void)!fgets(ei_buff, sizeof(ei_buff), stdin);
input_bytes = (MTE_SIZE_T)(strlen(ei_buff) - 1);
/* If the entropy is less than the minimum required, we must return an
error. */
if (input_bytes < info->min_length)
{
return mte_status_drbg_catastrophic;
}
else if (input_bytes > info->bytes)
{
/* If the entropy is longer than the provided buffer, point at our buffer
instead. */
info->buff = (MTE_UINT8_T *)ei_buff;
}
else
{
/* Otherwise copy the entropy to the provided buffer. */
memcpy(info->buff, ei_buff, input_bytes);
}
/* Set the actual entropy length. */
info->bytes = input_bytes;
/* We got it successfully. */
return mte_status_success;
}
static void n_cb(void *context, mte_drbg_nonce_info *info)
{
MTE_SIZE8_T i;
MTE_UINT64_T u64;
char line[80];
(void)context;
/* Get the nonce. */
printf("Enter the nonce (decimal digits only)> ");
fflush(stdout);
(void)!fgets(line, sizeof(line), stdin);
u64 = strtoul(line, NULL, 10);
/* Copy the nonce in little-endian format to the nonce buffer. */
for (i = 0; i < info->max_length && i < sizeof(u64); ++i)
{
info->buff[i] = (MTE_UINT8_T)(u64 >> (i * 8));
}
/* If the minimum length is greater than the size of the nonce we got, fill
up to that length with zeros. */
for (; i < info->min_length; ++i)
{
info->buff[i] = 0;
}
/* Set the actual nonce length. */
info->bytes = i;
}
static MTE_UINT64_T t_cb(void *context)
{
char line[80];
(void)context;
/* Get the timestamp. */
printf("Enter the timestamp (decimal digits only)> ");
fflush(stdout);
(void)!fgets(line, sizeof(line), stdin);
return strtoul(line, NULL, 10);
}
Cbs::Cbs() : myEntropy(NULL) { }
Cbs::~Cbs()
{
delete [] myEntropy;
}
mte_status Cbs::entropyCallback(mte_drbg_ei_info& info)
{
// Display a prompt.
std::cout << "Enter "
<< static_cast<size_t>(info.min_length) << '-' << info.max_length
<< " bytes of entropy> " << std::flush;
// Get a line of input.
std::string line;
std::cin >> line;
// If the input was less than the minimum required, we must return an error.
if (line.size() < info.min_length)
{
return mte_status_drbg_catastrophic;
}
// Set the actual entropy length. It cannot exceed the maximum required.
size_t buffBytes = info.bytes;
info.bytes = std::min(static_cast<MTE_SIZE_T>(line.size()), info.max_length);
// If the length is greater than the length of the provided buffer, we have
// to create our own buffer instead.
if (info.bytes > buffBytes)
{
delete [] myEntropy;
myEntropy = new uint8_t[info.bytes];
info.buff = myEntropy;
}
// Copy the entropy to the buffer and we got it successfully.
memcpy(info.buff, line.data(), info.bytes);
return mte_status_success;
}
void Cbs::nonceCallback(mte_drbg_nonce_info& info)
{
// Display a prompt.
std::cout << "Enter the nonce (decimal digits only)> " << std::flush;
// Get the nonce and ignore the rest of the line.
MTE_UINT64_T u64;
std::cin >> u64;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Copy the nonce in little-endian format to the nonce buffer.
size_t i;
for (i = 0; i < info.max_length && i < sizeof(u64); ++i)
{
info.buff[i] = static_cast<MTE_UINT8_T>(u64 >> (i * 8));
}
// If the minimum length is greater than the size of the nonce we got, fill
// up to that length with zeros.
for (; i < info.min_length; ++i)
{
info.buff[i] = 0;
}
// Set the actual nonce length.
info.bytes = static_cast<MTE_SIZE8_T>(i);
}
MTE_UINT64_T Cbs::timestampCallback()
{
// Display a prompt.
std::cout << "Enter the timestamp (decimal digits only)> " << std::flush;
// Get the timestamp and ignore the rest of the line.
MTE_UINT64_T u64;
std::cin >> u64;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return u64;
}
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;
}
}
}
import com.eclypses.mte.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class demoJavaCore
{
// 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.
static class Cbs implements MteBase.EntropyCallback,
MteBase.NonceCallback,
MteBase.TimestampCallback
{
public Cbs(BufferedReader br)
{
myBr = br;
}
public MteBase.EntropyCallback.BuffStatus entropyCallback(int minEntropy,
int minLength,
long maxLength)
{
// Display a prompt.
System.out.print("Enter " + minLength + "-" + maxLength +
" bytes of entropy> ");
// Get a line of input.
byte[] entropy8 = new byte[0];
try
{
entropy8 = myBr.readLine().getBytes(StandardCharsets.UTF_8);
}
catch (IOException ignored)
{ }
// If the input was less than the minimum required, we must return an
// error.
if (entropy8.length < minLength)
{
myBuffStatus.buff = null;
myBuffStatus.status = MteStatus.mte_status_drbg_catastrophic;
return myBuffStatus;
}
// Set the actual entropy length. It cannot exceed the maximum required.
int eiBytes = (int)Math.min(entropy8.length, maxLength);
// Create a direct buffer with the contents.
myBuffStatus.buff = ByteBuffer.allocateDirect(eiBytes);
myBuffStatus.buff.put(entropy8, 0, eiBytes);
// Success.
myBuffStatus.status = MteStatus.mte_status_success;
return myBuffStatus;
}
public int nonceCallback(int minLength, int maxLength, ByteBuffer nonce)
{
// Display a prompt.
System.out.print("Enter the nonce (decimal digits only)> ");
// Get the nonce.
long u64 = 0;
try
{
u64 = Long.parseLong(myBr.readLine());
}
catch (IOException ignored)
{ }
// Copy the nonce in little-endian format to the nonce buffer.
int nCopied = Math.min(nonce.capacity(), Long.BYTES);
for (int i = 0; i < nCopied; ++i)
{
nonce.put((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.put((byte)0);
}
return minLength;
}
// Otherwise return the amount copied.
return nCopied;
}
public long timestampCallback()
{
// Display a prompt.
System.out.print("Enter the timestamp (decimal digits only)> ");
// Get the timestamp.
long ts = 0;
try
{
ts = Long.parseLong(myBr.readLine());
}
catch (IOException ignored)
{ }
return ts;
}
BufferedReader myBr;
MteBase.EntropyCallback.BuffStatus myBuffStatus =
new MteBase.EntropyCallback.BuffStatus();
}
// The timestamp window and sequencing window are hard coded for this demo.
private static final long timestampWindow = 1;
private static final int sequenceWindow = 0;
public static void main(String[] args) throws IOException
{
// Status.
MteStatus status;
// 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.
if (!MteBase.initLicense("YOUR_COMPANY", "YOUR_LICENSE"))
{
String company = System.getenv("MTE_COMPANY");
String license = System.getenv("MTE_LICENSE");
if (company == null || license == null ||
!MteBase.initLicense(company, license))
{
status = MteStatus.mte_status_license_error;
System.err.println("Encode error (" +
MteBase.getStatusName(status) + "): " +
MteBase.getStatusDescription(status));
System.exit(status.getValue());
}
}
// Buffered input.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// Get the input data.
System.out.print("Enter the data to encode> ");
String input = br.readLine();
// Get the personalization string.
System.out.print("Enter the personalization> ");
String personal = br.readLine();
// Set up the options to use the buildtime options if the library is built
// for that; otherwise prompt for the options.
if (MteBase.hasRuntimeOpts())
{
// Get the DRBG.
System.out.print("DRBGs:");
for (int i = 1; i < MteBase.getDrbgsCount(); ++i)
{
System.out.print(" " + MteBase.getDrbgsName(MteDrbgs.valueOf(i)));
}
System.out.println();
System.out.print("Enter the DRBG> ");
drbg = MteBase.getDrbgsAlgo(br.readLine());
// Get the token size.
System.out.print("Enter the token size in bytes> ");
tokBytes = Integer.parseInt(br.readLine());
// Get the verifiers.
System.out.print("Verifiers:");
for (int i = 0; i < MteBase.getVerifiersCount(); ++i)
{
System.out.print(" " +
MteBase.getVerifiersName(MteVerifiers.valueOf(i)));
}
System.out.println();
System.out.print("Enter the verifiers> ");
verifiers = MteBase.getVerifiersAlgo(br.readLine());
} else {
drbg = MteBase.getDefaultDrbg();
tokBytes = MteBase.getDefaultTokBytes();
verifiers = MteBase.getDefaultVerifiers();
}
// Create the callbacks to get entropy, nonce, and timestamp from stdin.
Cbs cbs = new Cbs(br);
// 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)
{
System.err.println("Encoder instantiate error (" +
MteBase.getStatusName(status) + "): " +
MteBase.getStatusDescription(status));
System.exit(status.getValue());
}
// Encode the input.
MteBase.StrStatus encoded = encoder.encodeB64(input);
if (encoded.status != MteStatus.mte_status_success)
{
System.err.println("Encode error (" +
MteBase.getStatusName(encoded.status) + "): " +
MteBase.getStatusDescription(encoded.status));
System.exit(encoded.status.getValue());
}
// Display the encoded message.
System.out.println("Base64 message: " + encoded.str);
// 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)
{
System.err.println("Decoder instantiate error (" +
MteBase.getStatusName(status) + "): " +
MteBase.getStatusDescription(status));
System.exit(status.getValue());
}
// Decode the message.
MteBase.StrStatus decoded = decoder.decodeStrB64(encoded.str);
if (MteBase.statusIsError(decoded.status))
{
System.err.println("Decode error (" +
MteBase.getStatusName(decoded.status) + "): " +
MteBase.getStatusDescription(decoded.status));
System.exit(decoded.status.getValue());
}
else if (decoded.status != MteStatus.mte_status_success)
{
System.err.println("Decode warning (" +
MteBase.getStatusName(decoded.status) + "): " +
MteBase.getStatusDescription(decoded.status));
}
// Output the decoded data.
System.out.println("Decoded data: " + decoded.str);
// Output decode info.
System.out.println("Encode timestamp: " + decoder.getEncTs());
System.out.println("Decode timestamp: " + decoder.getDecTs());
System.out.println("Messages skipped: " + decoder.getMsgSkipped());
// Compare the decoded data against the original data.
if (decoded.str.equals(input))
{
System.out.println("The original data and decoded data match.");
}
else
{
System.out.println("The original data and decoded data DO NOT match.");
System.exit(-1);
}
// Success.
System.exit(0);
}
}
class Cbs: MteEntropyCallback, MteNonceCallback, MteTimestampCallback {
func entropyCallback(_ minEntropy: Int,
_ minLength: Int,
_ maxLength: UInt64,
_ entropyInput: inout [UInt8],
_ eiBytes: inout UInt64,
_ entropyLong: inout UnsafeMutableRawPointer?) -> mte_status {
// Display a prompt.
print("Enter \(minLength)-\(maxLength) bytes of entropy> ", terminator: "")
// Get a line of input.
let line = readLine()!
// If the input was less than the minimum required, we must return an error.
if line.utf8.count < minLength {
return mte_status_drbg_catastrophic
}
// Set the actual entropy length. It cannot exceed the maximum required.
let buffBytes = eiBytes
eiBytes = min(UInt64(line.utf8.count), maxLength)
// If the length is greater than the length of the provided buffer, we have
// to create our own buffer instead.
if eiBytes > buffBytes {
// Get the entropy input as an array.
let ei = [UInt8](line.utf8)
// If there is previous raw entropy, deallocate it.
if myEntropyRaw != nil {
myEntropyRaw!.deallocate()
}
// Allocate unsafe memory for the entropy.
myEntropyRaw =
UnsafeMutableRawPointer.allocate(byteCount: ei.count, alignment: 16)
// Copy from the entropy array to the unsafe memory.
ei.withUnsafeBytes { buff in
let raw = myEntropyRaw!.assumingMemoryBound(to: UInt8.self)
let ei = buff.bindMemory(to: UInt8.self)
raw.assign(from: ei.baseAddress!, count: ei.count)
}
// Set the raw pointer to point at the unsafe memory.
entropyLong = myEntropyRaw
}
else {
// Copy the entropy to the buffer.
entropyInput.replaceSubrange(Range(uncheckedBounds: (0, Int(eiBytes))),
with: line.utf8.prefix(Int(eiBytes)))
}
// Success.
return mte_status_success
}
func nonceCallback(_ minLength: Int,
_ maxLength: Int,
_ nonce: inout [UInt8],
_ nBytes: inout Int) {
// Display a prompt.
print("Enter the nonce (decimal digits only)> ", terminator: "")
// Get the nonce and ignore the rest of the line.
let u64 = UInt64(readLine()!)!
// Copy the nonce in little-endian format to the nonce buffer.
let nCopied = min(nonce.count, MemoryLayout.size(ofValue: u64))
for i in 0..<nCopied {
nonce[i] = UInt8(UInt64(u64 >> (i * 8)) & 0xFF)
}
// 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 i in nCopied..<minLength {
nonce[i] = 0
}
nBytes = minLength
}
else {
nBytes = nCopied
}
}
func timestampCallback() -> UInt64 {
// Display a prompt.
print("Enter the timestamp (decimal digits only)> ", terminator: "")
// Get the timestamp and ignore the rest of the line.
return UInt64(readLine()!)!
}
private var myEntropyRaw: UnsafeMutableRawPointer? = nil
}
//MARK: Callbacks
// In Objective-C, callbacks use delegates. See the Full Code Sample below for more information.
// The entropy callback allows the entropy to be created just before being consumed
// which limits the entropy variable lifecycle to the shortest time possible.
-(mte_status)entropyCallback:(mte_drbg_ei_info *)info {
NSError *error;
switch(_pairType) {
case ENC: {
@autoreleasepool {
puts("\nCalling to get Encoder Entropy");
NSString *name = @"ENC";
EcdhHelper *ecdhHelper = [[EcdhHelper alloc] initWithName:name error:&error];
if (error) {
NSLog(@"Error creating ecdhHelper: %@", error);
}
NSString *publicKey = [ecdhHelper getPublicKeyAndReturnError:&error];
if (error) {
NSLog(@"Error creating device public key: %@", error);
}
// Create NSMutableURLRequest as required. See full sample below for more information.
// Pausing to wait for response from server. Perhaps not the best way to handle this
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (error) {
NSLog(@"Error parsing JSON: %@", error);
} else {
static char eiBuff[32];
size_t inputBytes;
NSDictionary *jsonDictionary = (NSDictionary *)jsonObject;
// Assign encoderNonce to local variable where it will be accessible to the nonceCallback.
self->_tempEncoderNonce = (uint64)[[jsonDictionary valueForKey:@"timestamp"] integerValue];
NSArray<NSNumber *> *tempEntropy = [ecdhHelper createSharedSecretWithRemotePublicKeyStr:[jsonDictionary objectForKey:@"publicKey"] error:&error];
inputBytes = (unsigned long)tempEntropy.count;
// Fill the buffer
for (int i=0; i<[tempEntropy count]; i++) {
NSInteger value = [[tempEntropy objectAtIndex:i] integerValue];
eiBuff[i] = value;
}
// Check the length
if (inputBytes < info->min_length)
{
puts("Encoder Entropy too short");
}
else
{
/* Point at our buffer. */
info->buff = (MTE_UINT8_T *)eiBuff;
}
/* Set the actual entropy length. */
info->bytes = (MTE_SIZE_T)inputBytes;
dispatch_semaphore_signal(sema);
}
}];
[task resume];
if (![NSThread isMainThread]) {
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
} else {
while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW)) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0]];
}
}
break;
}
}
case DEC: {
@autoreleasepool {
puts("\nCalling to get Decoder Entropy");
NSString *name = @"DEC";
EcdhHelper *ecdhHelper = [[EcdhHelper alloc] initWithName:name error:&error];
if (error) {
NSLog(@"Error instantiating ecdhHelper: %@", error);
}
NSString *publicKey = [ecdhHelper getPublicKeyAndReturnError:&error];
if (error) {
NSLog(@"Error creating device public key: %@", error);
}
// Create NSMutableURLRequest as required. See full sample below for more information.
// Pausing to wait for response from server. Perhaps not the best way to handle this
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
// Pausing to wait for response from server. Perhaps not the best way to handle this
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (error) {
NSLog(@"Error parsing JSON: %@", error);
} else {
static char eiBuff[32];
size_t inputBytes;
NSDictionary *jsonDictionary = (NSDictionary *)jsonObject;
// Assign decoderNonce to local variable where it will be accessible to the nonceCallback.
self->_tempDecoderNonce = (uint64)[[jsonDictionary valueForKey:@"timestamp"] integerValue];
NSArray<NSNumber *> *tempEntropy = [ecdhHelper createSharedSecretWithRemotePublicKeyStr:[jsonDictionary objectForKey:@"publicKey"] error:&error];
inputBytes = (unsigned long)tempEntropy.count;
for (int i=0; i<[tempEntropy count]; i++) {
NSInteger value = [[tempEntropy objectAtIndex:i] integerValue];
eiBuff[i] = value;
}
if (inputBytes < info->min_length)
{
NSLog(@"Decoder Entropy too short");
}
else
{
/* Point at our buffer. */
info->buff = (MTE_UINT8_T *)eiBuff;
}
/* Set the actual entropy length. */
info->bytes = (MTE_SIZE_T)inputBytes;
dispatch_semaphore_signal(sema);
}
}];
[task resume];
if (![NSThread isMainThread]) {
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
} else {
while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW)) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0]];
}
}
break;
}
}
}
return mte_status_success;
}
-(void)nonceCallback:(mte_drbg_nonce_info *)info {
size_t i;
switch(_pairType) {
case ENC: {
puts("Entered Encoder NonceCallback");
// Copy the tempEncoderNonce in little-endian format to the nonce buffer.
for (i = 0; i < info->max_length && i < sizeof(_tempEncoderNonce); ++i)
{
info->buff[i] = (MTE_UINT8_T)(_tempEncoderNonce >> (i * 8));
}
break;
}
case DEC: {
puts("Entered Decoder NonceCallback");
// Copy the tempDecoderNonce in little-endian format to the nonce buffer.
for (i = 0; i < info->max_length && i < sizeof(_tempDecoderNonce); ++i)
{
info->buff[i] = (MTE_UINT8_T)(_tempDecoderNonce >> (i * 8));
}
break;
}
}
// If the minimum length is greater than the size of the nonce we got, fill
// up to that length with zeros.
for (; i < info->min_length; ++i)
{
info->buff[i] = 0;
}
// Set the actual nonce length.
info->bytes = (MTE_SIZE8_T)i;
}
- (uint64_t)timestampCallback {
puts("We have entered timestamp callback");
uint64_t timestamp = (uint64_t)[[NSDate date] timeIntervalSince1970];
return timestamp;
}
See PEP 585 for the new implementation of the typing module in python 3.9+
See PEP 563 for the back ported typing module in python 3.x - 3.8
from MteDrbgs import MteDrbgs
from MteVerifiers import MteVerifiers
from MteStatus import MteStatus
from MteBase import MteBase
from MteBase import MteEntropyCallback, MteNonceCallback, MteTimestampCallback
from MteEnc import MteEnc
from MteDec import MteDec
from typing import List
import os
import sys
# 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.
class Cbs(MteEntropyCallback, MteNonceCallback, MteTimestampCallback):
def entropy_callback(self,
min_entropy: int,
min_length: int,
max_length: int,
entropy_input: List[bytearray],
ei_bytes: List[int]) -> MteStatus:
# Display a prompt. Get a line of input.
line = input(f"Enter {min_length}-{max_length} bytes of entropy> ")
line = line.encode()
# If the input was less than the minimum required, we must return an error.
if len(line) < min_length:
return MteStatus.mte_status_drbg_catastrophic
# Set the actual entropy length. It cannot exceed the maximum required.
buff_bytes = ei_bytes[0]
ei_bytes[0] = min(len(line), max_length)
# If the length is greater than the length of the provided buffer, we have
# to create our own buffer instead.
if ei_bytes[0] > buff_bytes:
entropy_input[0] = bytearray(ei_bytes[0])
# Copy the entropy to the buffer and we got it successfully.
for i in range(0, ei_bytes[0]):
entropy_input[0][i] = line[i]
return MteStatus.mte_status_success
def nonce_callback(self,
min_length: int,
max_length: int,
nonce: bytearray,
n_bytes: List[int]) -> None:
# Display a prompt. Get the nonce.
u64 = input("Enter the nonce (decimal digits only)> ")
u64 = int(u64)
# Copy the nonce in little-endian format to the nonce buffer.
for i in range(0, min(8, max_length)):
nonce[i] = (u64 >> (i * 8)) & 0xff
# If the minimum length is greater than the size of the nonce we got, fill
# up to that length with zeros. The buffer is already zeroed, so just set
# the length.
n_bytes[0] = max(i + 1, min_length)
def timestamp_callback(self) -> int:
# Display a prompt. Get the timestamp.
u64 = input("Enter the timestamp (decimal digits only)> ")
return int(u64)
# The timestamp window and sequencing window are hard coded for this demo.
timestamp_window = 1
sequence_window = 0
def main():
# 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.
if not MteBase.init_license("YOUR_COMPANY", "YOUR_LICENSE"):
company = os.getenv("MTE_COMPANY")
license = os.getenv("MTE_LICENSE")
if company is None or \
license is None or \
not MteBase.init_license(company, license):
print("License init error ({0}): {1}".format(
MteBase.get_status_name(MteStatus.mte_status_license_error),
MteBase.get_status_description(MteStatus.mte_status_license_error)),
file=sys.stderr)
return MteStatus.mte_status_license_error.value
# Get the input data.
input_ = input("Enter the data to encode> ")
# Get the personalization string.
personal = input("Enter the personalization> ")
# Set up the options to use the buildtime options if the library is built
# for that; otherwise prompt for the options.
if MteBase.has_buildtime_opts():
drbg = MteBase.get_buildtime_drbg()
tok_bytes = MteBase.get_buildtime_tok_bytes()
verifiers = MteBase.get_buildtime_verifiers()
else:
# Get the DRBG.
print("DRBGs:", end="")
for i in range(1, MteBase.get_drbgs_count()):
print(" {0}".format(MteBase.get_drbgs_name(MteDrbgs(i))), end="")
print("")
drbg = input("Enter the DRBG> ")
drbg = MteBase.get_drbgs_algo(drbg)
# Get the token size.
tok_bytes = input("Enter the token size in bytes> ")
tok_bytes = int(tok_bytes)
# Get the verifiers.
print("Verifiers:", end="")
for i in range(0, MteBase.get_verifiers_count()):
print(" {0}".format(MteBase.get_verifiers_name(MteVerifiers(i))), end="")
print("")
verifiers = input("Enter the verifiers> ")
verifiers = MteBase.get_verifiers_algo(verifiers)
# Create the callbacks to get entropy, nonce, and timestamp from stdin.
cbs = Cbs()
# Create the Encoder.
encoder = MteEnc(drbg, tok_bytes, verifiers)
encoder.set_entropy_callback(cbs)
encoder.set_nonce_callback(cbs)
encoder.set_timestamp_callback(cbs)
status = encoder.instantiate(personal)
if status != MteStatus.mte_status_success:
print("Encoder instantiate error ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
return status.value
# Save the Encoder state.
esaved = encoder.save_state_b64()
if esaved == "":
print("Encoder state save error.", file=sys.stderr)
return MteStatus.mte_status_unsupported.value
# Encode the input.
(encoded, status) = encoder.encode_b64(input_)
if status != MteStatus.mte_status_success:
print("Encode error ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
return status.value
# Display the encoded message.
print(f"Base64 message: {encoded}")
# Create the Decoder.
decoder = MteDec(drbg,
tok_bytes,
verifiers,
timestamp_window,
sequence_window)
decoder.set_entropy_callback(cbs)
decoder.set_nonce_callback(cbs)
decoder.set_timestamp_callback(cbs)
status = decoder.instantiate(personal)
if status != MteStatus.mte_status_success:
print("Decoder instantiate error ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
return status.value
# Save the Decoder state.
dsaved = decoder.save_state_b64()
if dsaved == "":
print("Decoder state save error.", file=sys.stderr)
return MteStatus.mte_status_unsupported.value
# Decode the message.
(decoded, status) = decoder.decode_str_b64(encoded)
if MteBase.status_is_error(status):
print("Decode error ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
return status.value
elif status != MteStatus.mte_status_success:
print("Decode warning ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
# Output the decoded data.
print(f"Decoded data: {decoded}")
# Output decode info.
print(f"Encode timestamp: {decoder.get_enc_ts()}")
print(f"Decode timestamp: {decoder.get_dec_ts()}")
print(f"Messages skipped: {decoder.get_msg_skipped()}")
# Compare the decoded data against the original data.
if decoded == input_:
print("The original data and decoded data match.")
else:
print("The original data and decoded data DO NOT match.")
return -1
# Restore the Encoder and Decoder state.
status = encoder.restore_state_b64(esaved)
if status != MteStatus.mte_status_success:
print("Encoder state restore error ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
return status.value
status = decoder.restore_state_b64(dsaved)
if status != MteStatus.mte_status_success:
print("Decoder state restore error ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
return status.value
# Encode the input.
(encoded, status) = encoder.encode_b64(input_)
if status != MteStatus.mte_status_success:
print("Encode error ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
return status.value
# Display the encoded message.
print(f"Base64 message: {encoded}")
# Decode the message.
(decoded, status) = decoder.decode_str_b64(encoded)
if MteBase.status_is_error(status):
print("Decode error ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
return status.value
elif status != MteStatus.mte_status_success:
print("Decode warning ({0}): {1}".format(
MteBase.get_status_name(status),
MteBase.get_status_description(status)),
file=sys.stderr)
# Output the decoded data.
print(f"Decoded data: {decoded}")
# Output decode info.
print(f"Encode timestamp: {decoder.get_enc_ts()}")
print(f"Decode timestamp: {decoder.get_dec_ts()}")
print(f"Messages skipped: {decoder.get_msg_skipped()}")
# Compare the decoded data against the original data.
if decoded == input_:
print("The original data and decoded data match.")
else:
print("The original data and decoded data DO NOT match.")
return -1
# Success.
return 0
package main
import (
"bufio"
"fmt"
"os"
"goCore/mte"
)
// 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.
type Cbs struct {
}
func (cbs *Cbs) EntropyCallback(minEntropy int,
minLength int,
maxLength uint64) (eiLong []byte, eiBytes uint64, status mte.Status) {
// Display a prompt.
fmt.Printf("Enter %v-%v bytes of entropy> ", minLength, maxLength)
// Get a line of input.
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
entropyStdin := scanner.Text()
entropy8 := []byte(entropyStdin)
// If the input was less than the minimum required, we must return an error.
if len(entropy8) < minLength {
return nil, 0, mte.Status_mte_status_drbg_catastrophic
}
// Set the actual entropy length. It cannot exceed the maximum required.
if uint64(len(entropy8)) < maxLength {
eiBytes = uint64(len(entropy8))
} else {
eiBytes = maxLength
}
// Point at our buffer.
eiLong = entropy8
// Success.
status = mte.Status_mte_status_success
return
}
func (cbs *Cbs) NonceCallback(minLength int,
maxLength int,
nonce []byte,
nBytes *int) {
// Display a prompt.
fmt.Print("Enter the nonce (decimal digits only)> ")
// Get the nonce.
var u64 uint64
fmt.Scan(&u64)
// Copy the nonce in little-endian format to the nonce buffer.
nCopied := 8
if len(nonce) < nCopied {
nCopied = len(nonce)
}
for i := 0; i < nCopied; i++ {
nonce[i] = byte((u64 >> (i * 8)) & 0xff)
}
// 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 i := nCopied; i < minLength; i++ {
nonce[i] = 0
}
*nBytes = minLength
} else {
*nBytes = nCopied
}
}
func (cbs *Cbs) TimestampCallback() uint64 {
// Display a prompt.
fmt.Print("Enter the timestamp (decimal digits only)> ")
// Get the timestamp.
var u64 uint64
fmt.Scan(&u64)
return u64
}
// The timestamp window and sequencing window are hard coded for this demo.
const (
timestampWindow = 1
sequenceWindow = 0
)
func doMain() int {
// Status.
var status mte.Status
// Options.
var drbg mte.Drbgs
var tokBytes int
var verifiers mte.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.
if !mte.InitLicense("YOUR_COMPANY", "YOUR_LICENSE") {
company := os.Getenv("MTE_COMPANY")
license := os.Getenv("MTE_LICENSE")
if len(company) == 0 || len(license) == 0 ||
!mte.InitLicense(company, license) {
fmt.Fprintf(os.Stderr, "License init error (%v): %v\n",
mte.GetStatusName(mte.Status_mte_status_license_error),
mte.GetStatusDescription(mte.Status_mte_status_license_error))
return int(mte.Status_mte_status_license_error)
}
}
// Scanner input.
scanner := bufio.NewScanner(os.Stdin)
// Get the input data.
fmt.Print("Enter the data to encode> ")
scanner.Scan()
input := scanner.Text()
// Get the personalization string.
fmt.Print("Enter the personalization> ")
scanner.Scan()
personal := scanner.Text()
// Set up the options to use the buildtime options if the library is built
// for that; otherwise prompt for the options.
if mte.HasRuntimeOpts() {
// Get the DRBG.
fmt.Print("DRBGs:")
for i := 1; i < mte.GetDrbgsCount(); i++ {
fmt.Printf(" %v", mte.GetDrbgsName(mte.Drbgs(i)))
}
fmt.Print("\nEnter the DRBG> ")
scanner.Scan()
drbg = mte.GetDrbgsAlgo(scanner.Text())
// Get the token size.
fmt.Print("Enter the token size in bytes> ")
fmt.Scan(&tokBytes)
// Get the verifiers.
fmt.Print("Verifiers:")
for i := 0; i < mte.GetVerifiersCount(); i++ {
fmt.Printf(" %v", mte.GetVerifiersName(mte.Verifiers(i)))
}
fmt.Printf("\nEnter the verifiers> ")
scanner.Scan()
verifiers = mte.GetVerifiersAlgo(scanner.Text())
} else {
drbg = mte.GetDefaultDrbg()
tokBytes = mte.GetDefaultTokBytes()
verifiers = mte.GetDefaultVerifiers()
}
// Create the callbacks to get entropy, nonce, and timestamp from stdin.
cbs := &Cbs{}
// Create the Encoder.
encoder := mte.NewEncOpt(drbg, tokBytes, verifiers)
defer encoder.Destroy()
encoder.SetEntropyCallback(cbs)
encoder.SetNonceCallback(cbs)
encoder.SetTimestampCallback(cbs)
status = encoder.InstantiateStr(personal)
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)
}
// Save the Encoder state.
esaved := encoder.SaveStateB64()
if esaved == "" {
fmt.Fprintf(os.Stderr, "Encoder state save error.\n")
return int(mte.Status_mte_status_unsupported)
}
// Encode the input.
encoded, status := encoder.EncodeStrB64(input)
if status != mte.Status_mte_status_success {
fmt.Fprintf(os.Stderr, "Encode error (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
return int(status)
}
// Display the message.
fmt.Printf("Base64 message: %v\n", encoded)
// Create the Decoder.
decoder := mte.NewDecOpt(drbg,
tokBytes,
verifiers,
timestampWindow,
sequenceWindow)
defer decoder.Destroy()
decoder.SetEntropyCallback(cbs)
decoder.SetNonceCallback(cbs)
decoder.SetTimestampCallback(cbs)
status = decoder.InstantiateStr(personal)
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)
}
// Save the Decoder state.
dsaved := decoder.SaveStateB64()
if dsaved == "" {
fmt.Fprintf(os.Stderr, "Decoder state save error.\n")
return int(mte.Status_mte_status_unsupported)
}
// Decode the message.
decoded, status := decoder.DecodeStrB64(encoded)
if mte.StatusIsError(status) {
fmt.Fprintf(os.Stderr, "Decode error (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
return int(status)
} else if status != mte.Status_mte_status_success {
fmt.Fprintf(os.Stderr, "Decode warning (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
}
// Output the decoded data.
fmt.Printf("Decoded data: %v\n", decoded)
// Output decode info.
fmt.Printf("Encode timestamp: %v\n", decoder.GetEncTs())
fmt.Printf("Decode timestamp: %v\n", decoder.GetDecTs())
fmt.Printf("Messages skipped: %v\n", decoder.GetMsgSkipped())
// Compare the decoded data against the original data.
if decoded == input {
fmt.Println("The original data and decoded data match.")
} else {
fmt.Println("The original data and decoded data DO NOT match.")
return -1
}
// Restore the Encoder and Decoder state.
status = encoder.RestoreStateB64(esaved)
if status != mte.Status_mte_status_success {
fmt.Fprintf(os.Stderr, "Encoder state restore error (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
return int(status)
}
status = decoder.RestoreStateB64(dsaved)
if status != mte.Status_mte_status_success {
fmt.Fprintf(os.Stderr, "Decoder state restore error (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
return int(status)
}
// Encode the input.
encoded, status = encoder.EncodeStrB64(input)
if status != mte.Status_mte_status_success {
fmt.Fprintf(os.Stderr, "Encode error (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
return int(status)
}
// Display the message.
fmt.Printf("Base64 message: %v\n", encoded)
// Decode the message.
decoded, status = decoder.DecodeStrB64(encoded)
if mte.StatusIsError(status) {
fmt.Fprintf(os.Stderr, "Decode error (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
return int(status)
} else if status != mte.Status_mte_status_success {
fmt.Fprintf(os.Stderr, "Decode warning (%v): %v\n",
mte.GetStatusName(status), mte.GetStatusDescription(status))
}
// Output the decoded data.
fmt.Printf("Decoded data: %v\n", decoded)
// Output decode info.
fmt.Printf("Encode timestamp: %v\n", decoder.GetEncTs())
fmt.Printf("Decode timestamp: %v\n", decoder.GetDecTs())
fmt.Printf("Messages skipped: %v\n", decoder.GetMsgSkipped())
// Compare the decoded data against the original data.
if decoded == input {
fmt.Println("The original data and decoded data match.")
} else {
fmt.Println("The original data and decoded data DO NOT match.")
return -1
}
// Success.
return 0
}
func main() {
os.Exit(doMain())
}