Sleds/libeye/generatekeys.cpp

290 lines
9.1 KiB
C++

// Copyright (c) 2016 Sequence Logic, Inc. All rights reserved.
//
// Command line program for RSA key generation.
#include "eyering.h"
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
using namespace sequencelogic;
namespace
{
void printUsage(const char *pExe)
{
std::cout << "Usage:\n"
<< pExe << " [-h] [-listcr] [-human] -user {username} -cr1 {CR 1 question}::{CR 1 answer} -cr2 {CR 2 question}::{CR 2 answer} -cr3 {CR 3 question}::{CR 3 answer} "
<< "[-nosalt] [-noac] [-ac {account code}] [-salt {salt}]\n"
<< "-h -- Display this usage message.\n"
<< "-listcr -- Display a list of all the possible CR questions.\n"
<< "-human -- Also print out the keys in a \"human readable\" format. Default is false, regular output is JSON.\n"
<< "-user -- The username of the account to generate RSA keys for.\n"
<< "-cr[1,2,3] -- Three challenge/response questions and answers.\n"
<< "-nosalt -- Optional, don't generate a salt.\n"
<< "-noac -- Optional, don't generate an account code.\n"
<< "-ac -- Optional, use the passed in account code.\n"
<< "-salt -- Optional, use the passed in salt.\n"
<< "\nExample:\n"
<< " " << pExe << " -user viggy -cr1 favbook::hello -cr2 flame::there -cr3 kiss::sequencelogic" << std::endl;
}
void printCRQuests()
{
std::cout << "Challenge response questions:\n"
<< " favbook\n"
<< " flame\n"
<< " kiss\n"
<< " kissloc\n"
<< " concert\n"
<< " memperson\n"
<< " favchar\n"
<< " favsay\n"
<< " neverinv\n"
<< " bestcostume\n"
<< " growndiff\n"
<< " wallpic\n"
<< " childnames\n"
<< " songdesc\n"
<< " erasure\n"
<< " passphrase" << std::endl;
}
enum
{
E_HUMANREADABLE = 0x01,
E_HELP = 0x02,
E_LISTCRS = 0x04,
E_NOSALT = 0x08,
E_NOAC = 0x10
};
struct CmdLineData
{
std::string _user;
std::string _cr1;
std::string _cr2;
std::string _cr3;
std::string _accountCode;
std::string _salt;
unsigned short _nFlags;
CmdLineData() : _nFlags(0) {}
bool isHumanReadable() const { return (_nFlags & E_HUMANREADABLE) == E_HUMANREADABLE; }
bool isHelp() const { return (_nFlags & E_HELP) == E_HELP; }
bool isListCRs() const { return (_nFlags & E_LISTCRS) == E_LISTCRS; }
bool isNoSalt() const { return (_nFlags & E_NOSALT) == E_NOSALT; }
bool isNoAC() const { return (_nFlags & E_NOAC) == E_NOAC; }
};
bool parseCmdLine (int argc, const char *argv[], CmdLineData &opt);
}
int main(int argc, const char *argv[])
{
int nRetVal = 0;
CmdLineData cmdOpts;
if (parseCmdLine(argc, argv, cmdOpts))
{
if (cmdOpts.isHelp())
{
printUsage(argv[0]);
return nRetVal;
}
if (cmdOpts.isListCRs())
{
printCRQuests();
return nRetVal;
}
// Reformat for libeye. Just a JSON array...
std::stringstream jsonCRsStream;
jsonCRsStream << "["
<< "\"" << cmdOpts._user << "\","
<< "\"" << cmdOpts._cr1 << "\","
<< "\"" << cmdOpts._cr2 << "\","
<< "\"" << cmdOpts._cr3 << "\"]";
std::string jsonCRs = jsonCRsStream.str();
// Create the keys!
std::string salt = cmdOpts._salt, accountCode = cmdOpts._accountCode;
Keyring tmpKeyring ("Temp", "Temp keyring for key generation.");
if (cmdOpts.isNoSalt() && cmdOpts.isNoAC())
tmpKeyring.GenerateRSAKey("Key1", "Dummy desc", jsonCRs);
else if (cmdOpts.isNoAC())
tmpKeyring.ProvisionChallengeRSAKey("Key1", jsonCRs, salt);
else
tmpKeyring.ProvisionAccountRSAKey("Key1", accountCode, salt, jsonCRs);
Key tmpKey;
tmpKeyring.GetKey ("Key1", tmpKey);
char *pPubKey = tmpKey.GetPubKey();
// Dump them!
if (cmdOpts.isHumanReadable())
{
std::cout << "Keys for user '" << cmdOpts._user << "', with challenges:\n"
<< " CR1: " << cmdOpts._cr1 << "\n"
<< " CR2: " << cmdOpts._cr2 << "\n"
<< " CR3: " << cmdOpts._cr3 << "\n";
std::cout << "\n" << "Public:\n-------\n";
std::cout << pPubKey << "\n";
std::cout << "\nPrivate:\n--------\n";
std::cout << tmpKey.GetStringKey() << "\n";
std::cout << "Salt:\n-----\n" << salt << "\n";
std::cout << "Account Code:\n-------------\n" << accountCode << "\n";
}
// Always dump JSON. Convert '\n' to "\\n"
std::stringstream tmpStream;
std::string pubKeyStr;
std::string tmpString;
tmpStream.str(pPubKey);
while(std::getline(tmpStream, tmpString))
pubKeyStr += (tmpString + "\\n");
pubKeyStr.pop_back();
pubKeyStr.pop_back();
std::string privKeyStr;
std::stringstream tmpStream2;
tmpStream2.str(reinterpret_cast<const char *>(tmpKey.GetKey()));
while (std::getline(tmpStream2, tmpString))
privKeyStr += (tmpString + "\\n");
privKeyStr.pop_back();
privKeyStr.pop_back();
std::cout << "{\n"
<< " \"user\": \"" << cmdOpts._user << "\",\n"
<< " \"public\": \"" << pubKeyStr << "\",\n"
<< " \"private\": \"" << privKeyStr << "\"\n"
<< " \"salt\": \"" << salt << "\"\n"
<< " \"acccode\": \"" << accountCode << "\"\n"
<< "}\n";
delete [] pPubKey;
}
else
{
nRetVal = -1;
std::cerr << "Error parsing cmd line args." << std::endl;
printUsage(argv[0]);
}
return nRetVal;
}
namespace
{
bool parseCmdLine (int argc, const char *argv[], CmdLineData &opt)
{
bool bRetVal = true;
for (int i = 0; i < argc; ++i)
{
if ((argv[i][0] == '-') || (argv[i][0] == '/'))
{
std::string arg = argv[i];
arg.erase(0, 1);
std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower);
switch (argv[i][1])
{
case 'a':
if (arg == "ac")
{
if (++i < argc)
{
opt._accountCode = argv[i];
std::cout << argv[i] << std::endl;
}
else
{
std::cerr << "No account code specified." << std::endl;
bRetVal = false;
}
}
break;
case 'c':
if ((arg == "cr1") || (arg == "cr2") || (arg == "cr3"))
{
if (i+1 < argc)
{
switch (argv[i][3])
{
case '1':
opt._cr1 = argv[++i];
break;
case '2':
opt._cr2 = argv[++i];
break;
case '3':
opt._cr3 = argv[++i];
break;
}
}
}
break;
case 'h':
if (arg == "human")
opt._nFlags |= E_HUMANREADABLE;
else if (arg == "help")
opt._nFlags |= E_HELP;
break;
case 'l':
if (arg == "listcr")
opt._nFlags |= E_LISTCRS;
break;
case 'n':
if (arg == "nosalt")
opt._nFlags |= E_NOSALT;
else if (arg == "noac")
opt._nFlags |= E_NOAC;
break;
case 's':
if (arg =="salt")
{
if (++i < argc)
opt._salt = argv[i];
else
{
std::cerr << "No salt specified." << std::endl;
bRetVal = false;
}
}
break;
case 'u':
if (arg == "user")
{
if (++i < argc)
opt._user = argv[i];
}
break;
default:
break;
}
}
}
// Need at least user, and 3 CRs.
if (!opt.isHelp() && !opt.isListCRs() && (opt._user == ""))
{
std::cerr << "Error: no user specified.\n";
bRetVal = false;
}
if ((!opt.isHelp() && !opt.isListCRs()) && ((opt._cr1 == "") || (opt._cr2 == "") || (opt._cr3 == "")))
{
std::cerr << "Error: missing challenge/response input.\n";
bRetVal = false;
}
return bRetVal;
}
}