diff options
Diffstat (limited to 'Keychain.cpp')
-rw-r--r-- | Keychain.cpp | 627 |
1 files changed, 627 insertions, 0 deletions
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<Credential> 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<std::string, std::vector<Credential> >::iterator it = credentials.begin(); it != credentials.end(); it++) {
+ std::string serviceName = it->first;
+ std::vector<Credential> 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<std::string, std::vector<Credential> >::iterator it = credentials.begin(); it != credentials.end(); it++) {
+ std::cout << "[[#" << (i++) << "]] " << it->first << std::endl;
+
+ std::vector<Credential> 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<Credential> creds = getCreds(service);
+ return creds.size();
+}
+
+Credential Keychain::create(std::string service, std::string username, std::string password) {
+ std::vector<Credential> 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<Credential> 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<Credential> 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<Credential> 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<std::string, std::vector<Credential> >::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<Credential> 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<std::string> 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<Credential> 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<Credential> 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<Credential> 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<std::string, std::vector<Credential> >::iterator it = credentials.begin(); it != credentials.end(); it++) {
+ count += markResetOne(it->first);
+ }
+
+ return count;
+}
+
+int Keychain::markResetOne(std::string service) {
+ std::vector<Credential> 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<std::string, std::vector<Credential> >::iterator it = credentials.begin(); it != credentials.end(); it++) {
+ count += checkResetOne(it->first);
+ }
+
+ return count;
+}
+
+int Keychain::checkResetOne(std::string service) {
+ std::vector<Credential> 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<Credential> 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<Credential> 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<Credential> 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<Credential> 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<Credential> 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<Credential> 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<Credential> creds = getCreds(service);
+
+ Credential c = creds[cn];
+ c.password = password;
+ c.reset = false;
+ creds[cn] = c;
+
+ credentials[service] = creds;
+
+ return c;
+}
+
+std::vector<Credential> Keychain::getCreds(std::string service) {
+ std::vector<Credential> creds;
+
+ if (credentials.find(service) != credentials.end())
+ creds = credentials[service];
+
+ return creds;
+}
+
+int Keychain::getCredsUsernameCount(std::vector<Credential> 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<Credential> 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<Credential> 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<Credential> 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<std::string> Keychain::getServicesLike(std::string service) {
+ std::vector<std::string> rtr;
+ std::string service_lower;
+
+ for (int i = 0; i < service.size(); i++)
+ service_lower += tolower(service[i]);
+
+ for (std::map<std::string, std::vector<Credential> >::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;
+}
|