From 0f653b9fc3bc86a3b77c0977b6e1493a78030cb0 Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Oct 25 2021 11:28:04 +0000 Subject: crypt --- diff --git a/.gitignore b/.gitignore index 620e5b9..fc44ca9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.kdev4 /icetunnel2-debug /icetunnel2 +/deps/ diff --git a/build.sh b/build.sh index 0cf839d..58759c0 100755 --- a/build.sh +++ b/build.sh @@ -2,10 +2,12 @@ set -e +OPTS="-Ideps -Ldeps/cryptopp -lcryptopp" + if [ "$1" = "debug" ]; then - c++ -Wall -g -O0 *.cpp -o icetunnel2-debug + c++ -Wall -g -O0 *.cpp $OPTS -o icetunnel2-debug else - c++ -Wall -DNDEBUG -O3 *.cpp -o icetunnel2 + c++ -Wall -DNDEBUG -O3 *.cpp $OPTS -o icetunnel2 fi diff --git a/common.h b/common.h index e72b161..206c19a 100644 --- a/common.h +++ b/common.h @@ -3,10 +3,11 @@ enum { - PACKET_SIZE = 502, + PACKET_SIZE = 470, PACKETS_COUNT = 8*PACKET_SIZE, TCP_BUFFER_SIZE = PACKET_SIZE*PACKETS_COUNT, CRYPT_BLOCK = 128, + HASH_SIZE = 32, }; @@ -67,8 +68,6 @@ public: : other.address < address ? false : id < other.id; } - - static unsigned int generateId(); }; @@ -103,7 +102,7 @@ struct __attribute__((__packed__)) Packet { enum { FULL_PACKET_SIZE = sizeof(Packet), HEADER_SIZE = FULL_PACKET_SIZE - PACKET_SIZE, - CRYPT_PACKET_SIZE = ((FULL_PACKET_SIZE - 1)/CRYPT_BLOCK + 1)*CRYPT_BLOCK, + CRYPT_PACKET_SIZE = ((FULL_PACKET_SIZE + HASH_SIZE - 1)/CRYPT_BLOCK + 1)*CRYPT_BLOCK, }; diff --git a/crypt.cpp b/crypt.cpp index 8b13789..4aa98fa 100644 --- a/crypt.cpp +++ b/crypt.cpp @@ -1 +1,171 @@ +#include + +#include +#include +#include +#include + + +#include "crypt.h" + + + +class Crypt::Private { +public: + Crypt &crypt; + unsigned char key[CRYPT_BLOCK]; + unsigned char iv[2][CRYPT_BLOCK]; + Time tq[2]; + + CryptoPP::DefaultAutoSeededRNG random; + CryptoPP::SHA3_256 hasher; + CryptoPP::CBC_Mode::Encryption enc; + CryptoPP::CBC_Mode::Decryption dec; + + inline Private(Crypt &crypt): + crypt(crypt), key(), iv(), tq() { } + + inline void setTimeQwant(Time timeQwant, int index) { + if (tq[index] == timeQwant) return; + tq[index] = timeQwant; + for(unsigned char *e = iv[index], *c = e + CRYPT_BLOCK - 1; c >= e; --c) + { *c = timeQwant & 0xff; timeQwant >>= 8; } + } + + inline bool hash256(const unsigned char *src, int srcSize, unsigned char *dst) { + try { + hasher.Restart(); + hasher.CalculateDigest(dst, src, srcSize); + return true; + } catch(...) { } + return false; + } + + inline bool encrypt(const unsigned char *src, unsigned char *dst, int size) { + try { + enc.SetKeyWithIV(key, CRYPT_BLOCK, iv[0]); + enc.ProcessData(dst, src, size); + return true; + } catch(...) { } + return false; + } + + inline bool decrypt(const unsigned char *src, unsigned char *dst, int size, int index) { + try { + dec.SetKeyWithIV(key, CRYPT_BLOCK, iv[index]); + dec.ProcessData(dst, src, size); + return true; + } catch(...) { } + return false; + } +}; + + + + +Crypt::Crypt(): + priv(new Private(*this)) { } + + +Crypt::~Crypt() + { resetKey(); delete priv; priv = nullptr; } + + +unsigned int Crypt::random() + { return priv->random.GenerateWord32(); } + + +bool Crypt::setKey(const char *key) { + static_assert(CRYPT_BLOCK % HASH_SIZE == 0); + static_assert(CRYPT_BLOCK > HASH_SIZE); + + static const char salt[] = "dnmnfhne78hj0fklf2891ve"; + const int count = CRYPT_BLOCK; + try { + priv->hasher.Restart(); + priv->hasher.Update((const unsigned char*)salt, sizeof(salt)); + priv->hasher.Update((const unsigned char*)key, strlen(key)); + priv->hasher.Final(priv->key); + for(int i = 1; i < count; ++i) { + priv->hasher.Restart(); + priv->hasher.CalculateDigest(priv->key + i*HASH_SIZE, priv->key + (i - 1)*HASH_SIZE, HASH_SIZE); + } + return true; + } catch(...) { } + return false; +} + + +void Crypt::resetKey() + { memset(priv->key, 0, sizeof(priv->key)); } + + +void Crypt::setTime(Time time, Time qwant) { + Time hq = qwant/2; + time -= hq; + Time tq = time/qwant; + if (time % qwant < hq) { + priv->setTimeQwant(tq, 0); + priv->setTimeQwant(tq + 1, 1); + } else { + priv->setTimeQwant(tq + 1, 1); + priv->setTimeQwant(tq, 0); + } +} + + +bool Crypt::encrypt(const void *src, int srcSize, void *dst, int &dstSize) { + int ds = dstSize; + dstSize = 0; + if (!srcSize) return true; + if (!src) return false; + + int count = (srcSize + HASH_SIZE - 1)/CRYPT_BLOCK + 1; + int size = count*CRYPT_BLOCK; + if (ds < size) return false; + if (size > CRYPT_PACKET_SIZE) return false; + + unsigned char data[CRYPT_PACKET_SIZE] = {}; + memcpy(data + HASH_SIZE, src, srcSize); + static_assert(HASH_SIZE == 256/8); + if ( !priv->hash256(data + HASH_SIZE, size - 8, data) + || !priv->encrypt(data, (unsigned char*)dst, size) ) + return false; + + dstSize = size; + return true; +} + + +bool Crypt::decrypt(const void *src, int srcSize, void *dst, int &dstSize) { + int ds = dstSize; + dstSize = 0; + if (!srcSize) return true; + if (!src) return false; + if (srcSize % CRYPT_BLOCK) return false; + + int count = srcSize/CRYPT_BLOCK; + int size = count*CRYPT_BLOCK; + if (ds < size - HASH_SIZE) return false; + if (size > CRYPT_PACKET_SIZE) return false; + ds = size - HASH_SIZE; + + unsigned char hash[2][HASH_SIZE] = {}; + unsigned char data[2][CRYPT_PACKET_SIZE] = {}; + bool valid[2] = {}; + for(int i = 0; i < 2; ++i) { + static_assert(HASH_SIZE == 256/8); + if ( !priv->decrypt((unsigned char*)src, data[i], size, i) + || !priv->hash256(data[i] + HASH_SIZE, size - 8, hash[i]) ) return false; + valid[i] = 0 == memcmp(hash, data[i], HASH_SIZE); + } + + if (valid[0]) memcpy(dst, data[0] + HASH_SIZE, ds); else + if (valid[1]) memcpy(dst, data[1] + HASH_SIZE, ds); else + return false; + + dstSize = size - HASH_SIZE; + return true; +} + diff --git a/crypt.h b/crypt.h index a2d71e6..2d7f329 100644 --- a/crypt.h +++ b/crypt.h @@ -10,8 +10,8 @@ class Crypt { private: - Time time; - std::vector keyData; + class Private; + Private *priv; public: Crypt(); @@ -20,10 +20,12 @@ public: bool setKey(const char *key); void resetKey(); - void setTime(Time time); + void setTime(Time time, Time qwant); bool encrypt(const void *src, int srcSize, void *dst, int &dstSize); bool decrypt(const void *src, int srcSize, void *dst, int &dstSize); + + unsigned int random(); }; diff --git a/tunnel.cpp b/tunnel.cpp index 7323dbb..7647eda 100644 --- a/tunnel.cpp +++ b/tunnel.cpp @@ -14,6 +14,7 @@ Tunnel::Tunnel(): udpConfirmDuration(udpResendDuration/8), udpSilenceDuration(300000000), udpKeepAliveDuration(udpSilenceDuration/32), + timeQwant(1200000000), pollDuration(5000000), udpSockId(-1), tcpSockId(-1), @@ -202,7 +203,7 @@ bool Tunnel::iteration() { // wait for events poll.wait(pollTime); time = monotonicTime(); - crypt.setTime(time); + crypt.setTime(time, timeQwant); if (poll.list[0].closed || (tcpSockId >= 0 && poll.list[1].closed)) { poll.list.clear(); @@ -220,7 +221,7 @@ bool Tunnel::iteration() { if (sockId >= 0) { ConnId id; id.address = remoteUdpAddress; - id.id = ConnId::generateId(); + id.id = crypt.random(); Connection &conn = connections.emplace(id, Connection::Args(*this, id, tcpSockId)).first->second; conn.tcpRecvQueue.readFromTcp(); } diff --git a/tunnel.h b/tunnel.h index 2e36a7c..bd03119 100644 --- a/tunnel.h +++ b/tunnel.h @@ -25,6 +25,7 @@ public: Time udpConfirmDuration; Time udpSilenceDuration; Time udpKeepAliveDuration; + Time timeQwant; Time pollDuration; ConnMap connections;