Skip to content

Instantly share code, notes, and snippets.

@PaddeK
Created July 14, 2015 23:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PaddeK/979317f301c4fb62f0f3 to your computer and use it in GitHub Desktop.
Save PaddeK/979317f301c4fb62f0f3 to your computer and use it in GitHub Desktop.
Nymi SDK 2.0 C++ example
#include "ncl.h"
#include <string>
#include <iostream>
#include <iomanip>
#include <vector>
#include <sstream>
#include <fstream>
#include <array>
using namespace std;
bool gNclInitialized=false; //Global variable to maintain the state of the NCL
int gHandle=-1; //Global variable to maintain the current connected Nymi handle
vector<NclProvision> gProvisions; //Global vector for storing the list of provisioned Nymi
NclVk verificationKey;
NclVkId verificationKeyId;
const string FILE_PROVISION = "provision.txt";
const string FILE_VERIFICATION_KEY = "verification.txt";
const string FILE_SIGNATURE = "signature.txt";
const string HOME_PATH = "D:\\";
int saveProvisionsToFile()
{
ofstream file((HOME_PATH + FILE_PROVISION).c_str());
file << gProvisions.size() << "\n";
for (unsigned i = 0; i < gProvisions.size(); ++i) {
for (unsigned j = 0; j < NCL_PROVISION_KEY_SIZE; ++j) {
file << (int)gProvisions[i].key[j] << " ";
}
file << " ";
for (unsigned j = 0; j < NCL_PROVISION_ID_SIZE; ++j) {
file << (int)gProvisions[i].id[j] << " ";
}
file << "\n";
}
file.close();
return 0;
}
int getProvisionsFromFile()
{
ifstream file((HOME_PATH + FILE_PROVISION).c_str());
if (file.good()) {
unsigned size = 0;
file >> size;
for (unsigned i = 0; i < size; ++i) {
gProvisions.push_back(NclProvision());
for (unsigned j = 0; j < NCL_PROVISION_KEY_SIZE; ++j) {
unsigned b;
file >> b;
gProvisions.back().key[j] = b;
}
for (unsigned j = 0; j < NCL_PROVISION_ID_SIZE; ++j) {
unsigned b;
file >> b;
gProvisions.back().id[j] = b;
}
}
return 0;
}
return 1;
}
int saveVerificationKeyToFile(NclVkId id, NclVk vk) {
ofstream file((HOME_PATH + FILE_VERIFICATION_KEY).c_str());
for (unsigned i = 0; i < NCL_VK_ID_SIZE; i++) {
file << (int) id[i] << " ";
}
file << " ";
for (unsigned i = 0; i < NCL_VK_SIZE; i++) {
file << (int) vk[i] << " ";
}
file.close();
return 0;
}
int getVerificationKeyFromFile() {
ifstream file((HOME_PATH + FILE_VERIFICATION_KEY).c_str());
if (file.good()) {
NclUInt8 id[NCL_VK_ID_SIZE];
NclUInt8 vk[NCL_VK_SIZE];
for (unsigned i = 0; i < NCL_VK_ID_SIZE; ++i) {
unsigned b;
file >> b;
id[i] = b;
}
for (unsigned i = 0; i < NCL_VK_SIZE; ++i) {
unsigned b;
file >> b;
vk[i] = b;
}
memmove(verificationKeyId, id, sizeof(id));
memmove(verificationKey, vk, sizeof(vk));
return 0;
}
return 1;
}
int saveSignatureToFile(NclSig sig) {
ofstream file((HOME_PATH + FILE_SIGNATURE).c_str());
for (unsigned i = 0; i < NCL_SIG_SIZE; i++) {
file << (int)sig[i] << " ";
}
file.close();
return 0;
}
string hexStr(unsigned char *data, int len)
{
stringstream ss;
ss << hex;
for (int i = 0; i < len; ++i)
ss << setw(2) << setfill('0') << (int)data[i];
return ss.str();
}
/*
Function for handling the events thrown by the NCL
@param[in] event NclEvent that contains the event type and member variables
@param[in] userData Data that needs to be passed to the callback functions if provided
*/
void callback(NclEvent event, void* userData){
NclBool res;
switch(event.type){
case NCL_EVENT_INIT:
if(event.init.success){
gNclInitialized=true;
cout<<"log: init succeeded, getting info\n";
NclInfo info=nclInfo(); //Prints current initialization configuration
cout<<info.string;
}
else exit(-1);
break;
case NCL_EVENT_ERROR:
exit(-1);
break;
case NCL_EVENT_DISCOVERY:
cout<<"log: Nymi discovered\n";
res=nclStopScan(); //Stops scanning to prevent discovering new Nymis
if(res){
cout<<"Stopping Scan successful\n";
}
else{
cout<<"Stopping Scan failed\n";
}
gHandle=event.discovery.nymiHandle;
res=nclAgree(gHandle); //Initiates the provisioning process with discovered Nymi
if(res){
cout<<"Agree request successful\n";
}
else{
cout<<"Agree request failed\n";
}
break;
case NCL_EVENT_FIND:
cout<<"log: Nymi found\n";
res=nclStopScan(); //Stops scanning to prevent more find events
if(res){
cout<<"Stopping Scan successful\n";
}
else{
cout<<"Stopping Scan failed\n";
}
gHandle=event.find.nymiHandle;
res=nclValidate(gHandle); //Validates the found Nymi
if(res){
cout<<"Validate request successful\n";
}
else{
cout<<"Validaterequest failed\n";
}
break;
case NCL_EVENT_DISCONNECTION:
cout<<"log: disconnected\n";
gHandle=-1; //Uninitialize the Nymi handle
break;
case NCL_EVENT_AGREEMENT:
//Displays the LED pattern for user confirmation
cout<<"Is this:\n";
for(unsigned i=0; i<NCL_AGREEMENT_PATTERNS;++i){
for(unsigned j=0; j<NCL_LEDS; ++j)
cout<<event.agreement.leds[i][j];
cout<<"\n";
}
cout<<"the correct LED pattern (agree/reject)?\n";
break;
case NCL_EVENT_PROVISION:
//Store the provision information in a vector. Ideally this information
//is stored in persistent memory to be used later for future validations
gProvisions.push_back(event.provision.provision);
saveProvisionsToFile();
cout<<"log: provisioned\n";
break;
case NCL_EVENT_VK:
gHandle = event.vk.nymiHandle;
NclVkId vkId;
NclVk vk;
memmove(vkId, event.vk.id, sizeof(event.vk.id));
memmove(vk, event.vk.vk, sizeof(event.vk.vk));
cout << hexStr(vk, NCL_VK_SIZE) << "\n";
saveVerificationKeyToFile(vkId, vk);
cout << "Signature Key pair created and stored to file\n";
break;
case NCL_EVENT_SIG:
gHandle = event.sig.nymiHandle;
NclSig sig;
cout << "Message signed and signature stored to file\n";
memmove(sig, event.sig.sig, sizeof(event.sig.sig));
cout << hexStr(sig, NCL_SIG_SIZE) << "\n";
saveSignatureToFile(sig);
break;
case NCL_EVENT_VALIDATION:
cout<<"Nymi validated! Now trusted user requests can happen, such as request Symmetric Keys!\n";
break;
default: break;
}
}
/*
Main program function
*/
int main(){
cout << "Welcome to Hello Nymi!\n";
cout << "Enter \"load\" if you want to load a previous provision.\n";
cout << "Enter \"createSigKeyPair\" if you want to create a Signature Key pair.\n";
cout << "Enter \"sign\" if you want to sign a message with a stored Key pair.\n";
cout << "Enter \"provision\" if you want to start trusting a new Nymi.\n";
cout << "Enter \"validate\" if you want to find trusted Nymis and validate the first one found.\n";
cout << "Enter \"quit\" to quit.\n\n";
//Only if using the Nymulator.
//127.0.0.1 is the localhost computer. Supply a different IP if using a different host computer
//9089 is the port the Nymulator is listening on
//if(!nclSetIpAndPort("127.0.0.1", 9089)) return -1;
//Initializes the Nymi Communication Library
//'callback' refers to the function that will be handling the NCL callbacks
//NULL indicates there is no data to be passed to the NCL callbacks
//'HelloNymi' is the name of this NEA program that will be provisioned in the Nymi
//NCL_MODE_DEFAULT to run NCL in the default mode
//stderr refers to the stream where the NCL logs will be printed
if(!nclInit(callback, NULL, "HelloNymi", NCL_MODE_DEFAULT, stderr)) return -1;
//Main loop for continuously polling user input
while(true){
string input;
cin>>input; //retreives and stores user input
//Ensures no commands are handled until NCL has completed initialization
if(!gNclInitialized){
cout<<"error: NCL didn't finished initializing yet!\n";
continue;
}
if(input=="provision"){
NclBool res=nclStartDiscovery();
if(res){
cout<<"Discovery started successfully\n";
}
else{
cout<<"Discovery failed to start\n";
}
}
else if (input == "load") {
int error = getProvisionsFromFile();
if (!error) {
cout << "Provision load was successful\n";
}
else {
cout << "No Provision found\n";
}
}
else if (input == "createSigKeyPair") {
if (gHandle != -1) {
NclBool res = nclCreateSigKeyPair(gHandle, NCL_SECP256K);
if (res) {
cout << "creatSigKeyPair started successfully\n";
}
else {
cout << "createSigKeyPair failed\n";
}
continue;
}
cout << "No Nymi validated and ready\n";
}
else if (input == "sign") {
if (gHandle != -1) {
int error = getVerificationKeyFromFile();
NclUInt8 message[NCL_MESSAGE_SIZE] = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '!', '!', '!', '!'};
NclMessage msg;
memmove(msg, message, sizeof(message));
if (!error) {
NclBool res = nclSign(gHandle, verificationKeyId, msg);
if (res) {
cout << "Signing the message\n";
}
else {
cout << "Signing the message failed\n";
}
}
else {
cout << "No Key pair found to sign with\n";
}
continue;
}
cout << "No Nymi validated and ready\n";
}
else if(input=="agree"){
NclBool res=nclProvision(gHandle, NCL_FALSE);
if(res){
cout<<"Provision request successful\n";
}
else{
cout<<"Provisioning failed\n";
}
}
else if(input=="reject"){
//Attempt to disconnect from currently connected Nymi
if(!nclDisconnect(gHandle)){
cout<<"Disconnection Failed!\n";
}
}
else if(input=="validate"){
NclBool res=nclStartFinding(gProvisions.data(), gProvisions.size(), NCL_FALSE);
if(res){
cout<<"Finding started successfully\n";
}
else{
cout<<"Finding failed to start\n";
}
}
else if(input=="disconnect"){
if(gHandle==-1){
cout<<"NEA Not connected to a Nymi. Cannot Disconnect\n";
continue;
}
NclBool res=nclDisconnect(gHandle);
if(res){
cout<<"Disconnection request successfull\n";
}
else{
cout<<"Disconnection failed\n";
}
}
else if(input=="quit"){
if(gHandle!=-1){
nclDisconnect(gHandle);
}
break;
}
else{
cout<<"Unknown Command\n";
}
}
nclFinish(); //closes the NCL
return 0; //Quits program
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment