ECDH Key Exchange Examples
Purpose
The objective of an MTE ECDH "Examples" is to provide a short example of basic MTE Ecdh actions.
Simple demonstration of ECDH within one application.
- C
- C++
- CSharp
- Java
- JavaScript
- Swift
- ObjC
- Python
- Go
#include <stdio.h>
#include <string.h>
#include "mte_alloca.h"
#include "mte_ecdh.h"
#include "mte_random.h"
static char* bytes_to_hex(const uint8_t*, size_t);
static uint8_t* private_keyA;
static size_t private_keyA_bytes;
static uint8_t* public_keyA;
static size_t public_keyA_bytes;
static uint8_t* secretA;
static size_t secretA_bytes;
static uint8_t* private_keyB;
static size_t private_keyB_bytes;
static uint8_t* public_keyB;
static size_t public_keyB_bytes;
static uint8_t* secretB;
static size_t secretB_bytes;
/*************************************************
* Main program
************************************************/
int main() {
// Allocate memory for keys and secret data, and set their sizes.
private_keyA = MTE_ALLOCA(MTE_ECDH_PRIVATE_KEY_SZ);
private_keyA_bytes = MTE_ECDH_PRIVATE_KEY_SZ;
public_keyA = MTE_ALLOCA(MTE_ECDH_PUBLIC_KEY_SZ);
public_keyA_bytes = MTE_ECDH_PUBLIC_KEY_SZ;
secretA = MTE_ALLOCA(MTE_ECDH_SECRET_DATA_SZ);
secretA_bytes = MTE_ECDH_SECRET_DATA_SZ;
private_keyB = MTE_ALLOCA(MTE_ECDH_PRIVATE_KEY_SZ);
private_keyB_bytes = MTE_ECDH_PRIVATE_KEY_SZ;
public_keyB = MTE_ALLOCA(MTE_ECDH_PUBLIC_KEY_SZ);
public_keyB_bytes = MTE_ECDH_PUBLIC_KEY_SZ;
secretB = MTE_ALLOCA(MTE_ECDH_SECRET_DATA_SZ);
secretB_bytes = MTE_ECDH_SECRET_DATA_SZ;
int status = 0;
// Check if memory allocation for any of the above failed.
if ((private_keyA == NULL) || (public_keyA == NULL) || (secretA == NULL) || (private_keyA == NULL) || (public_keyA == NULL) || (secretB == NULL)) {
status = -2;
printf("\n\nMemory allocation error.\n");
return status;
}
// Create key pair A and check for success.
printf("Create key pair A: ");
if (mte_ecdh_create_keypair(private_keyA, &private_keyA_bytes, public_keyA, &public_keyA_bytes, &mte_random_callback, NULL) != MTE_ECDH_SUCCESS) {
printf("Failed to create Key Pair A\n");
status = -1;
return status;
}
// Print key pair A.
char* buffer;
printf("OK\n");
printf("Private: %s\n", bytes_to_hex(private_keyA, private_keyA_bytes));
buffer = bytes_to_hex(public_keyA, public_keyA_bytes);
printf("Public: %.*s\n", MTE_ECDH_PUBLIC_KEY_SZ, buffer);
printf(" %s\n", buffer + MTE_ECDH_PUBLIC_KEY_SZ);
// Create key pair B and check for success.
printf("Create key pair B: ");
if (mte_ecdh_create_keypair
(private_keyB, &private_keyB_bytes,
public_keyB, &public_keyB_bytes,
&mte_random_callback, NULL) != MTE_ECDH_SUCCESS) {
printf("Failed to create Key Pair B\n");
status = -1;
return status;
}
// Print key pair B and attempt to create shared secrets.
printf("OK\n");
printf("Private: %s\n", bytes_to_hex(private_keyB, private_keyB_bytes));
buffer = bytes_to_hex(public_keyB, public_keyB_bytes);
printf("Public: %.*s\n", MTE_ECDH_PUBLIC_KEY_SZ, buffer);
printf(" %s\n", buffer + MTE_ECDH_PUBLIC_KEY_SZ);
// Create shared secret A.
printf("Shared secret A: ");
if (mte_ecdh_create_secret(private_keyA, private_keyA_bytes, public_keyB, public_keyB_bytes, secretA, &secretA_bytes) != MTE_ECDH_SUCCESS) {
printf("Failed to create Shared Secret A.\n");
status = -1;
return status;
}
else {
printf("%s\n", bytes_to_hex(secretA, secretA_bytes));
}
// Attempt to create the second shared secret.
printf("Shared secret B: ");
if (mte_ecdh_create_secret(private_keyB, private_keyB_bytes,
public_keyA, public_keyA_bytes,
secretB, &secretB_bytes) != MTE_ECDH_SUCCESS) {
printf("Failed to create Shared Secret B.\n");
status = -1;
return status;
}
else {
printf("%s\n", bytes_to_hex(secretB, secretB_bytes));
}
// Check if the shared secrets match.
printf("Pairing secrets: ");
if (memcmp(secretA, secretB, secretA_bytes) != 0) {
printf("No match\n");
status = -1;
return status;
}
else
printf("Match\n");
return status;
}
/********************************************************************
* Helper function to convert a byte array to a hex string.
*
* Overview: convert a byte array to an ASCII hex representation
* Input: pointer to the input byte array
* length of the input byte array
* pointer to the output byte array
* size of the output byte array
* Output: pointer to the output byte array (convenience result)
********************************************************************/
static char* bytes_to_hex(const uint8_t* input, size_t input_bytes) {
static char buffer[512];
if (sizeof(buffer) < (2 * input_bytes + 1))
input_bytes = (sizeof(buffer) - 1) / 2;
const uint8_t* pin = input;
const char* hex = "0123456789ABCDEF";
char* pout = buffer;
while (pin < input + input_bytes) {
*pout++ = hex[(*pin >> 4) & 0xF];
*pout++ = hex[*pin++ & 0xF];
}
*pout = 0;
return buffer;
}
#include <cstdio>
#include <cstring>
#include "MteEcdh.h"
#include "MteRandom.h"
/********************************************************************
* Helper function to convert a byte array to a hex string.
*
* Overview: convert a byte array to an ASCII hex representation
* Input: pointer to the input byte array
* length of the input byte array
* pointer to the output byte array
* size of the output byte array
* Output: pointer to the output byte array (convenience result)
********************************************************************/
char* bytesToHex(const uint8_t* input, size_t inputBytes) {
static char buffer[512];
size_t sz = inputBytes;
if (sizeof(buffer) < (2 * sz + 1))
sz = (sizeof(buffer) - 1) / 2;
const uint8_t* pin = input;
const char* hex = "0123456789ABCDEF";
char* pout = buffer;
while (pin < input + sz) {
*pout++ = hex[(*pin >> 4) & 0xF];
*pout++ = hex[*pin++ & 0xF];
}
*pout = 0;
return buffer;
}
/*****************************************************
* Implementation of an application defined callback
* which is used to generate entropy for ecdhB and
* also to test the "zeroize" and "getRandom" methods.
****************************************************/
class EcdhBCallback : public MteEcdh::EntropyCallback {
public:
virtual unsigned int entropyCallback(void* entropy, size_t entropyBytes) {
if (MteRandom::getBytes(entropy, entropyBytes) == 0)
return MteEcdh::Success;
else
return MteEcdh::EntropyFail;
}
};
/*************************************************
* Main program, loop through all the test vectors
* and print out results to the console.
************************************************/
int main() {
char* buffer;
uint8_t* publicKeyA;
uint8_t* secretA;
uint8_t* publicKeyB;
uint8_t* secretB;
printf("Ecdh Add-On Demo\n");
// Create ecdhA and buffers
MteEcdh ecdhA;
publicKeyA = new uint8_t[MteEcdh::SzPublicKey];
secretA = new uint8_t[MteEcdh::SzSecretData];
// Create ecdhB and buffers
MteEcdh ecdhB;
publicKeyB = new uint8_t[MteEcdh::SzPublicKey];
secretB = new uint8_t[MteEcdh::SzSecretData];
// Set entropy for ecdhA
uint8_t* entropy = new uint8_t[MteEcdh::SzPrivateKey];
if (MteRandom::getBytes(entropy, MteEcdh::SzPrivateKey) != 0) {
printf("Calling MteRandom failed.\n");
return -1;
}
ecdhA.setEntropy(entropy, MteEcdh::SzPrivateKey);
// Create key pair for ecdhA
size_t size = MteEcdh::SzPublicKey;
if (ecdhA.createKeyPair(publicKeyA, size) != MteEcdh::Success) {
printf("MteEcdh creating key pair A failed.\n");
return -1;
}
// Note: "entropy" was just zeroized by the createKeyPair function!
buffer = bytesToHex(publicKeyA, MteEcdh::SzPublicKey);
printf("EcdhA public key: %.*s\n", MteEcdh::SzPublicKey, buffer);
printf(" %s\n", buffer + MteEcdh::SzPublicKey);
// Create key pair for ecdhB
EcdhBCallback ecdhBCallback;
ecdhB.setEntropyCallback(&ecdhBCallback);
size = MteEcdh::SzPublicKey;
if (ecdhB.createKeyPair(publicKeyB, size) != MteEcdh::Success) {
printf("MteEcdh creating key pair B failed.\n");
return -1;
}
buffer = bytesToHex(publicKeyB, MteEcdh::SzPublicKey);
printf("EcdhB public key: %.*s\n", MteEcdh::SzPublicKey, buffer);
printf(" %s\n", buffer + MteEcdh::SzPublicKey);
// Create secret for EcdhA
size = MteEcdh::SzSecretData;
if (ecdhA.createSecret(publicKeyB, MteEcdh::SzPublicKey,
secretA, size) != MteEcdh::Success) {
printf("MteEcdh creating secret A failed.\n");
return -1;
}
printf("EcdhA secret: %s\n", bytesToHex(secretA, MteEcdh::SzSecretData));
// Create secret for EcdhB
size = MteEcdh::SzSecretData;
if (ecdhB.createSecret(publicKeyA, MteEcdh::SzPublicKey,
secretB, size) != MteEcdh::Success) {
printf("MteEcdh creating secret B failed.\n");
return -1;
}
printf("EcdhB secret: %s\n", bytesToHex(secretB, MteEcdh::SzSecretData));
// Test if secrets match
printf("Pairing secrets: ");
if (memcmp(secretA, secretB, MteEcdh::SzSecretData) != 0) {
printf("No match\n");
return -1;
}
else
printf("Match\n");
return 0;
}
using System.Text;
namespace Eclypses.MTE {
class Program {
//*******************************************************************
// Helper function to convert a byte array to a hex string.
//
// Overview: convert a byte array to an ASCII hex representation
// Input: pointer to the input byte array
// length of the input byte array
// pointer to the output byte array
// size of the output byte array
// Output: pointer to the output byte array (convenience result)
//*******************************************************************
private static string BytesToHex(byte[] input) {
const string hex = "0123456789ABCDEF";
StringBuilder sb = new();
sb.Clear();
int i = 0;
while (i < input.Length) {
sb.Append(hex[(input[i] >> 4) & 0xF]);
sb.Append(hex[input[i] & 0xF]);
i++;
}
return sb.ToString();
}
private static readonly byte[] publicKeyA = new byte[MteEcdh.SzPublicKey];
private static readonly byte[] secretA = new byte[MteEcdh.SzSecretData];
private static readonly byte[] publicKeyB = new byte[MteEcdh.SzPublicKey];
private static readonly byte[] secretB = new byte[MteEcdh.SzSecretData];
/*****************************************************
* Implementation of an application defined callback
* which is used to generate entropy for ecdhB and
* also to test the "zeroize" and "getRandom" methods.
****************************************************/
public class EcdhBCallback : IMteEcdhEntropyCallback {
public int EntropyCallback(byte[] entropyInput) {
if (entropyInput.Length != MteEcdh.SzPrivateKey)
return MteEcdh.MemoryFail;
Array.Fill(entropyInput, (byte)0xCC);
MteEcdh.Zeroize(entropyInput);
for (int i = 0; i < entropyInput.Length; i++)
if (entropyInput[i] != 0)
return MteEcdh.MemoryFail;
// Get random bytes.
byte[] temp = MteRandom.GetBytes((uint)entropyInput.Length);
if (temp.Length == 0) {
return MteEcdh.EntropyFail;
}
Array.Copy(temp, entropyInput, temp.Length);
return MteEcdh.Success;
}
}
/*************************************************
* Main program, loop through all the test vectors
* and print out results to the console.
************************************************/
static int Main() {
Console.WriteLine("Ecdh Add-On Demo");
MteEcdh ecdhA = new();
// Create key pair for ecdhA.
if (ecdhA.CreateKeyPair(publicKeyA) != MteEcdh.Success) {
Console.WriteLine("MteEcdh creating key pair A failed");
return -1;
}
string s = BytesToHex(publicKeyA);
Console.WriteLine("EcdhA public key: {0}", s[..MteEcdh.SzPublicKey]);
Console.WriteLine(" {0}", s[MteEcdh.SzPublicKey..]);
// Create key pair for ecdhB.
MteEcdh ecdhB = new();
EcdhBCallback ecdhBCallback = new();
ecdhB.SetEntropyCallback(ecdhBCallback);
if (ecdhB.CreateKeyPair(publicKeyB) != MteEcdh.Success) {
Console.WriteLine("MteEcdh creating key pair B failed");
return -1;
}
s = BytesToHex(publicKeyB);
Console.WriteLine("EcdhB public key: {0}", s[..MteEcdh.SzPublicKey]);
Console.WriteLine(" {0}", s[MteEcdh.SzPublicKey..]);
// Create secret for ecdhA.
if (ecdhA.CreateSecret(publicKeyB, secretA) != MteEcdh.Success) {
Console.WriteLine("MteEcdh creating secret A failed.");
return -1;
}
Console.WriteLine("EcdhA secret: {0}", BytesToHex(secretA));
// Create secret for ecdhB.
if (ecdhB.CreateSecret(publicKeyA, secretB) != MteEcdh.Success) {
Console.WriteLine("MteEcdh creating secret B failed.");
return -1;
}
Console.WriteLine("EcdhB secret: {0}", BytesToHex(secretB));
Console.Write("Pairing secrets: ");
if (!secretA.SequenceEqual(secretB)) {
Console.WriteLine("No match");
return -1;
} else {
Console.WriteLine("Match");
}
return 0;
}
}
}
import com.eclypses.mte.MteEcdh;
import com.eclypses.mte.MteRandom;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class demoJavaEcdh implements MteEcdh.EntropyCallback {
//-------------------------------------------
// This helper function converts a byte array
// of arbitrary length to a hex string.
//-------------------------------------------
private String bytesToHex(byte[] bytes) {
StringBuilder hex = new StringBuilder();
for (byte b : bytes)
hex.append(String.format("%02X", b));
return hex.toString();
}
//----------------------------------------------------
// Implementation of an application defined callback
// which is used to generate entropy for ecdhB using
// the MteRandom class.
//----------------------------------------------------
public int entropyCallback(byte[] entropyInput) {
byte[] random = MteRandom.getBytes(MteEcdh.SzPrivateKey);
if (random.length != MteEcdh.SzPrivateKey)
return MteEcdh.EntropyFail;
// Copy the data to parameter...
System.arraycopy(random, 0, entropyInput, 0, random.length);
// ... and zero out the data.
MteEcdh.zeroize(random);
return MteEcdh.Success;
}
public int run() {
byte[] publicKeyA = new byte[MteEcdh.SzPublicKey];
byte[] secretA = new byte[MteEcdh.SzSecretData];
byte[] publicKeyB = new byte[MteEcdh.SzPublicKey];
byte[] secretB = new byte[MteEcdh.SzSecretData];
String s;
System.out.println("Ecdh Add-On Demo");
// Create ecdhA.
MteEcdh ecdhA = new MteEcdh();
// Create ecdhB.
MteEcdh ecdhB = new MteEcdh();
// Create key pair for ecdhA.
if (ecdhA.createKeyPair(publicKeyA) != MteEcdh.Success) {
System.out.println("MteEcdh creating key pair A failed.");
return -1;
}
s = bytesToHex(publicKeyA);
System.out.println("EcdhA public key: " + s.substring(0, MteEcdh.SzPublicKey));
System.out.println(" " + s.substring(MteEcdh.SzPublicKey));
// Create key pair for ecdhB.
ecdhB.setEntropyCallback(this);
if (ecdhB.createKeyPair(publicKeyB) != MteEcdh.Success) {
System.out.println("MteEcdh creating key pair B failed.");
return -1;
}
s = bytesToHex(publicKeyB);
System.out.println("EcdhB public key: " + s.substring(0, MteEcdh.SzPublicKey));
System.out.println(" " + s.substring(MteEcdh.SzPublicKey));
// Create secret for ecdhA.
if (ecdhA.createSecret(publicKeyB, secretA) != MteEcdh.Success) {
System.out.println("MteEcdh creating secret A failed.");
return -1;
}
System.out.println("EcdhA secret: " + bytesToHex(secretA));
// Create secret for ecdhB.
if (ecdhB.createSecret(publicKeyA, secretB) != MteEcdh.Success) {
System.out.println("MteEcdh creating secret B failed.");
return -1;
}
System.out.println("EcdhB secret: " + bytesToHex(secretB));
System.out.print("Pairing secrets: ");
if (!Arrays.equals(secretA, secretB)) {
System.out.println("No match");
return -1;
} else {
System.out.println("Match");
}
return 0;
}
//-----------------------------------------------------------
// This static main() function is used to run the test driver
// as a console app in Linux and Windows. This function is
// not used in Android.
//-----------------------------------------------------------
public static void main(String[] args) {
demoJavaEcdh job = new demoJavaEcdh();
job.run();
}
}
import { MteEcdh, MteEcdhStatus, MteWasm, MteMem } from "./Mte.js";
// The timestamp window and sequencing window are hard coded for this demo.
var timestampWindow = 1;
var sequenceWindow = 0;
// Create and instantiate the singleton WASM. The instantiate() call returns a
// promise that must be resolved before any other MTE objects can be created.
// The instantiated, resolved MteWasm object must be passed as an argument to
// create any other MTE objects.
let wasm = new MteWasm();
wasm.instantiate().then(function () { main(); });
// Main function.
function main() {
console.log("Eclypses Kyber Demo");
console.log("-------------------\n");
var ecdhA = new MteEcdh(wasm);
var ecdhB = new MteEcdh(wasm);
// Create key pair A.
console.log("Creating key pair A\n");
var result = ecdhA.createKeypair();
if (result.status !== MteEcdhStatus.success) {
console.log("ecdhA: Failed to create the key pair (", result.status, ").");
return;
}
var publicKeyA = result.arr;
var str = publicKeyA.reduce(function (s, b) {
return s + b.toString(16).padStart(2, '0');
}, '').toUpperCase();
console.log("Public key A:\n" + str);
// Create key pair B.
console.log("Creating key pair B\n");
result = ecdhB.createKeypair();
if (result.status !== MteEcdhStatus.success) {
console.log("ecdhB: Failed to create the key pair (", result.status, ").");
return;
}
var publicKeyB = result.arr;
str = publicKeyB.reduce(function (s, b) {
return s + b.toString(16).padStart(2, '0');
}, '').toUpperCase();
console.log("Public key B:\n" + str);
// Get shared secret A.
result = ecdhA.createSecret(publicKeyB);
if (result.status !== MteEcdhStatus.success) {
throw new Error("ecdhA: Failed to create the shared secret.");
}
var secretA = result.arr;
str = secretA.reduce(function (s, b) {
return s + b.toString(16).padStart(2, '0');
}, '').toUpperCase();
console.log("Shared secret A:\n" + str);
// Get shared secret B.
result = ecdhB.createSecret(publicKeyA);
if (result.status !== MteEcdhStatus.success) {
throw new Error("ecdhB: Failed to create the shared secret.");
}
var secretB = result.arr;
str = secretB.reduce(function (s, b) {
return s + b.toString(16).padStart(2, '0');
}, '').toUpperCase();
console.log("Shared secret B:\n" + str);
// Compare shared secrets.
if (secretA.length === secretB.length &&
secretA.every(function (v, i) { return v === secretB[i]; })) {
console.log("Shared secrets: MATCH.");
}
else {
console.log("Shared secrets: NO MATCH.");
}
ecdhA.destruct();
ecdhB.destruct();
// Success.
return;
}
import Foundation
class Cbs: MteEcdhEntropyCallback {
func entropyCallback(_ entropyInput: inout [UInt8],
_ eiBytes: UInt64) -> Int32 {
// Zeroize the entropy.
MteEcdh.zeroize(&entropyInput)
let status = MteRandom.getBytes(&entropyInput)
if status != MteEcdh.ResultCodes.success {
debugPrint("Error getting secure random bytes. Error Code: \(status)")
}
// Success.
return Int32(MteEcdh.ResultCodes.success)
}
}
public func main() -> Int32 {
let privateKey:[UInt8] = [UInt8](repeating: 0, count: MteEcdh.Constants.privateKeySize)
var publicKey:[UInt8] = [UInt8](repeating: 0, count: MteEcdh.Constants.publicKeySize)
var secret:[UInt8] = [UInt8](repeating: 0, count: MteEcdh.Constants.secretDataSize)
let privateKey2:[UInt8] = [UInt8](repeating: 0, count: MteEcdh.Constants.privateKeySize)
var publicKey2:[UInt8] = [UInt8](repeating: 0, count: MteEcdh.Constants.publicKeySize)
var secret2:[UInt8] = [UInt8](repeating: 0, count: MteEcdh.Constants.secretDataSize)
var status: Int = 0
if status == 0 {
print("\n\nAvailability test for OS supplied RNG\n")
print("-------------------------------------\n\n")
print("Reading \(MTE_ECDH_SECRET_DATA_SZ) bytes 8 times:\n")
secret.removeAll(keepingCapacity: false)
secret = [UInt8](repeating: 0, count: Int(MTE_ECDH_SECRET_DATA_SZ))
for _ in 0...8 {
let res = MteRandom.getBytes(&secret)
if res == 0 {
print(secret.map{ String(format:"%02X", $0) }.joined())
} else {
print ("Calling MteRandom.getBytes failed.\n")
}
}
}
let ecdhA = MteEcdh()
if status == 0 {
print("\n\nPairing test using OS supplied RNG\n")
print("----------------------------------\n\n")
print("Create key pair A: ")
(status, publicKey) = ecdhA.createKeyPair()
if status != MteEcdh.ResultCodes.success {
print("Failed\n")
status = -1
}
}
let ecdhB = MteEcdh()
// Create the callbacks to get entropy.
let cbs = Cbs()
ecdhB.setEntropyCallback(cbs)
if status == 0 {
print("OK\n")
print("Private: \(privateKey.map{ String(format:"%02X", $0) }.joined())\n")
let midpoint = Int(MTE_ECDH_PUBLIC_KEY_SZ/2)
print("Public: \(Array(publicKey[0 ..< midpoint]).map{ String(format:"%02X", $0)}.joined())\n")
print(" \(Array(publicKey[midpoint ..< Int(MTE_ECDH_PUBLIC_KEY_SZ)]).map{ String(format:"%02X", $0)}.joined())\n")
print("Create key pair B: ")
(status, publicKey2) = ecdhB.createKeyPair()
if status != MTE_ECDH_SUCCESS {
print("Failed\n")
status = -1
}
}
if status == 0 {
print("OK\n")
print("Private: \(privateKey2.map{ String(format:"%02X", $0) }.joined())\n")
let midpoint = Int(MTE_ECDH_PUBLIC_KEY_SZ/2)
print("Public: \(Array(publicKey2[0 ..< midpoint]).map{ String(format:"%02X", $0)}.joined())\n")
print(" \(Array(publicKey2[midpoint ..< Int(MTE_ECDH_PUBLIC_KEY_SZ)]).map{ String(format:"%02X", $0)}.joined())\n")
print("Shared secret A: ")
(status, secret) = ecdhA.getSharedSecret(peerPublicKey: publicKey2)
if status != MTE_ECDH_SUCCESS {
print("Failed\n")
status = -1
}
}
if status == 0 {
print("\(secret.map{ String(format:"%02X", $0) }.joined())\n")
print("Shared secret B: ")
(status, secret2) = ecdhB.getSharedSecret(peerPublicKey: publicKey)
if status != MTE_ECDH_SUCCESS {
print("Failed\n")
status = -1
}
}
if status == 0 {
print("\(secret2.map{ String(format:"%02X", $0) }.joined())\n")
print("Pairing secrets: ")
if !secret.elementsEqual(secret2) {
print("No match\n")
status = -1
} else {
print("Match")
}
}
switch status {
case -2:
print("\n\nMemory allocation error.\n")
case -1:
print("\n\nFAILURE.\n")
case 0:
print("\n\nTests completed successfully.")
default:
// Software error, this can't happen.
print("\n\nUnknown.\n")
}
// Success.
return Int32(status)
}
#import "MteEcdh.h"
#import "MteRandom.h"
#import <Foundation/Foundation.h>
#import <stdlib.h>
#import <string.h>
/********************************************************************
* Helper function to convert a byte array to a hex string.
*
* Overview: convert a byte array to an ASCII hex representation
* Input: pointer to the input byte array
* length of the input byte array
* pointer to the output byte array
* size of the output byte array
* Output: pointer to the output byte array (convenience result)
********************************************************************/
char *bytesToHex(const uint8_t *input, size_t inputBytes) {
static char buffer[512];
if (sizeof(buffer) < (2 * inputBytes + 1))
inputBytes = (sizeof(buffer) - 1) / 2;
const uint8_t *pin = input;
const char *hex = "0123456789ABCDEF";
char *pout = buffer;
while (pin < input + inputBytes) {
*pout++ = hex[(*pin >> 4) & 0xF];
*pout++ = hex[*pin++ & 0xF];
}
*pout = 0;
return buffer;
}
@interface Cbs : NSObject<MteEcdhEntropyCallback>
{
uint8_t *myEntropy;
}
-(int)entropyCallback:(uint8_t *)entropyInput : (size_t)eiBytes;
@end
int main(int argc, char **argv)
{
int status = 0;
// uint8 *privateKey = malloc(PrivateKeySize);
// size_t privateKeyBytes = PrivateKeySize;
uint8 *publicKey = malloc(PublicKeySize);
size_t publicKeyBytes = PublicKeySize;
uint8 *secret = malloc(SecretDataSize);
size_t secretBytes = SecretDataSize;
// uint8 *privateKey2 = malloc(PrivateKeySize);
// size_t privateKeyBytes2 = PrivateKeySize;
uint8 *publicKey2 = malloc(PublicKeySize);
size_t publicKeyBytes2 = PublicKeySize;
uint8 *secret2 = malloc(SecretDataSize);
size_t secretBytes2 = SecretDataSize;
MteEcdh *mteEcdhA = [[MteEcdh alloc] init];
printf("\n\nAvailability test for OS supplied RNG\n");
printf("-------------------------------------\n\n");
printf("Reading %ld bytes 8 times:\n", (long)SecretDataSize);
secretBytes = SecretDataSize;
for (int i = 0; i < 8; i++)
{
if ([MteRandom getBytes:secret :secretBytes] == Success)
{
printf("%s\n", bytesToHex(secret, secretBytes));
}
else
{
printf("Calling getBytes() failed.\n");
status = -1;
break;
}
}
if (status == 0)
{
printf("\n\nPairing test using OS supplied RNG\n");
printf("----------------------------------\n\n");
printf("Create key pair A: ");
status = [mteEcdhA createKeyPair:publicKey :&publicKeyBytes];
if (status != Success)
{
printf("Failed\n");
status = -1;
}
}
// Create the callbacks to get entropy.
Cbs *cbs = [[Cbs alloc] init];
MteEcdh *mteEcdhB = [[MteEcdh alloc] init];
[mteEcdhB setEntropyCallback:cbs];
char *buffer;
if (status == 0)
{
printf("OK\n");
// printf("Private: %s\n", bytesToHex(privateKey, privateKeyBytes));
buffer = bytesToHex(publicKey, publicKeyBytes);
printf("Public: %.*s\n", (int)PublicKeySize, buffer);
printf(" %s\n", buffer + PublicKeySize);
printf("Create key pair B: ");
status = [mteEcdhB createKeyPair:publicKey2 :&publicKeyBytes2];
if (status != Success)
{
printf("Failed\n");
status = -1;
}
}
if (status == 0)
{
printf("OK\n");
// printf("Private: %s\n", bytesToHex(privateKey2, privateKeyBytes2));
buffer = bytesToHex(publicKey2, publicKeyBytes2);
printf("Public: %.*s\n", (int)PublicKeySize, buffer);
printf(" %s\n", buffer + PublicKeySize);
printf("Shared secret A: ");
status = [mteEcdhA createSecret:publicKey2 :publicKeyBytes2 :secret :&secretBytes];
if (status != Success)
{
printf("Failed\n");
status = -1;
}
}
if (status == 0)
{
printf("%s\n", bytesToHex(secret, secretBytes));
printf("Shared secret B: ");
status = [mteEcdhB createSecret:publicKey :publicKeyBytes :secret2 :&secretBytes2];
if (status != Success)
{
printf("Failed\n");
status = -1;
}
}
if (status == 0)
{
printf("%s\n", bytesToHex(secret2, secretBytes2));
printf("Pairing secrets: ");
if (memcmp(secret, secret2, SecretDataSize) != 0)
{
printf("No Match\n");
status = -1;
}
else
{
printf("Match\n");
}
}
switch (status)
{
case -2:
printf("\n\nMemory allocation error.\n");
break;
case -1:
printf("\n\nFAILURE.\n");
break;
case 0:
printf("\n\nTests completed successfully.\n");
break;
default:
// Software error, this can't happen.
break;
}
return status;
}
@implementation Cbs
-(int)entropyCallback:(uint8_t *)entropyInput : (size_t)eiBytes
{
// Set byte array to 0xcc.
for (int i = 0; i < eiBytes; i++)
{
entropyInput[i] = 0xcc;
}
// Zeroize the entropy.
[MteEcdh zeroize:entropyInput :eiBytes];
// Ensure each value is zero.
for (int i = 0; i < eiBytes; i++)
{
if (entropyInput[i] != 0)
{
return MTE_ECDH_MEMORY_FAIL;
}
}
// Get random bytes.
int res = [MteRandom getBytes:entropyInput :eiBytes];
if (res != MTE_ECDH_SUCCESS)
{
return MTE_ECDH_ENTROPY_FAIL;
}
return MTE_ECDH_SUCCESS;
}
@end
import ctypes
import MteEcdh
import MteRandom
import copy
from MteEcdh import EcdhEntropyCallback
publicKeyA = bytearray(MteEcdh.SzPublicKey)
publicKeyB = bytearray(MteEcdh.SzPublicKey)
secretA = bytearray(MteEcdh.SzSecretData)
secretB = bytearray(MteEcdh.SzSecretData)
def bytes_to_hex(input):
hex_chars = "0123456789ABCDEF"
sb = []
i = 0
while i < len(input):
sb.append(hex_chars[(input[i] >> 4) & 0xF])
sb.append(hex_chars[input[i] & 0xF])
i += 1
return''.join(sb)
class ecdhB_callback:
def entropy_callback(entropyInput):
if len(entropyInput) != MteEcdh.SzPrivateKey:
print("first memory fail")
return MteEcdh.MemoryFail
# Generate a random byte string
rand = MteRandom.MteRandom()
random_bytes = rand.get_bytes(MteEcdh.SzPrivateKey)
# Copy the random bytes into entropyInput
for i in range(len(entropyInput)):
entropyInput[i] = random_bytes[i]
ecdhTest = MteEcdh.MteEcdh()
return 0
def main():
print("\n\nEcdh Add-On Demo\n")
# Create ecdhA.
ecdhA = MteEcdh.MteEcdh()
# Create ecdhB.
ecdhB = MteEcdh.MteEcdh()
# Create key pair for ecdhA.
if ecdhA.create_keypair(publicKeyA) != MteEcdh.Success:
print("MteEcdh creating key pair A failed.\n")
return -1
s = bytes_to_hex(publicKeyA)
print("EcdhA public key: " + s)
# Create key pair for ecdhB.
ecdhBCallback = ecdhB_callback
ecdhB.set_entropy_callback(ecdhBCallback)
if ecdhB.create_keypair(publicKeyB) != MteEcdh.Success:
print("MteEcdh creating key pair B failed.\n")
return -1
s = bytes_to_hex(publicKeyB)
print("EcdhB public key: " + s)
# Create secret for ecdhA.
if ecdhA.create_secret(publicKeyB, secretA) != MteEcdh.Success:
print("MteEcdh creating secret A failed.\n")
return -1
s = bytes_to_hex(secretA)
print("EcdhA secret: " + s)
# Create secret for ecdhB.
if ecdhB.create_secret(publicKeyA, secretB) != MteEcdh.Success:
print("MteEcdh creating secret B failed.\n")
return -1
s = bytes_to_hex(secretB)
print("EcdhB secret: " + s)
# Test if secrets match.
print(bytes_to_hex(secretB))
print("Pairing secrets: ")
if secretA != secretB:
print("No Match")
else:
print("Match")
return 0
main()
package main
import "C"
import (
"fmt"
"os"
"reflect"
"goEcdhDemo/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 {
}
/*****************************************************
* Implementation of an application defined callback
* which is used to generate entropy for ecdhB and
* also to test the "Zeroize" and "Random_GetBytes" methods.
****************************************************/
func (cbs *Cbs) EntropyCallback(entropyData []byte) int {
// Set byte array to 0xcc.
for i := range entropyData {
entropyData[i] = 0xcc
}
// Zeroize the entropy.
mte.MteEcdhZeroize(entropyData)
// Ensure each value is zero.
for i := range entropyData {
if entropyData[i] != 0 {
return mte.MTE_ECDH_MEMORY_FAIL
}
}
var entropySize = len(entropyData)
res, temp := mte.Random_GetBytes(entropySize)
if res {
// Copy to the entropy buffer.
copy(entropyData, temp)
} else {
return mte.MTE_ECDH_ENTROPY_FAIL
}
return mte.MTE_ECDH_SUCCESS
}
func doMain() int {
var publicKeyA []byte = make([]byte, mte.MTE_ECDH_PUBLIC_KEY_SZ)
var secretA []byte = make([]byte, mte.MTE_ECDH_SECRET_DATA_SZ)
var publicKeyB []byte = make([]byte, mte.MTE_ECDH_PUBLIC_KEY_SZ)
var secretB []byte = make([]byte, mte.MTE_ECDH_SECRET_DATA_SZ)
var status int
fmt.Println("Ecdh Add-On Demo")
// Create ecdhA.
ecdhA := mte.NewMteEcdhDef()
defer ecdhA.Destroy()
// Create ecdhB.
ecdhB := mte.NewMteEcdhDef()
defer ecdhB.Destroy()
// Create key pair for ecdhA.
status, publicKeyA = ecdhA.CreateKeypair()
if status != mte.MTE_ECDH_SUCCESS {
fmt.Print("MteEcdh creating key pair A failed.\n")
return -1
}
fmt.Printf("EcdhA public key: %X\n", publicKeyA[0:mte.MTE_ECDH_PUBLIC_KEY_SZ/2])
fmt.Printf(" %X\n", publicKeyA[mte.MTE_ECDH_PUBLIC_KEY_SZ/2:])
// Create key pair for ecdhB.
cbs := &Cbs{}
ecdhB.SetEntropyCallback(cbs)
status, publicKeyB = ecdhB.CreateKeypair()
if status != mte.MTE_ECDH_SUCCESS {
fmt.Print("MteEcdh creating key pair B failed.\n")
return -1
}
fmt.Printf("EcdhB public key: %X\n", publicKeyB[0:mte.MTE_ECDH_PUBLIC_KEY_SZ/2])
fmt.Printf(" %X\n", publicKeyB[mte.MTE_ECDH_PUBLIC_KEY_SZ/2:])
// Create secret for ecdhA.
status, secretA = ecdhA.CreateSecret(publicKeyB)
if status != mte.MTE_ECDH_SUCCESS {
fmt.Print("MteEcdh creating secret A failed.\n")
return -1
}
fmt.Printf("EcdhA secret: %X\n", secretA)
// Create secret for ecdhB.
status, secretB = ecdhB.CreateSecret(publicKeyA)
if status != mte.MTE_ECDH_SUCCESS {
fmt.Print("MteEcdh creating secret B failed.\n")
return -1
}
fmt.Printf("EcdhB secret: %X\n", secretB)
// Test if secrets match.
if !reflect.DeepEqual(secretA, secretB) {
fmt.Print("No match\n")
status = -1
} else {
fmt.Print("Match\n")
}
// Success.
return 0
}
func main() {
os.Exit(doMain())
}