summaryrefslogblamecommitdiffstats
path: root/Cryptor.cpp
blob: 25a2ae9ece4a7133cb71202095ef745cb12fe79a (plain) (tree)
1
2
3


                               






















                                                                       


                                                                                                                     
                        
                                   
          

              

                                            

                   












                                                                                                             

                     









                                                             
                                


                                                              

                                                    

                                              
                           
                 




                                          

                                        

                                    


                                   




                                                                                                       
                                      
                                


                                                              








                                                    
                 













                                          





                                                                             

               
                        
                               
          

                   

















                                                                                                             













































































                                                               


                                                                                    


                        











                                                                                 



































































                                                                          
#include "Cryptor.h"

bool Cryptor::haveKey = false;
unsigned char Cryptor::key[AES_BLOCK_LENGTH];

static void toHex(char *output, const void *input, size_t size) {
	const unsigned char *_input = (const unsigned char *)input;
	for (size_t i = 0; i < size; i++) {
		sprintf(output+(i*2), "%02hhX", _input[i]);
	}
}

static void fromHex(void *output, const char *input) {
	unsigned char *_output = (unsigned char *)output;
	size_t size = strlen(input);
	if (size & 1) {
		throw 1;
	} else {
		size /= 2;
	}
	for (size_t i = 0; i < size; i++) {
		if (sscanf(input+(i*2), "%02hhx", &_output[i]) != 1) {
			throw 1;
		}
	}
}

void Cryptor::encryptAndSave(std::string remoteHost, std::string port, std::string directory, std::string payload) {
	// Key
	if (!haveKey) {
		assembleKey(true);
	}

	// IV
	unsigned char iv[AES_BLOCK_LENGTH];
	generateRandom(iv, sizeof(iv));

	// Encrypt
	size_t ciphertextLen = 0;
	unsigned char *ciphertext = new unsigned char[payload.size() + 64];
	const mbedtls_cipher_info_t *cipherInfo = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CBC);
	mbedtls_cipher_context_t cipher;

	mbedtls_cipher_init(&cipher);
	mbedtls_cipher_setup(&cipher, cipherInfo);
	mbedtls_cipher_setkey(&cipher, key, sizeof(key)*8, MBEDTLS_ENCRYPT);
	mbedtls_cipher_set_padding_mode(&cipher, MBEDTLS_PADDING_PKCS7);
	mbedtls_cipher_crypt(&cipher, iv, sizeof(iv),
			(const unsigned char *)payload.c_str(), payload.size(),
			ciphertext, &ciphertextLen);
	mbedtls_cipher_free(&cipher);

	// Save Data
	char encIV[(AES_BLOCK_LENGTH * 2) + 1];
	char *encCipher = new char[(ciphertextLen * 2) + 1];
	toHex(encIV, iv, sizeof(iv));
	toHex(encCipher, ciphertext, ciphertextLen);
	std::string _encIV(encIV);
	std::string _encCipher(encCipher);

	delete[] encCipher;
	delete[] ciphertext;

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

	// Decode data
	unsigned char *ciphertext = new unsigned char[encCipher.size() / 2];
	unsigned char iv[AES_BLOCK_LENGTH];
	fromHex(ciphertext, encCipher.c_str());
	fromHex(iv, encIV.c_str());

	// Key
	if (!haveKey) {
		assembleKey();
	}

	// Decrypt
	size_t plaintextLen = 0;
	char *plaintext = new char[(encCipher.size() / 2) + 64];
	const mbedtls_cipher_info_t *cipherInfo = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CBC);
	mbedtls_cipher_context_t cipher;

	mbedtls_cipher_init(&cipher);
	mbedtls_cipher_setup(&cipher, cipherInfo);
	mbedtls_cipher_setkey(&cipher, key, sizeof(key)*8, MBEDTLS_DECRYPT);
	mbedtls_cipher_set_padding_mode(&cipher, MBEDTLS_PADDING_PKCS7);
	mbedtls_cipher_crypt(&cipher, iv, sizeof(iv),
			ciphertext, (encCipher.size() / 2),
			(unsigned char *)plaintext, &plaintextLen);
	mbedtls_cipher_free(&cipher);

	std::string payload(plaintext, plaintextLen);

	delete[] plaintext;
	delete[] ciphertext;

	return payload;
}

std::string Cryptor::createRandomPassword(PasswordSpec spec) {
	CryptoPP::AutoSeededRandomPool randl;
	std::string password;

	std::vector<char> 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) {
	unsigned char hashbuf[32];
	mbedtls_sha256((const unsigned char *)str.c_str(), str.size(), hashbuf, 0);
	memcpy(key, hashbuf, sizeof(key));
	haveKey = true;
}

void Cryptor::generateRandom(void *output, size_t size) {
	mbedtls_entropy_context entropy;
	mbedtls_ctr_drbg_context random;

	mbedtls_entropy_init(&entropy);
	mbedtls_ctr_drbg_init(&random);
	mbedtls_ctr_drbg_seed(&random, mbedtls_entropy_func, &entropy, NULL, 0);
	mbedtls_ctr_drbg_random(&random, (unsigned char *)output, size);
	mbedtls_ctr_drbg_free(&random);
	mbedtls_entropy_free(&entropy);
}

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