105 lines
3.9 KiB
C++
105 lines
3.9 KiB
C++
// net_classic_cipher_test — 40250 _IMPROVED_PACKET_ENCRYPTION_ end to end,
|
|
// no socket: a client-polarity ClassicCipher and a server-polarity one run the
|
|
// DH2 key agreement against each other, then encrypt/decrypt must round-trip
|
|
// symmetrically (client.encrypt -> server.decrypt and vice versa).
|
|
#include "../src/net/classic/classic_cipher.h"
|
|
#include "../src/net/classic/wire_classic.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace mtnet::classic;
|
|
|
|
static int g_fail = 0;
|
|
#define CHECK(c, msg) \
|
|
do { \
|
|
if (!(c)) { \
|
|
std::fprintf(stderr, "FAIL: %s\n", msg); \
|
|
++g_fail; \
|
|
} \
|
|
} while (0)
|
|
|
|
int main() {
|
|
ClassicCipher client; // polarity = true (EterLib/NetStream.cpp:3004)
|
|
ClassicCipher server; // polarity = false (desc.cpp FinishHandshake)
|
|
|
|
// Each side generates its DH2 public blob (spub || epub).
|
|
uint8_t cbuf[KEY_AGREEMENT_MAX_DATA_LEN];
|
|
uint8_t sbuf[KEY_AGREEMENT_MAX_DATA_LEN];
|
|
size_t clen = sizeof(cbuf);
|
|
size_t slen = sizeof(sbuf);
|
|
size_t cagreed = client.prepare(cbuf, &clen);
|
|
size_t sagreed = server.prepare(sbuf, &slen);
|
|
|
|
CHECK(cagreed != 0, "client prepare -> non-zero agreed length");
|
|
CHECK(sagreed != 0, "server prepare -> non-zero agreed length");
|
|
CHECK(cagreed == sagreed, "both sides same agreed-value length (same DH2 params)");
|
|
CHECK(clen > 0 && clen <= KEY_AGREEMENT_MAX_DATA_LEN, "client blob length sane");
|
|
CHECK(clen == slen, "blob lengths match");
|
|
|
|
// Activate: each consumes the PEER's (agreed_length, blob).
|
|
bool ca = client.activate(true, sagreed, sbuf, slen);
|
|
bool sa = server.activate(false, cagreed, cbuf, clen);
|
|
CHECK(ca, "client activate");
|
|
CHECK(sa, "server activate");
|
|
CHECK(client.key_ready() && server.key_ready(), "both have encoder+decoder");
|
|
|
|
// The stream turns real only after GC_KEY_AGREEMENT_COMPLETED.
|
|
CHECK(!client.activated(), "cipher not 'activated' until set_activated");
|
|
client.set_activated(true);
|
|
server.set_activated(true);
|
|
|
|
// --- round trip: client -> server ---
|
|
{
|
|
std::string plain = "the quick brown fox CG_MOVE \x07\x01\x00\x00 jumps";
|
|
std::vector<uint8_t> buf(plain.begin(), plain.end());
|
|
std::vector<uint8_t> orig = buf;
|
|
client.encrypt(buf.data(), buf.size());
|
|
CHECK(buf != orig, "ciphertext differs from plaintext");
|
|
server.decrypt(buf.data(), buf.size());
|
|
CHECK(buf == orig, "server recovers client's plaintext");
|
|
}
|
|
|
|
// --- round trip: server -> client, and CTR keystream continuity ---
|
|
{
|
|
std::string a = "GC_MAIN_CHARACTER hello world 0123456789";
|
|
std::string b = "second chunk keeps the CTR counter advancing";
|
|
std::vector<uint8_t> ba(a.begin(), a.end()), bb(b.begin(), b.end());
|
|
std::vector<uint8_t> oa = ba, ob = bb;
|
|
server.encrypt(ba.data(), ba.size());
|
|
server.encrypt(bb.data(), bb.size());
|
|
client.decrypt(ba.data(), ba.size());
|
|
client.decrypt(bb.data(), bb.size());
|
|
CHECK(ba == oa && bb == ob, "client recovers server's two chunks (CTR continuity)");
|
|
}
|
|
|
|
// --- a fresh pair must derive a *different* key (ephemeral) ---
|
|
{
|
|
ClassicCipher c2, s2;
|
|
uint8_t x[256], y[256];
|
|
size_t xl = sizeof(x), yl = sizeof(y);
|
|
size_t xa = c2.prepare(x, &xl);
|
|
size_t ya = s2.prepare(y, &yl);
|
|
c2.activate(true, ya, y, yl);
|
|
s2.activate(false, xa, x, xl);
|
|
c2.set_activated(true);
|
|
s2.set_activated(true);
|
|
|
|
std::string msg = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; // 32 identical bytes
|
|
std::vector<uint8_t> p1(msg.begin(), msg.end());
|
|
std::vector<uint8_t> p2 = p1;
|
|
client.encrypt(p1.data(), p1.size()); // from the first session (already advanced)
|
|
c2.encrypt(p2.data(), p2.size()); // fresh session
|
|
CHECK(p1 != p2, "different sessions produce different ciphertext");
|
|
}
|
|
|
|
if (g_fail) {
|
|
std::fprintf(stderr, "%d check(s) failed\n", g_fail);
|
|
return 1;
|
|
}
|
|
std::puts("net_classic_cipher_test OK");
|
|
return 0;
|
|
}
|