#include "Keychain.h" Keychain::Keychain(std::string directory) { this->directory = directory; } Keychain::~Keychain() { } Keychain* Keychain::newKeychain(std::string directory) { return new Keychain(directory); } Keychain* Keychain::loadKeychain(std::string directory) { std::string data = Cryptor::loadAndDecrypt(directory); std::istringstream datstr(data); Keychain* kc = new Keychain(directory); int kcSize, servSize; datstr >> kcSize; if (datstr.fail()) throw 1; for (int i = 0; i < kcSize; i++) { std::string serviceName; datstr >> serviceName; datstr >> servSize; if (datstr.fail()) throw 1; std::vector creds; for (int j = 0; j < servSize; j++) { std::string username; std::string password; bool reset; datstr >> username; datstr >> password; datstr >> reset; Credential c; c.username = username; c.password = password; c.reset = reset; creds.push_back(c); } kc->credentials[serviceName] = creds; } return kc; } void Keychain::saveKeychain() { std::stringstream datstr; int kcSize, servSize; kcSize = credentials.size(); datstr << kcSize << std::endl; for (std::map >::iterator it = credentials.begin(); it != credentials.end(); it++) { std::string serviceName = it->first; std::vector creds = it->second; servSize = creds.size(); datstr << serviceName << std::endl; datstr << servSize << std::endl; for (int i = 0; i < servSize; i++) { std::string username; std::string password; bool reset; username = creds[i].username; password = creds[i].password; reset = creds[i].reset; datstr << username << std::endl; datstr << password << std::endl; datstr << reset << std::endl; } } Cryptor::encryptAndSave(directory, datstr.str()); } void Keychain::walk() { // Don't call this, it's just for debuging purposes and prints out plaintext passwords! std::cout << "Starting Keychain Walk" << std::endl; std::cout << credentials.size() << " services." << std::endl; int i = 0; for (std::map >::iterator it = credentials.begin(); it != credentials.end(); it++) { std::cout << "[[#" << (i++) << "]] " << it->first << std::endl; std::vector creds = it->second; std::cout << creds.size() << " credentials." << std::endl; for (int j = 0; j < creds.size(); j++) { std::cout << "[#" << j << "]" << std::endl; Credential c = creds[j]; std::cout << "username= " << c.username << std::endl; std::cout << "password= " << c.password << std::endl; std::cout << "reset = " << (c.reset ? "true" : "false") << std::endl; std::cout << std::endl; } std::cout << std::endl; } std::cout << std::endl; std::cout << "Ending Keychain Walk" << std::endl; } int Keychain::getServiceCount(std::string service) { std::vector creds = getCreds(service); return creds.size(); } Credential Keychain::create(std::string service, std::string username, std::string password) { std::vector creds = getCreds(service); Credential c; c.username = username; c.password = password; creds.push_back(c); credentials[service] = creds; return c; } Credential Keychain::create(std::string service, std::string username, PasswordSpec spec) { return create(service, username, Cryptor::createRandomPassword(spec)); } Credential Keychain::create(std::string service, std::string password) { return create(service, Cryptor::createRandomPassword(getUsernameSpec()), password); } Credential Keychain::create(std::string service, PasswordSpec spec) { return create(service, Cryptor::createRandomPassword(spec)); } bool Keychain::_delete(std::string service) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } std::cout << "WARNING: This will delete all " << creds.size() << " credentials for " << service << std::endl; promptConfirm(); credentials.erase(service); return true; } bool Keychain::_delete(std::string service, std::string username) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } int count = getCredsUsernameCount(creds, username); if (count == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << " with username " << username << std::endl; throw false; } std::cout << "WARNING: This will delete all " << count << " credentials for " << service << " with username " << username << std::endl; promptConfirm(); for (int i = 0; i < creds.size(); i++) { if (creds[i].username == username) { creds.erase(creds.begin() + i); i--; } } credentials[service] = creds; if (creds.size() == 0) { credentials.erase(service); return true; } return false; } bool Keychain::_delete(std::string service, int cn) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } if (cn >= creds.size()) { std::cerr << "Error: credential number is out of bounds for " << service << std::endl; throw false; } std::cout << "WARNING: This will delete credential number " << cn << " for " << service << std::endl; promptConfirm(); creds.erase(creds.begin() + cn); credentials[service] = creds; if (creds.size() == 0) { credentials.erase(service); return true; } return false; } void Keychain::show() { std::cout << "Keychain contains " << credentials.size() << " services." << std::endl; if (credentials.size() > 0) std::cout << std::endl; for (std::map >::iterator it = credentials.begin(); it != credentials.end(); it++) { bool marked = checkResetOne(it->first) != 0; std::cout << it->first << "(" << getServiceCount(it->first) << ")" << (marked ? " ***Marked for Reset***" : "") << std::endl; } } void Keychain::show1(std::string service) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } std::cout << "Keychain contains " << creds.size() << " credentials for " << service << std::endl; std::cout << std::endl; printServiceCreds(creds); } void Keychain::showlike(std::string service) { std::vector servs = getServicesLike(service); if (servs.size() == 0) { std::cerr << "Error: keychain doesn't contain any services like " << service << std::endl; throw false; } std::cout << "Keychain contains " << servs.size() << " services like " << service << std::endl; std::cout << std::endl; for (int i = 0; i < servs.size(); i++) { bool marked = checkResetOne(servs[i]) != 0; std::cout << servs[i] << "(" << getServiceCount(servs[i]) << ")" << (marked ? " ***Marked for Reset***" : "") << std::endl; } } Credential Keychain::get(std::string service) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } if (creds.size() > 1) { std::cerr << "Notice: multiple credentials were found in the keychain for " << service << std::endl; std::cout << "Use the -user or -cn options to specify which credential to return." << std::endl; printServiceCreds(creds); throw false; } return creds[0]; } Credential Keychain::get(std::string service, std::string username) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } int count = getCredsUsernameCount(creds, username); if (count == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << " with username " << username << std::endl; std::cout << "Listing known usernames below..." << std::endl; std::cout << "Use the -user or -cn options to specify which credential to return." << std::endl; printServiceCreds(creds); throw false; } if (count > 1) { std::cerr << "Notice: multiple credentials were found in the keychain for " << service << " with username " << username << std::endl; std::cout << "Use the -cn option to specify which credential to return." << std::endl; printServiceCreds(creds); throw false; } return getCredByUsername(creds, username); } Credential Keychain::get(std::string service, int cn) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } if (cn >= creds.size()) { std::cerr << "Error: credential number is out of bounds for " << service << std::endl; std::cout << "Listing known credentials below..." << std::endl; printServiceCreds(creds); throw false; } return creds[cn]; } int Keychain::markResetAll() { int count = 0; for (std::map >::iterator it = credentials.begin(); it != credentials.end(); it++) { count += markResetOne(it->first); } return count; } int Keychain::markResetOne(std::string service) { std::vector creds = getCreds(service); if (creds.size() == 0) return 0; int count = 0; for (int i = 0; i < creds.size(); i++) { Credential c = creds[i]; if (!c.reset) { c.reset = true; count++; creds[i] = c; } } credentials[service] = creds; return count; } int Keychain::checkResetAll() { int count = 0; for (std::map >::iterator it = credentials.begin(); it != credentials.end(); it++) { count += checkResetOne(it->first); } return count; } int Keychain::checkResetOne(std::string service) { std::vector creds = getCreds(service); int count = 0; for (int i = 0; i < creds.size(); i++) { Credential c = creds[i]; if (c.reset) { count++; } } return count; } Credential Keychain::ruser(std::string service, std::string username) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } if (creds.size() > 1) { std::cerr << "Notice: multiple credentials were found in the keychain for " << service << std::endl; std::cout << "Use the -cn option to specify which credential to modify." << std::endl; printServiceCreds(creds); throw false; } return resetUsername(service, username, 0); } Credential Keychain::ruser(std::string service) { return ruser(service, Cryptor::createRandomPassword(getUsernameSpec())); } Credential Keychain::ruser(std::string service, std::string username, int cn) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } if (cn >= creds.size()) { std::cerr << "Error: credential number is out of bounds for " << service << std::endl; std::cout << "Listing known credentials below..." << std::endl; printServiceCreds(creds); throw false; } return resetUsername(service, username, cn); } Credential Keychain::ruser(std::string service, int cn) { return ruser(service, Cryptor::createRandomPassword(getUsernameSpec()), cn); } Credential Keychain::rpass(std::string service, std::string password) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } if (creds.size() > 1) { std::cerr << "Notice: multiple credentials were found in the keychain for " << service << std::endl; std::cout << "Use the -user or -cn options to specify which credential to modify." << std::endl; printServiceCreds(creds); throw false; } return resetPassword(service, password, 0); } Credential Keychain::rpass(std::string service, PasswordSpec spec) { return rpass(service, Cryptor::createRandomPassword(spec)); } Credential Keychain::rpass(std::string service, std::string password, std::string username) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } int count = getCredsUsernameCount(creds, username); if (count == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << " with username " << username << std::endl; std::cout << "Listing known usernames below..." << std::endl; std::cout << "Use the -user or -cn options to specify which credential to modify." << std::endl; printServiceCreds(creds); throw false; } if (count > 1) { std::cerr << "Notice: multiple credentials were found in the keychain for " << service << " with username " << username << std::endl; std::cout << "Use the -cn option to specify which credential to modify." << std::endl; printServiceCreds(creds); throw false; } int cn = getPosByUsername(creds, username); return resetPassword(service, password, cn); } Credential Keychain::rpass(std::string service, PasswordSpec spec, std::string username) { return rpass(service, Cryptor::createRandomPassword(spec), username); } Credential Keychain::rpass(std::string service, std::string password, int cn) { std::vector creds = getCreds(service); if (creds.size() == 0) { std::cerr << "Error: keychain doesn't contain any credentials for " << service << std::endl; throw false; } if (cn >= creds.size()) { std::cerr << "Error: credential number is out of bounds for " << service << std::endl; std::cout << "Listing known credentials below..." << std::endl; printServiceCreds(creds); throw false; } return resetPassword(service, password, cn); } Credential Keychain::rpass(std::string service, PasswordSpec spec, int cn) { return rpass(service, Cryptor::createRandomPassword(spec), cn); } Credential Keychain::resetUsername(std::string service, std::string username, int cn) { std::cout << "Notice: value of user (" << username << ") is not being used to select a credential, but as the NEW username value." << std::endl; std::cout << "WARNING: Username for " << service << " will be changed." << std::endl; promptConfirm(); std::vector creds = getCreds(service); Credential c = creds[cn]; c.username = username; c.reset = false; creds[cn] = c; credentials[service] = creds; return c; } Credential Keychain::resetPassword(std::string service, std::string password, int cn) { std::cout << "WARNING: Password for " << service << " will be changed." << std::endl; promptConfirm(); std::vector creds = getCreds(service); Credential c = creds[cn]; c.password = password; c.reset = false; creds[cn] = c; credentials[service] = creds; return c; } std::vector Keychain::getCreds(std::string service) { std::vector creds; if (credentials.find(service) != credentials.end()) creds = credentials[service]; return creds; } int Keychain::getCredsUsernameCount(std::vector creds, std::string username) { int count = 0; for (int i = 0; i < creds.size(); i++) { if (creds[i].username == username) count++; } return count; } Credential Keychain::getCredByUsername(std::vector creds, std::string username) { for (int i = 0; i < creds.size(); i++) { if (creds[i].username == username) return creds[i]; } throw 1; } int Keychain::getPosByUsername(std::vector creds, std::string username) { for (int i = 0; i < creds.size(); i++) { if (creds[i].username == username) return i; } throw 1; } void Keychain::printServiceCreds(std::vector creds) { for (int i = 0; i < creds.size(); i++) { std::cout << "[#" << i << "] " << creds[i].username << (creds[i].reset ? " ***Marked for Reset***" : "") << std::endl; } } void Keychain::promptConfirm() { std::cout << "Continue? [y/n]: "; char c; std::cin.ignore(); std::cin >> c; if (c != 'y' && c != 'Y') { std::cerr << "Notice: aborted." << std::endl; throw false; } } std::vector Keychain::getServicesLike(std::string service) { std::vector rtr; std::string service_lower; for (int i = 0; i < service.size(); i++) service_lower += tolower(service[i]); for (std::map >::iterator it = credentials.begin(); it != credentials.end(); it++) { std::string currServ = it->first; std::string currServ_lower; for (int i = 0; i < currServ.size(); i++) currServ_lower += tolower(currServ[i]); if (currServ_lower.find(service_lower) != std::string::npos) rtr.push_back(currServ); else if (service_lower.find(currServ_lower) != std::string::npos) rtr.push_back(currServ); } return rtr; } PasswordSpec Keychain::getUsernameSpec() { PasswordSpec unamespec; unamespec.ml = 10; unamespec.ns = true; unamespec.nc = true; unamespec.nn = true; return unamespec; }