From 490d36e65ac24e34e3021c2a0947384aee138c88 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Wed, 13 Apr 2016 21:05:14 -0400 Subject: Root commit for new Compass repository This is the Alpha version of ComPASS, originally developed sometime in 2014. --- Keychain.cpp | 627 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 Keychain.cpp (limited to 'Keychain.cpp') diff --git a/Keychain.cpp b/Keychain.cpp new file mode 100644 index 0000000..8e017eb --- /dev/null +++ b/Keychain.cpp @@ -0,0 +1,627 @@ +#include "Keychain.h" + +Keychain::Keychain(std::string remoteHost, std::string port, std::string directory) { + this->remoteHost = remoteHost; + this->port = port; + this->directory = directory; +} + +Keychain::~Keychain() { +} + +Keychain* Keychain::newKeychain(std::string directory) { + Keychain* kc = new Keychain("", "", directory); + return kc; +} + +Keychain* Keychain::loadKeychain(std::string remoteHost, std::string port, std::string directory) { + std::string data = Cryptor::loadAndDecrypt(remoteHost, port, directory); + std::istringstream datstr(data); + + Keychain* kc = new Keychain(remoteHost, port, 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(remoteHost, port, 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; +} -- cgit v1.2.3