Created
July 14, 2015 23:38
-
-
Save PaddeK/979317f301c4fb62f0f3 to your computer and use it in GitHub Desktop.
Nymi SDK 2.0 C++ example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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