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