# Security — DH Key Exchange and XTEA-CTR Cipher Cryptographic library providing Diffie-Hellman key exchange and XTEA symmetric encryption, optimized for 486-class DOS hardware running under DJGPP/DPMI. ## Components ### Diffie-Hellman Key Exchange - 1024-bit MODP group (RFC 2409 Group 2 safe prime) - 256-bit private exponents for fast computation on 486 CPUs - Montgomery multiplication (CIOS variant) for modular exponentiation - Lazy-initialized Montgomery constants (R^2 mod p, -p0^-1 mod 2^32) ### XTEA Cipher (CTR Mode) - 128-bit key, 64-bit block size, 32 rounds - CTR mode — encrypt and decrypt are the same XOR operation - No lookup tables, no key schedule — just shifts, adds, and XORs - Ideal for constrained environments with small key setup cost ### Pseudo-Random Number Generator - XTEA-CTR based DRBG (deterministic random bit generator) - Hardware entropy from PIT counter (~10 bits) and BIOS tick count - Supports additional entropy injection (keyboard timing, mouse, etc.) - Auto-seeds from hardware on first use if not explicitly seeded ## Performance At serial port speeds, encryption overhead is minimal: | Speed | Blocks/sec | CPU cycles/sec | % of 33 MHz 486 | |----------|------------|----------------|------------------| | 9600 | 120 | ~240K | < 1% | | 57600 | 720 | ~1.4M | ~4% | | 115200 | 1440 | ~2.9M | ~9% | DH key exchange takes approximately 0.3s at 66 MHz or 0.6s at 33 MHz (256-bit private exponent, 1024-bit modulus). ## API Reference ### Constants | Name | Value | Description | |---------------------|-------|--------------------------------| | `SEC_DH_KEY_SIZE` | 128 | DH public key size (bytes) | | `SEC_XTEA_KEY_SIZE` | 16 | XTEA key size (bytes) | | `SEC_SUCCESS` | 0 | Success | | `SEC_ERR_PARAM` | -1 | Invalid parameter | | `SEC_ERR_NOT_READY` | -2 | Keys not yet generated/derived | | `SEC_ERR_ALLOC` | -3 | Memory allocation failed | ### Types ```c typedef struct SecDhS SecDhT; // Opaque DH context typedef struct SecCipherS SecCipherT; // Opaque cipher context ``` ### RNG Functions ```c int secRngGatherEntropy(uint8_t *buf, int len); ``` Reads hardware entropy sources (PIT counter, BIOS tick count). Returns the number of bytes written. Provides roughly 20 bits of true entropy. ```c void secRngSeed(const uint8_t *entropy, int len); ``` Initializes the DRBG with the given entropy. XOR-folds the input into the XTEA key, derives the counter, and mixes state by generating and discarding 64 bytes. ```c void secRngAddEntropy(const uint8_t *data, int len); ``` Mixes additional entropy into the running RNG state without resetting it. Use this to stir in keyboard timing, mouse jitter, or other runtime entropy. ```c void secRngBytes(uint8_t *buf, int len); ``` Generates `len` pseudo-random bytes. Auto-seeds from hardware if not previously seeded. ### Diffie-Hellman Functions ```c SecDhT *secDhCreate(void); ``` Allocates a new DH context. Returns `NULL` on allocation failure. ```c int secDhGenerateKeys(SecDhT *dh); ``` Generates a 256-bit random private key and computes the corresponding 1024-bit public key (g^private mod p). The RNG should be seeded first. ```c int secDhGetPublicKey(SecDhT *dh, uint8_t *buf, int *len); ``` Exports the public key into `buf`. On entry, `*len` must be at least `SEC_DH_KEY_SIZE` (128). On return, `*len` is set to 128. ```c int secDhComputeSecret(SecDhT *dh, const uint8_t *remotePub, int len); ``` Computes the shared secret from the remote side's public key. Validates that the remote key is in range [2, p-2] to prevent small-subgroup attacks. ```c int secDhDeriveKey(SecDhT *dh, uint8_t *key, int keyLen); ``` Derives a symmetric key by XOR-folding the 128-byte shared secret down to `keyLen` bytes. ```c void secDhDestroy(SecDhT *dh); ``` Securely zeroes and frees the DH context (private key, shared secret). ### Cipher Functions ```c SecCipherT *secCipherCreate(const uint8_t *key); ``` Creates an XTEA-CTR cipher context with the given 16-byte key. Counter starts at zero. ```c void secCipherCrypt(SecCipherT *c, uint8_t *data, int len); ``` Encrypts or decrypts `data` in place. CTR mode is symmetric — the same operation encrypts and decrypts. ```c void secCipherSetNonce(SecCipherT *c, uint32_t nonceLo, uint32_t nonceHi); ``` Sets the 64-bit nonce/counter. Call before encrypting if you need a specific starting counter value. ```c void secCipherDestroy(SecCipherT *c); ``` Securely zeroes and frees the cipher context. ## Example ### Full Key Exchange ```c #include "security.h" #include // Seed the RNG uint8_t entropy[16]; secRngGatherEntropy(entropy, sizeof(entropy)); secRngSeed(entropy, sizeof(entropy)); // Create DH context and generate keys SecDhT *dh = secDhCreate(); secDhGenerateKeys(dh); // Export public key to send to remote uint8_t myPub[SEC_DH_KEY_SIZE]; int pubLen = SEC_DH_KEY_SIZE; secDhGetPublicKey(dh, myPub, &pubLen); // ... send myPub to remote, receive remotePub ... // Compute shared secret and derive a 16-byte key secDhComputeSecret(dh, remotePub, SEC_DH_KEY_SIZE); uint8_t key[SEC_XTEA_KEY_SIZE]; secDhDeriveKey(dh, key, SEC_XTEA_KEY_SIZE); secDhDestroy(dh); // Create cipher and encrypt SecCipherT *cipher = secCipherCreate(key); uint8_t message[] = "Secret message"; secCipherCrypt(cipher, message, sizeof(message)); // message is now encrypted // Decrypt (same operation — CTR mode is symmetric) // Reset counter first if using the same cipher context secCipherSetNonce(cipher, 0, 0); secCipherCrypt(cipher, message, sizeof(message)); // message is now plaintext again secCipherDestroy(cipher); ``` ### Standalone Encryption ```c // XTEA-CTR can be used independently of DH uint8_t key[SEC_XTEA_KEY_SIZE] = { /* your key */ }; SecCipherT *c = secCipherCreate(key); uint8_t data[1024]; // ... fill data ... secCipherCrypt(c, data, sizeof(data)); // encrypt in place secCipherDestroy(c); ``` ## Implementation Details ### BigNum Arithmetic All modular arithmetic uses a 1024-bit big number type (`BigNumT`) stored as 32 x `uint32_t` words in little-endian order. Operations: - Add, subtract, compare, shift-left-1, bit test - Montgomery multiplication (CIOS with implicit right-shift) - Modular exponentiation (left-to-right binary square-and-multiply) ### Montgomery Multiplication The CIOS (Coarsely Integrated Operand Scanning) variant computes `a * b * R^-1 mod m` in a single pass with implicit division by the word base. Constants are computed once on first DH use: - `R^2 mod p` — via 2048 iterations of shift-and-conditional-subtract - `-p[0]^-1 mod 2^32` — via Newton's method (5 iterations) ### Secure Zeroing Key material is erased using a volatile-pointer loop that the compiler cannot optimize away, preventing sensitive data from lingering in memory. ## Building ``` make # builds ../lib/libsecurity.a make clean # removes objects and library ``` Target: DJGPP cross-compiler, 486+ CPU.