// Copyright (c) 2016 Sequence Logic, Inc. All rights reserved. // // Command line program for RSA key generation. #include "eyering.h" #include #include #include #include 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(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; } }