#include "Cryptor.h" bool Cryptor::haveKey = false; unsigned char Cryptor::key[CryptoPP::AES::DEFAULT_KEYLENGTH]; void Cryptor::encryptAndSave(std::string remoteHost, std::string port, std::string directory, std::string payload) { // Key if (!haveKey) assembleKey(true); // IV unsigned char iv[CryptoPP::AES::BLOCKSIZE]; CryptoPP::AutoSeededRandomPool randl; randl.GenerateBlock(iv, sizeof(iv)); // Encrypt std::string cipher; CryptoPP::CBC_Mode::Encryption enc(key, sizeof(key), iv); CryptoPP::StringSource(payload, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::StringSink(cipher))); // Save Data std::string encIV, encCipher; CryptoPP::StringSource(iv, sizeof(iv), true, new CryptoPP::HexEncoder(new CryptoPP::StringSink(encIV))); CryptoPP::StringSource(cipher, true, new CryptoPP::HexEncoder(new CryptoPP::StringSink(encCipher))); if (remoteHost == "") { if (directory[directory.size() - 1] != '/') directory += "/"; directory += KEYCHAIN_FILE; std::ofstream f(directory.c_str()); f << encIV << std::endl; f << encCipher << std::endl; f.close(); } else { Socket s; std::string err = ""; s.conn(remoteHost, port); s.sendline("store"); s.sendline(directory); s.sendline(encIV); s.sendline(encCipher); err = s.readline(); s.clo(); if (err != "OK") throw 1; } } std::string Cryptor::loadAndDecrypt(std::string remoteHost, std::string port, std::string directory) { // Load Data std::string encIV, encCipher, ivstr, cipher; if (remoteHost == "") { if (directory[directory.size() - 1] != '/') directory += "/"; directory += KEYCHAIN_FILE; std::ifstream f(directory.c_str()); if (!f.good()) { f.close(); throw 1; } f >> encIV; f >> encCipher; f.close(); } else { Socket s; std::string err = ""; s.conn(remoteHost, port); s.sendline("fetch"); s.sendline(directory); err = s.readline(); if (err != "OK") { s.clo(); throw 1; } encIV = s.readline(); encCipher = s.readline(); s.clo(); } CryptoPP::StringSource(encIV, true, new CryptoPP::HexDecoder(new CryptoPP::StringSink(ivstr))); CryptoPP::StringSource(encCipher, true, new CryptoPP::HexDecoder(new CryptoPP::StringSink(cipher))); // Key if (!haveKey) assembleKey(); // IV unsigned char iv[CryptoPP::AES::BLOCKSIZE]; memcpy(iv, ivstr.c_str(), ivstr.size()); // Decrypt std::string payload; CryptoPP::CBC_Mode::Decryption dec(key, sizeof(key), iv); CryptoPP::StringSource(cipher, true, new CryptoPP::StreamTransformationFilter(dec, new CryptoPP::StringSink(payload))); return payload; } std::string Cryptor::createRandomPassword(PasswordSpec spec) { CryptoPP::AutoSeededRandomPool randl; std::string password; std::vector validChars; // Always allow lower-case alphabetic characters for (int i = 0; i < 26; i++) validChars.push_back('a' + i); // Allow special chars? if (!spec.ns) { validChars.push_back('`'); validChars.push_back('~'); validChars.push_back('!'); validChars.push_back('@'); validChars.push_back('#'); validChars.push_back('$'); validChars.push_back('%'); validChars.push_back('^'); validChars.push_back('&'); validChars.push_back('*'); validChars.push_back('('); validChars.push_back(')'); validChars.push_back('-'); validChars.push_back('_'); validChars.push_back('='); validChars.push_back('+'); validChars.push_back('['); validChars.push_back('{'); validChars.push_back(']'); validChars.push_back('}'); validChars.push_back('\\'); validChars.push_back('|'); validChars.push_back(';'); validChars.push_back(':'); validChars.push_back(','); validChars.push_back('<'); validChars.push_back('.'); validChars.push_back('>'); validChars.push_back('/'); validChars.push_back('?'); } // Allow capital letters? if (!spec.nc) { for (int i = 0; i < 26; i++) validChars.push_back('A' + i); } // Allow numbers? if (!spec.nn) { for (int i = 0; i < 10; i++) validChars.push_back('0' + i); } // Build string for (int i = 0; i < spec.ml; i++) { unsigned char r[1]; char c; randl.GenerateBlock(r, sizeof(r)); c = validChars[r[0] % validChars.size()]; password += c; } return password; } void Cryptor::rekey() { haveKey = false; } void Cryptor::sha256(std::string str) { CryptoPP::SHA256 hash; std::string rtr; CryptoPP::StringSource(str, true, new CryptoPP::HashFilter(hash, new CryptoPP::StringSink(rtr), false, CryptoPP::AES::DEFAULT_KEYLENGTH)); memcpy(key, rtr.c_str(), rtr.size()); haveKey = true; } std::string Cryptor::readPassword(bool confirm) { std::string password; #ifdef WIN32 HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE); DWORD mode = 0; GetConsoleMode(hstdin, &mode); SetConsoleMode(hstdin, mode & ~ENABLE_ECHO_INPUT); password = promptPassword(confirm); SetConsoleMode(hstdin, mode); #else termios oldt; tcgetattr(STDIN_FILENO, &oldt); termios newt = oldt; newt.c_lflag &= ~ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &newt); password = promptPassword(confirm); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); #endif // WIN32 return password; } std::string Cryptor::readPassword() { return readPassword(false); } void Cryptor::assembleKey(bool confirm) { sha256(readPassword(confirm)); } void Cryptor::assembleKey() { assembleKey(false); } std::string Cryptor::promptPassword(bool confirm) { std::string password; while (true) { std::cout << PASSWORD_PROMPT; std::cin >> password; std::cout << std::endl; if (confirm) { std::string conf; std::cout << PASSWORD_CONF; std::cin >> conf; std::cout << std::endl; if (password == conf) break; else std::cout << PASSWORD_ERROR << std::endl; } else break; } return password; }