259 lines
7 KiB
Markdown
259 lines
7 KiB
Markdown
# 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 <string.h>
|
|
|
|
// 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.
|