Blame crypt.cpp

c47604
0f653b
#include <cassert></cassert>
0f653b
0f653b
#include <cryptopp osrng.h=""></cryptopp>
0f653b
#include <cryptopp sha3.h=""></cryptopp>
0f653b
#include <cryptopp modes.h=""></cryptopp>
0f653b
#include <cryptopp threefish.h=""></cryptopp>
0f653b
0f653b
0f653b
#include "crypt.h"
0f653b
0f653b
0f653b
0f653b
class Crypt::Private {
0f653b
public:
0f653b
	Crypt &crypt;
0f653b
	unsigned char key[CRYPT_BLOCK];
0f653b
	unsigned char iv[2][CRYPT_BLOCK];
0f653b
	Time tq[2];
0f653b
	
0f653b
	CryptoPP::DefaultAutoSeededRNG random;
0f653b
	CryptoPP::SHA3_256 hasher;
0f653b
	CryptoPP::CBC_Mode<cryptopp::threefish1024>::Encryption enc;</cryptopp::threefish1024>
0f653b
	CryptoPP::CBC_Mode<cryptopp::threefish1024>::Decryption dec;</cryptopp::threefish1024>
0f653b
	
0f653b
	inline Private(Crypt &crypt):
0f653b
		crypt(crypt), key(), iv(), tq() { }
0f653b
	
24937f
	inline ~Private() {
24937f
		memset(key, 0, sizeof(key));
24937f
		memset(iv, 0, sizeof(iv));
24937f
		memset(tq, 0, sizeof(tq));
24937f
	}
24937f
	
0f653b
	inline void setTimeQwant(Time timeQwant, int index) {
0f653b
		if (tq[index] == timeQwant) return;
0f653b
		tq[index] = timeQwant;
0f653b
		for(unsigned char *e = iv[index], *c = e + CRYPT_BLOCK - 1; c >= e; --c)
0f653b
			{ *c = timeQwant & 0xff; timeQwant >>= 8; }
0f653b
	}
0f653b
	
0f653b
	inline bool hash256(const unsigned char *src, int srcSize, unsigned char *dst) {
0f653b
		try {
0f653b
			hasher.Restart();
0f653b
			hasher.CalculateDigest(dst, src, srcSize);
0f653b
			return true;
0f653b
		} catch(...) { }
0f653b
		return false;
0f653b
	}
0f653b
	
0f653b
	inline bool encrypt(const unsigned char *src, unsigned char *dst, int size) {
0f653b
		try {
0f653b
			enc.SetKeyWithIV(key, CRYPT_BLOCK, iv[0]);
0f653b
			enc.ProcessData(dst, src, size);
0f653b
			return true;
0f653b
		} catch(...) { }
0f653b
		return false;
0f653b
	}
0f653b
	
0f653b
	inline bool decrypt(const unsigned char *src, unsigned char *dst, int size, int index) {
0f653b
		try {
0f653b
			dec.SetKeyWithIV(key, CRYPT_BLOCK, iv[index]);
0f653b
			dec.ProcessData(dst, src, size);
0f653b
			return true;
0f653b
		} catch(...) { }
0f653b
		return false;
0f653b
	}
0f653b
};
0f653b
0f653b
0f653b
0f653b
0f653b
Crypt::Crypt():
0f653b
	priv(new Private(*this)) { }
0f653b
0f653b
0f653b
Crypt::~Crypt()
0f653b
	{ resetKey(); delete priv; priv = nullptr; }
0f653b
0f653b
0f653b
unsigned int Crypt::random()
0f653b
	{ return priv->random.GenerateWord32(); }
