ChaCha20-Poly1305.h (5485B)
1 /* 2 * ChaCha20-Poly1305 AEAD Implementation 3 * 4 * Compliant with: 5 * - RFC 8439 (ChaCha20 and Poly1305 for IETF Protocols) 6 * - Used in TLS 1.3, WireGuard, OpenSSH 7 * 8 * ⚠️ WARNING: 96-bit Nonces - DO NOT use random nonces! 9 * - MUST use sequential counter nonces (never reuse!) 10 * - Random nonces have collision risk after ~2^32 messages 11 * - Consider XChaCha20-Poly1305 for random nonces (192-bit) 12 * 13 * Security Features: 14 * - 256-bit keys 15 * - 96-bit nonces (MUST be sequential or unique) 16 * - Authenticated encryption (AEAD) 17 * - Fast software implementation (~1-2 GB/s) 18 * - No hardware acceleration needed 19 * - No timing attacks 20 * - Simpler than AES-GCM 21 * 22 * Advantages over AES-GCM: 23 * - Faster on CPUs without AES-NI 24 * - Simpler implementation 25 * - No cache-timing vulnerabilities 26 * - Better performance on mobile devices 27 * 28 * When to use XChaCha20-Poly1305 instead: 29 * - You want to use random nonces (simpler, safer) 30 * - You can't reliably track nonce state 31 * - You're encrypting many messages (>2^32) 32 */ 33 34 #ifndef CHACHA20_POLY1305_H 35 #define CHACHA20_POLY1305_H 36 37 #include <stdint.h> 38 #include <stdlib.h> 39 40 #ifdef __cplusplus 41 extern "C" { 42 #endif 43 44 /* Constants */ 45 #define CHACHA20_KEY_SIZE 32 /* 256 bits */ 46 #define CHACHA20_NONCE_SIZE 12 /* 96 bits (IETF version) */ 47 #define CHACHA20_BLOCK_SIZE 64 /* 512 bits */ 48 #define POLY1305_KEY_SIZE 32 /* 256 bits */ 49 #define POLY1305_TAG_SIZE 16 /* 128 bits */ 50 51 /* ChaCha20 context */ 52 typedef struct { 53 uint32_t state[16]; 54 uint8_t keystream[64]; 55 size_t keystream_pos; 56 uint64_t counter; 57 } chacha20_context; 58 59 /* Poly1305 context */ 60 typedef struct { 61 uint32_t r[5]; 62 uint32_t h[5]; 63 uint32_t pad[4]; 64 uint8_t buffer[16]; 65 size_t buffer_len; 66 uint64_t total_len; 67 } poly1305_context; 68 69 /* ChaCha20-Poly1305 AEAD context */ 70 typedef struct { 71 chacha20_context cipher; 72 poly1305_context mac; 73 uint64_t aad_len; 74 uint64_t data_len; 75 } chacha20_poly1305_context; 76 77 /** 78 * Initialize ChaCha20-Poly1305 AEAD 79 * 80 * @param ctx AEAD context 81 * @param key 256-bit (32 byte) encryption key 82 * @param nonce 96-bit (12 byte) nonce 83 * @return 0 on success, -1 on error 84 * 85 * ⚠️ Security Notes: 86 * - NEVER reuse (key, nonce) pairs 87 * - DO NOT use random nonces (collision risk after ~2^32 messages) 88 * - MUST use sequential counter or guaranteed-unique nonces 89 * - For random nonces, use XChaCha20-Poly1305 instead (192-bit) 90 * - Used in TLS 1.3, WireGuard, SSH 91 * - Provides both encryption and authentication 92 */ 93 int chacha20_poly1305_init(chacha20_poly1305_context *ctx, 94 const uint8_t *key, 95 const uint8_t *nonce); 96 97 /** 98 * ChaCha20-Poly1305 AEAD Encryption 99 * 100 * @param ctx Initialized context 101 * @param aad Additional authenticated data (can be NULL if aad_len is 0) 102 * @param aad_len AAD length in bytes 103 * @param plaintext Input plaintext 104 * @param pt_len Plaintext length in bytes 105 * @param ciphertext Output ciphertext buffer (must be pt_len bytes) 106 * @param tag Output authentication tag (must be 16 bytes) 107 * @return 0 on success, -1 on error 108 * 109 * Security Notes: 110 * - AAD is authenticated but not encrypted 111 * - Maximum plaintext: 2^38 - 64 bytes (~256 GB) 112 * - Tag must be sent with ciphertext 113 * - Verify tag before using decrypted data 114 * 115 * Performance: 116 * - ~1-2 GB/s in software (no hardware needed) 117 * - Faster than AES-GCM on CPUs without AES-NI 118 */ 119 int chacha20_poly1305_encrypt(chacha20_poly1305_context *ctx, 120 const uint8_t *aad, size_t aad_len, 121 const uint8_t *plaintext, size_t pt_len, 122 uint8_t *ciphertext, 123 uint8_t *tag); 124 125 /** 126 * ChaCha20-Poly1305 AEAD Decryption 127 * 128 * @param ctx Initialized context 129 * @param aad Additional authenticated data (must match encryption) 130 * @param aad_len AAD length in bytes 131 * @param ciphertext Input ciphertext 132 * @param ct_len Ciphertext length in bytes 133 * @param tag Authentication tag from encryption (16 bytes) 134 * @param plaintext Output plaintext buffer (must be ct_len bytes) 135 * @return 0 on success, -1 on authentication failure 136 * 137 * Security Notes: 138 * - Returns -1 if authentication tag doesn't match 139 * - Plaintext is NOT valid if function returns -1 140 * - Constant-time tag comparison 141 * - MUST verify return value before using plaintext 142 */ 143 int chacha20_poly1305_decrypt(chacha20_poly1305_context *ctx, 144 const uint8_t *aad, size_t aad_len, 145 const uint8_t *ciphertext, size_t ct_len, 146 const uint8_t *tag, 147 uint8_t *plaintext); 148 149 /** 150 * Clean up context (zeros sensitive data) 151 * 152 * @param ctx Context to clean 153 * 154 * Security: Zeros all key material and state 155 */ 156 void chacha20_poly1305_cleanup(chacha20_poly1305_context *ctx); 157 158 /** 159 * Standalone ChaCha20 encryption/decryption 160 * (Use ChaCha20-Poly1305 AEAD for authenticated encryption) 161 * 162 * @param key 256-bit key 163 * @param nonce 96-bit nonce 164 * @param counter Initial counter (usually 0 or 1) 165 * @param input Input data 166 * @param output Output buffer (can be same as input) 167 * @param len Data length 168 * @return 0 on success 169 */ 170 int chacha20_crypt(const uint8_t *key, const uint8_t *nonce, 171 uint32_t counter, const uint8_t *input, 172 uint8_t *output, size_t len); 173 174 #ifdef __cplusplus 175 } 176 #endif 177 178 #endif /* CHACHA20_POLY1305_H */