#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<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(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;
}