0f653b
0f653b
0f653b
bool Crypt::setKey(const char *key) {
0f653b
	static_assert(CRYPT_BLOCK % HASH_SIZE == 0);
0f653b
	static_assert(CRYPT_BLOCK > HASH_SIZE);
0f653b
	
0f653b
	static const char salt[] = "dnmnfhne78hj0fklf2891ve";
0f653b
	const int count = CRYPT_BLOCK;
0f653b
	try {
0f653b
		priv->hasher.Restart();
0f653b
		priv->hasher.Update((const unsigned char*)salt, sizeof(salt));
0f653b
		priv->hasher.Update((const unsigned char*)key, strlen(key));
0f653b
		priv->hasher.Final(priv->key);
0f653b
		for(int i = 1; i < count; ++i) {
0f653b
			priv->hasher.Restart();
0f653b
			priv->hasher.CalculateDigest(priv->key + i*HASH_SIZE, priv->key + (i - 1)*HASH_SIZE, HASH_SIZE);
0f653b
		}
0f653b
		return true;
0f653b
	} catch(...) { }
0f653b
	return false;
0f653b
}
0f653b
0f653b
0f653b
void Crypt::resetKey()
0f653b
	{ memset(priv->key, 0, sizeof(priv->key)); }
0f653b
0f653b
0f653b
void Crypt::setTime(Time time, Time qwant) {
0f653b
	Time hq = qwant/2;
0f653b
	time -= hq;
0f653b
	Time tq = time/qwant;
0f653b
	if (time % qwant < hq) {
0f653b
		priv->setTimeQwant(tq,     0);
0f653b
		priv->setTimeQwant(tq + 1, 1);
0f653b
	} else {
0f653b
		priv->setTimeQwant(tq + 1, 1);
0f653b
		priv->setTimeQwant(tq,     0);
0f653b
	}
0f653b
}
0f653b
0f653b
0f653b
bool Crypt::encrypt(const void *src, int srcSize, void *dst, int &dstSize) {
0f653b
	int ds = dstSize;
0f653b
	dstSize = 0;
0f653b
	if (!srcSize) return true;
0f653b
	if (!src) return false;
0f653b
	
0f653b
	int count = (srcSize + HASH_SIZE - 1)/CRYPT_BLOCK + 1;
0f653b
	int size = count*CRYPT_BLOCK;
0f653b
	if (ds < size) return false;
0f653b
	if (size > CRYPT_PACKET_SIZE) return false;
0f653b
0f653b
	unsigned char data[CRYPT_PACKET_SIZE] = {};
0f653b
	memcpy(data + HASH_SIZE, src, srcSize);
0f653b
	static_assert(HASH_SIZE == 256/8);
0f653b
	if ( !priv->hash256(data + HASH_SIZE, size - 8, data)
0f653b
	  || !priv->encrypt(data, (unsigned char*)dst, size) )
0f653b
		return false;
0f653b
	
0f653b
	dstSize = size;
0f653b
	return true;
0f653b
}
0f653b
0f653b
0f653b
bool Crypt::decrypt(const void *src, int srcSize, void *dst, int &dstSize) {
0f653b
	int ds = dstSize;
0f653b
	dstSize = 0;
0f653b
	if (!srcSize) return true;
0f653b
	if (!src) return false;
0f653b
	if (srcSize % CRYPT_BLOCK) return false;
0f653b
	
0f653b
	int count = srcSize/CRYPT_BLOCK;
0f653b
	int size = count*CRYPT_BLOCK;
0f653b
	if (ds < size - HASH_SIZE) return false;
0f653b
	if (size > CRYPT_PACKET_SIZE) return false;
0f653b
	ds = size - HASH_SIZE;
0f653b
	
0f653b
	unsigned char hash[2][HASH_SIZE] = {};
0f653b
	unsigned char data[2][CRYPT_PACKET_SIZE] = {};
0f653b
	bool valid[2] = {};
0f653b
	for(int i = 0; i < 2; ++i) {
0f653b
		static_assert(HASH_SIZE == 256/8);
0f653b
		if ( !priv->decrypt((unsigned char*)src, data[i], size, i)
0f653b
		  || !priv->hash256(data[i] + HASH_SIZE, size - 8, hash[i]) ) return false;
0f653b
		valid[i] = 0 == memcmp(hash, data[i], HASH_SIZE);
0f653b
	}
0f653b
	
0f653b
	if (valid[0]) memcpy(dst, data[0] + HASH_SIZE, ds); else
0f653b
	if (valid[1]) memcpy(dst, data[1] + HASH_SIZE, ds); else
0f653b
				  return false;
0f653b
	
0f653b
	dstSize = size - HASH_SIZE;
0f653b
	return true;
0f653b
}
0f653b