Byte-exact cereal binary layout, RFC 8439 ChaCha20-Poly1305, RFC 7914 scrypt defaults; tokio transport preserving the original's observable behavior (contract B1-B3, B5 quirks included). Parity evidence: golden C++ vectors in tests/vectors.rs and loopback behavior tests; both cross-directions verified against the unmodified C++ binaries. Source: https://git.0xfeedc0de.com/michael/OmniVox
73 lines
3.2 KiB
C++
73 lines
3.2 KiB
C++
// Golden-vector generator for the Rust port. Output is normative.
|
|
#include "common.h"
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
|
|
static std::string hex(const uint8_t* p, size_t n) {
|
|
std::ostringstream os; os << std::hex << std::setfill('0');
|
|
for (size_t i = 0; i < n; i++) os << std::setw(2) << (int)p[i];
|
|
return os.str();
|
|
}
|
|
static std::string hexv(const std::vector<uint8_t>& v) { return hex(v.data(), v.size()); }
|
|
|
|
int main() {
|
|
// 1. scrypt key derivation (default params N=2^17 r=8 p=1)
|
|
OmniVox<DatagramPayload> vox;
|
|
std::vector<uint8_t> pw(g_sPassword.begin(), g_sPassword.end());
|
|
auto key = vox.deriveEncryptKey(pw, g_vecSalt);
|
|
std::cout << "scrypt_key=" << hex(key.data(), key.size()) << "\n";
|
|
|
|
// extra scrypt vector: known short inputs
|
|
std::vector<uint8_t> pw2{'p','a','s','s'}, salt2{'s','a','l','t'};
|
|
auto key2 = vox.deriveEncryptKey(pw2, salt2);
|
|
std::cout << "scrypt_key2=" << hex(key2.data(), key2.size()) << "\n";
|
|
|
|
vox.setEncryptKey(key);
|
|
|
|
// 2. cereal byte layouts
|
|
DatagramPayload dp;
|
|
dp.id = 0x1234; dp.v1.qword = 0x1122334455667788ULL;
|
|
dp.payload = {'H','e','l','l','o'};
|
|
std::cout << "cereal_datagram=" << hexv(serializeObject(dp)) << "\n";
|
|
DatagramPayload dp0; // all defaults
|
|
std::cout << "cereal_datagram_default=" << hexv(serializeObject(dp0)) << "\n";
|
|
|
|
AeadPacket ap{};
|
|
for (int i = 0; i < 12; i++) ap.nonce[i] = (uint8_t)i;
|
|
for (int i = 0; i < 16; i++) ap.tag[i] = (uint8_t)(0xA0 + i);
|
|
ap.payload = {0xDE, 0xAD, 0xBE, 0xEF};
|
|
std::cout << "cereal_aead=" << hexv(serializeObject(ap)) << "\n";
|
|
AeadPacket ap0{};
|
|
std::cout << "cereal_aead_empty=" << hexv(serializeObject(ap0)) << "\n";
|
|
|
|
// 3. AEAD vectors: fixed nonce, CryptoPP as the oracle
|
|
auto vec = [](std::string s){ return std::vector<uint8_t>(s.begin(), s.end()); };
|
|
{
|
|
auto pkt = vox.encrypt(vec("Hello")); // random nonce: structure check only
|
|
std::cout << "aead_random_payloadlen=" << pkt.payload.size() << "\n";
|
|
}
|
|
// deterministic: set key, encrypt with forced nonce by round-tripping through
|
|
// a fresh object whose rng we can't seed... instead use Crypto++ directly.
|
|
{
|
|
CryptoPP::ChaCha20Poly1305::Encryption enc;
|
|
uint8_t nonce[12] = {0,1,2,3,4,5,6,7,8,9,10,11};
|
|
enc.SetKeyWithIV(key.data(), key.size(), nonce, 12);
|
|
std::string pt = "Hello";
|
|
std::vector<uint8_t> ct(pt.size()), tag(16);
|
|
enc.EncryptAndAuthenticate(ct.data(), tag.data(), 16, nonce, 12,
|
|
nullptr, 0,
|
|
(const unsigned char*)pt.data(), pt.size());
|
|
std::cout << "aead_ct=" << hexv(ct) << "\n";
|
|
std::cout << "aead_tag=" << hex(tag.data(), 16) << "\n";
|
|
}
|
|
{
|
|
CryptoPP::ChaCha20Poly1305::Encryption enc;
|
|
uint8_t nonce[12] = {0,1,2,3,4,5,6,7,8,9,10,11};
|
|
enc.SetKeyWithIV(key.data(), key.size(), nonce, 12);
|
|
std::vector<uint8_t> ct(0), tag(16);
|
|
enc.EncryptAndAuthenticate(ct.data(), tag.data(), 16, nonce, 12,
|
|
nullptr, 0, (const unsigned char*)"", 0);
|
|
std::cout << "aead_empty_tag=" << hex(tag.data(), 16) << "\n";
|
|
}
|
|
return 0;
|
|
} |