├── README.md ├── poly1305.h ├── chachapoly_aead.h ├── chacha.h ├── .travis.yml ├── bench.c ├── poly1305.c ├── chachapoly_aead.c ├── chacha.c └── tests.c /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/jonasschnelli/chacha20poly1305.svg?branch=master)](https://travis-ci.org/jonasschnelli/chacha20poly1305) 2 | 3 | chacha20poly1305@bitcoin AEAD 4 | ===== 5 | 6 | Simple C module for ChaCha20Poly1305@bitcoin AEAD 7 | 8 | Features: 9 | * Simple, pure C code without any dependencies. 10 | 11 | 12 | Build steps 13 | ----------- 14 | 15 | Object code: 16 | 17 | $ gcc -lm -O3 -c poly1305.c chacha.c chachapoly_aead.c 18 | 19 | Tests: 20 | 21 | $ gcc -O3 poly1305.c chacha.c chachapoly_aead.c tests.c -o test 22 | 23 | Benchmark: 24 | 25 | $ gcc -lm -O3 poly1305.c chacha.c chachapoly_aead.c bench.c -o bench 26 | -------------------------------------------------------------------------------- /poly1305.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: poly1305.h,v 1.4 2014/05/02 03:27:54 djm Exp $ */ 2 | 3 | /* 4 | * Public Domain poly1305 from Andrew Moon 5 | * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna 6 | */ 7 | 8 | #ifndef POLY1305_H 9 | #define POLY1305_H 10 | 11 | #include 12 | #include 13 | 14 | #define POLY1305_KEYLEN 32 15 | #define POLY1305_TAGLEN 16 16 | 17 | void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, 18 | const uint8_t key[POLY1305_KEYLEN]) 19 | __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) 20 | __attribute__((__bounded__(__buffer__, 2, 3))) 21 | __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); 22 | 23 | #endif /* POLY1305_H */ 24 | -------------------------------------------------------------------------------- /chachapoly_aead.h: -------------------------------------------------------------------------------- 1 | #ifndef CHACHA20_POLY_AEAD_H 2 | #define CHACHA20_POLY_AEAD_H 3 | 4 | #include "chacha.h" 5 | 6 | #define CHACHA_KEYLEN 32 /* 2 x 256 bit keys */ 7 | #define CHACHA20_POLY1305_AEAD_KEY_LEN 32 8 | #define CHACHA20_POLY1305_AEAD_AAD_LEN 3 /* 3 bytes length */ 9 | #define CHACHA20_ROUND_OUTPUT 64 /* 64 bytes per round */ 10 | #define AAD_PACKAGES_PER_ROUND 21 /* 64 / 3 round down*/ 11 | 12 | struct chachapolyaead_ctx { 13 | struct chacha_ctx main_ctx, header_ctx; 14 | uint8_t aad_keystream_buffer[CHACHA20_ROUND_OUTPUT]; 15 | uint64_t cached_aad_seqnr; 16 | }; 17 | 18 | int chacha20poly1305_init(struct chachapolyaead_ctx* cpctx, const uint8_t* k_1, int k_1_len, const uint8_t* k_2, int k_2_len); 19 | int chacha20poly1305_crypt(struct chachapolyaead_ctx* ctx, uint64_t seqnr, uint64_t seqnr_aad, int pos_aad, uint8_t* dest, size_t dest_len, const uint8_t* src, size_t srv_len, int is_encrypt); 20 | int chacha20poly1305_get_length(struct chachapolyaead_ctx* ctx, 21 | uint32_t* len_out, 22 | uint64_t seqnr, 23 | const uint8_t* ciphertext); 24 | #endif /* CHACHA20_POLY_AEAD_H */ 25 | -------------------------------------------------------------------------------- /chacha.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: chacha.h,v 1.4 2016/08/27 04:04:56 guenther Exp $ */ 2 | 3 | /* 4 | chacha-merged.c version 20080118 5 | D. J. Bernstein 6 | Public domain. 7 | */ 8 | 9 | #ifndef CHACHA_H 10 | #define CHACHA_H 11 | 12 | #include 13 | #include 14 | 15 | struct chacha_ctx { 16 | uint32_t input[16]; 17 | }; 18 | 19 | #define CHACHA_MINKEYLEN 16 20 | #define CHACHA_NONCELEN 8 21 | #define CHACHA_CTRLEN 8 22 | #define CHACHA_STATELEN (CHACHA_NONCELEN + CHACHA_CTRLEN) 23 | #define CHACHA_BLOCKLEN 64 24 | 25 | void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits) 26 | __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); 27 | void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr) 28 | __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) 29 | __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); 30 | void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m, uint8_t *c, 31 | uint32_t bytes) 32 | __attribute__((__bounded__(__buffer__, 2, 4))) 33 | __attribute__((__bounded__(__buffer__, 3, 4))); 34 | 35 | #endif /* CHACHA_H */ 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | dist: xenial 3 | os: 4 | - osx 5 | - linux 6 | 7 | compiler: 8 | - clang 9 | - gcc 10 | - x86_64-w64-mingw32-gcc 11 | 12 | addons: 13 | apt: 14 | packages: 15 | - valgrind 16 | - binutils-mingw-w64 17 | - gcc-mingw-w64 18 | - wine 19 | 20 | before_install: 21 | - pip install --user cpp-coveralls 22 | - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew install gnu-sed; fi 23 | 24 | matrix: 25 | fast_finish: 26 | - true 27 | exclude: 28 | - os: osx 29 | compiler: x86_64-w64-mingw32-gcc 30 | 31 | script: 32 | - $CC -lm -O3 poly1305.c chacha.c chachapoly_aead.c bench.c -o bench 33 | - rm -f *.o 34 | - $CC -lm -O0 -g poly1305.c chacha.c chachapoly_aead.c tests.c -o test 35 | - if ( [ "${TRAVIS_OS_NAME}" == "linux" ] ) && ( [ "$CC" == "gcc" ] ); then 36 | valgrind --track-origins=yes --leak-check=full --error-exitcode=1 ./test; 37 | ./test; 38 | else 39 | if ( [ "$CC" == x86_64-w64-mingw32-gcc ] ) || ( [ "$CC" == i686-w64-mingw32-gcc ] ); then 40 | ls -la; 41 | else 42 | ./test; 43 | fi 44 | fi 45 | -------------------------------------------------------------------------------- /bench.c: -------------------------------------------------------------------------------- 1 | #include "sys/time.h" 2 | #include 3 | #include 4 | 5 | #include "chachapoly_aead.h" 6 | #include "poly1305.h" 7 | 8 | static const uint8_t testkey[32] = { 9 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 10 | 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 11 | 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; 12 | 13 | static const uint8_t testnonce[32] = {0x00, 0x01, 0x02, 0x03, 14 | 0x04, 0x05, 0x06, 0x07}; 15 | 16 | static const uint8_t testdata[12] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 17 | 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21}; 18 | 19 | static const uint64_t BUFFER_SIZE = 1000 * 1000; 20 | 21 | static const uint8_t aead_keys[64] = { 22 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 23 | 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 24 | 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 27 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 28 | 29 | static double gettimedouble(void) 30 | { 31 | struct timeval tv; 32 | gettimeofday(&tv, NULL); 33 | return tv.tv_usec * 0.000001 + tv.tv_sec; 34 | } 35 | 36 | static void print_number(double x) 37 | { 38 | double y = x; 39 | int c = 0; 40 | if (y < 0.0) { 41 | y = -y; 42 | } 43 | while (y < 100.0) { 44 | y *= 10.0; 45 | c++; 46 | } 47 | printf("%.*f", c, x); 48 | } 49 | 50 | static void run_benchmark(char* name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) 51 | { 52 | int i; 53 | double min = HUGE_VAL; 54 | double sum = 0.0; 55 | double max = 0.0; 56 | for (i = 0; i < count; i++) { 57 | double begin, total; 58 | if (setup != NULL) { 59 | setup(data); 60 | } 61 | begin = gettimedouble(); 62 | benchmark(data); 63 | total = gettimedouble() - begin; 64 | if (teardown != NULL) { 65 | teardown(data); 66 | } 67 | if (total < min) { 68 | min = total; 69 | } 70 | if (total > max) { 71 | max = total; 72 | } 73 | sum += total; 74 | } 75 | printf("%s: min ", name); 76 | print_number(min * 1000000000.0 / iter); 77 | printf("ns / avg "); 78 | print_number((sum / count) * 1000000000.0 / iter); 79 | printf("ns / max "); 80 | print_number(max * 1000000000.0 / iter); 81 | printf("ns\n"); 82 | } 83 | 84 | static void bench_chacha_ivsetup(void* data) 85 | { 86 | struct chacha_ctx* ctx = (struct chacha_ctx*)data; 87 | int i; 88 | for (i = 0; i < 50000; i++) { 89 | chacha_ivsetup(ctx, testnonce, NULL); 90 | } 91 | } 92 | 93 | static void bench_chacha_keysetup(void* data) 94 | { 95 | struct chacha_ctx* ctx = (struct chacha_ctx*)data; 96 | int i; 97 | for (i = 0; i < 50000; i++) { 98 | chacha_keysetup(ctx, testkey, 256); 99 | } 100 | } 101 | 102 | static void bench_chacha_encrypt(void* data) 103 | { 104 | struct chacha_ctx* ctx = (struct chacha_ctx*)data; 105 | uint8_t scratch[16] = {0}; 106 | int i; 107 | for (i = 0; i < 4000000 / 16; i++) { 108 | chacha_encrypt_bytes(ctx, scratch, scratch, 16); 109 | } 110 | } 111 | 112 | static void bench_poly1305_auth(void* data) 113 | { 114 | struct chacha_ctx* ctx = (struct chacha_ctx*)data; 115 | uint8_t poly1305_tag[16] = {0}; 116 | int i; 117 | for (i = 0; i < 4000000 / 12; i++) { 118 | poly1305_auth(poly1305_tag, testdata, 12, testkey); 119 | } 120 | } 121 | 122 | static void bench_chacha20poly1305_init(void* data) 123 | { 124 | struct chachapolyaead_ctx* ctx = (struct chachapolyaead_ctx*)data; 125 | int i; 126 | for (i = 0; i < 50000; i++) { 127 | chacha20poly1305_init(ctx, aead_keys, 32, aead_keys + 32, 32); 128 | } 129 | } 130 | 131 | static void bench_chacha20poly1305_crypt(void* data) 132 | { 133 | struct chachapolyaead_ctx* ctx = (struct chachapolyaead_ctx*)data; 134 | int i; 135 | uint32_t seqnr = 0; 136 | 137 | uint8_t buffer[BUFFER_SIZE + 16]; 138 | for (i = 0; i < 30; i++) { 139 | chacha20poly1305_crypt(ctx, seqnr, seqnr, 0, buffer, BUFFER_SIZE + 16, buffer, BUFFER_SIZE, 1); 140 | } 141 | } 142 | 143 | int main(void) 144 | { 145 | struct chacha_ctx ctx_chacha; 146 | struct chachapolyaead_ctx aead_ctx; 147 | run_benchmark("chacha_ivsetup", bench_chacha_ivsetup, NULL, NULL, &ctx_chacha, 148 | 20, 50000); 149 | run_benchmark("chacha_keysetup", bench_chacha_keysetup, NULL, NULL, 150 | &ctx_chacha, 20, 50000); 151 | run_benchmark("chacha_encrypt", bench_chacha_encrypt, NULL, NULL, &ctx_chacha, 152 | 20, 4000000); 153 | run_benchmark("poly1305_auth", bench_poly1305_auth, NULL, NULL, &ctx_chacha, 154 | 20, 4000000); 155 | run_benchmark("chacha20poly1305_init", bench_chacha20poly1305_init, NULL, 156 | NULL, &aead_ctx, 20, 4000000); 157 | run_benchmark("chacha20poly1305_crypt 1MB", bench_chacha20poly1305_crypt, 158 | NULL, NULL, &aead_ctx, 20, 30); 159 | return 0; 160 | } -------------------------------------------------------------------------------- /poly1305.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Public Domain poly1305 from Andrew Moon 3 | * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna 4 | */ 5 | 6 | /* $OpenBSD: poly1305.c,v 1.3 2013/12/19 22:57:13 djm Exp $ */ 7 | 8 | #include "poly1305.h" 9 | 10 | #define mul32x32_64(a, b) ((uint64_t)(a) * (b)) 11 | 12 | #define U8TO32_LE(p) \ 13 | (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ 14 | ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) 15 | 16 | #define U32TO8_LE(p, v) \ 17 | do { \ 18 | (p)[0] = (uint8_t)((v)); \ 19 | (p)[1] = (uint8_t)((v) >> 8); \ 20 | (p)[2] = (uint8_t)((v) >> 16); \ 21 | (p)[3] = (uint8_t)((v) >> 24); \ 22 | } while (0) 23 | 24 | void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, 25 | size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { 26 | uint32_t t0, t1, t2, t3; 27 | uint32_t h0, h1, h2, h3, h4; 28 | uint32_t r0, r1, r2, r3, r4; 29 | uint32_t s1, s2, s3, s4; 30 | uint32_t b, nb; 31 | size_t j; 32 | uint64_t t[5]; 33 | uint64_t f0, f1, f2, f3; 34 | uint32_t g0, g1, g2, g3, g4; 35 | uint64_t c; 36 | unsigned char mp[16]; 37 | 38 | /* clamp key */ 39 | t0 = U8TO32_LE(key + 0); 40 | t1 = U8TO32_LE(key + 4); 41 | t2 = U8TO32_LE(key + 8); 42 | t3 = U8TO32_LE(key + 12); 43 | 44 | /* precompute multipliers */ 45 | r0 = t0 & 0x3ffffff; 46 | t0 >>= 26; 47 | t0 |= t1 << 6; 48 | r1 = t0 & 0x3ffff03; 49 | t1 >>= 20; 50 | t1 |= t2 << 12; 51 | r2 = t1 & 0x3ffc0ff; 52 | t2 >>= 14; 53 | t2 |= t3 << 18; 54 | r3 = t2 & 0x3f03fff; 55 | t3 >>= 8; 56 | r4 = t3 & 0x00fffff; 57 | 58 | s1 = r1 * 5; 59 | s2 = r2 * 5; 60 | s3 = r3 * 5; 61 | s4 = r4 * 5; 62 | 63 | /* init state */ 64 | h0 = 0; 65 | h1 = 0; 66 | h2 = 0; 67 | h3 = 0; 68 | h4 = 0; 69 | 70 | /* full blocks */ 71 | if (inlen < 16) 72 | goto poly1305_donna_atmost15bytes; 73 | poly1305_donna_16bytes: 74 | m += 16; 75 | inlen -= 16; 76 | 77 | t0 = U8TO32_LE(m - 16); 78 | t1 = U8TO32_LE(m - 12); 79 | t2 = U8TO32_LE(m - 8); 80 | t3 = U8TO32_LE(m - 4); 81 | 82 | h0 += t0 & 0x3ffffff; 83 | h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; 84 | h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; 85 | h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; 86 | h4 += (t3 >> 8) | (1 << 24); 87 | 88 | poly1305_donna_mul: 89 | t[0] = mul32x32_64(h0, r0) + mul32x32_64(h1, s4) + mul32x32_64(h2, s3) + 90 | mul32x32_64(h3, s2) + mul32x32_64(h4, s1); 91 | t[1] = mul32x32_64(h0, r1) + mul32x32_64(h1, r0) + mul32x32_64(h2, s4) + 92 | mul32x32_64(h3, s3) + mul32x32_64(h4, s2); 93 | t[2] = mul32x32_64(h0, r2) + mul32x32_64(h1, r1) + mul32x32_64(h2, r0) + 94 | mul32x32_64(h3, s4) + mul32x32_64(h4, s3); 95 | t[3] = mul32x32_64(h0, r3) + mul32x32_64(h1, r2) + mul32x32_64(h2, r1) + 96 | mul32x32_64(h3, r0) + mul32x32_64(h4, s4); 97 | t[4] = mul32x32_64(h0, r4) + mul32x32_64(h1, r3) + mul32x32_64(h2, r2) + 98 | mul32x32_64(h3, r1) + mul32x32_64(h4, r0); 99 | 100 | h0 = (uint32_t)t[0] & 0x3ffffff; 101 | c = (t[0] >> 26); 102 | t[1] += c; 103 | h1 = (uint32_t)t[1] & 0x3ffffff; 104 | b = (uint32_t)(t[1] >> 26); 105 | t[2] += b; 106 | h2 = (uint32_t)t[2] & 0x3ffffff; 107 | b = (uint32_t)(t[2] >> 26); 108 | t[3] += b; 109 | h3 = (uint32_t)t[3] & 0x3ffffff; 110 | b = (uint32_t)(t[3] >> 26); 111 | t[4] += b; 112 | h4 = (uint32_t)t[4] & 0x3ffffff; 113 | b = (uint32_t)(t[4] >> 26); 114 | h0 += b * 5; 115 | 116 | if (inlen >= 16) 117 | goto poly1305_donna_16bytes; 118 | 119 | /* final bytes */ 120 | poly1305_donna_atmost15bytes: 121 | if (!inlen) 122 | goto poly1305_donna_finish; 123 | 124 | for (j = 0; j < inlen; j++) 125 | mp[j] = m[j]; 126 | mp[j++] = 1; 127 | for (; j < 16; j++) 128 | mp[j] = 0; 129 | inlen = 0; 130 | 131 | t0 = U8TO32_LE(mp + 0); 132 | t1 = U8TO32_LE(mp + 4); 133 | t2 = U8TO32_LE(mp + 8); 134 | t3 = U8TO32_LE(mp + 12); 135 | 136 | h0 += t0 & 0x3ffffff; 137 | h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; 138 | h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; 139 | h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; 140 | h4 += (t3 >> 8); 141 | 142 | goto poly1305_donna_mul; 143 | 144 | poly1305_donna_finish: 145 | b = h0 >> 26; 146 | h0 = h0 & 0x3ffffff; 147 | h1 += b; 148 | b = h1 >> 26; 149 | h1 = h1 & 0x3ffffff; 150 | h2 += b; 151 | b = h2 >> 26; 152 | h2 = h2 & 0x3ffffff; 153 | h3 += b; 154 | b = h3 >> 26; 155 | h3 = h3 & 0x3ffffff; 156 | h4 += b; 157 | b = h4 >> 26; 158 | h4 = h4 & 0x3ffffff; 159 | h0 += b * 5; 160 | b = h0 >> 26; 161 | h0 = h0 & 0x3ffffff; 162 | h1 += b; 163 | 164 | g0 = h0 + 5; 165 | b = g0 >> 26; 166 | g0 &= 0x3ffffff; 167 | g1 = h1 + b; 168 | b = g1 >> 26; 169 | g1 &= 0x3ffffff; 170 | g2 = h2 + b; 171 | b = g2 >> 26; 172 | g2 &= 0x3ffffff; 173 | g3 = h3 + b; 174 | b = g3 >> 26; 175 | g3 &= 0x3ffffff; 176 | g4 = h4 + b - (1 << 26); 177 | 178 | b = (g4 >> 31) - 1; 179 | nb = ~b; 180 | h0 = (h0 & nb) | (g0 & b); 181 | h1 = (h1 & nb) | (g1 & b); 182 | h2 = (h2 & nb) | (g2 & b); 183 | h3 = (h3 & nb) | (g3 & b); 184 | h4 = (h4 & nb) | (g4 & b); 185 | 186 | f0 = ((h0) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); 187 | f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); 188 | f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); 189 | f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); 190 | 191 | U32TO8_LE(&out[0], f0); 192 | f1 += (f0 >> 32); 193 | U32TO8_LE(&out[4], f1); 194 | f2 += (f1 >> 32); 195 | U32TO8_LE(&out[8], f2); 196 | f3 += (f2 >> 32); 197 | U32TO8_LE(&out[12], f3); 198 | } 199 | -------------------------------------------------------------------------------- /chachapoly_aead.c: -------------------------------------------------------------------------------- 1 | #include "chachapoly_aead.h" 2 | 3 | #define __STDC_WANT_LIB_EXT1__ 1 4 | #include "poly1305.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && \ 11 | !defined(__WINDOWS__) 12 | #define __WINDOWS__ 13 | #endif 14 | 15 | #if defined(__linux__) || defined(__CYGWIN__) 16 | #include 17 | 18 | #elif defined(__APPLE__) 19 | #include 20 | #define htole32(x) OSSwapHostToLittleInt32(x) 21 | #define le32toh(x) OSSwapLittleToHostInt32(x) 22 | #define htole64(x) OSSwapHostToLittleInt64(x) 23 | #define le64toh(x) OSSwapLittleToHostInt64(x) 24 | 25 | #elif defined(__OpenBSD__) 26 | #include 27 | 28 | #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) 29 | #include 30 | #define le32toh(x) letoh32(x) 31 | #define le64toh(x) letoh64(x) 32 | 33 | #elif defined(__WINDOWS__) 34 | #include 35 | #include 36 | 37 | #if BYTE_ORDER == LITTLE_ENDIAN 38 | #define htole32(x) (x) 39 | #define le32toh(x) (x) 40 | 41 | #define htole64(x) (x) 42 | #define le64toh(x) (x) 43 | 44 | #elif BYTE_ORDER == BIG_ENDIAN 45 | #define htole32(x) __builtin_bswap32(x) 46 | #define le32toh(x) __builtin_bswap32(x) 47 | 48 | #define htole64(x) __builtin_bswap64(x) 49 | #define le64toh(x) __builtin_bswap64(x) 50 | 51 | #else 52 | #error byte order not supported 53 | #endif /* endif byteorder */ 54 | #else 55 | 56 | #error platform not supported 57 | 58 | #endif /* endif platform */ 59 | 60 | #ifndef HAVE_TIMINGSAFE_BCMP 61 | 62 | int timingsafe_bcmp(const void* b1, const void* b2, size_t n) 63 | { 64 | const unsigned char *p1 = b1, *p2 = b2; 65 | int ret = 0; 66 | 67 | for (; n > 0; n--) 68 | ret |= *p1++ ^ *p2++; 69 | return (ret != 0); 70 | } 71 | 72 | #endif /* TIMINGSAFE_BCMP */ 73 | 74 | #ifndef HAVE_MEMSET_S 75 | void memory_cleanse(void* p, size_t n) 76 | { 77 | #if defined(__has_feature) 78 | #if __has_feature(memory_sanitizer) 79 | memset(p, 0, n); 80 | #endif 81 | #endif 82 | } 83 | 84 | #else /* no memset_s available */ 85 | void memory_cleanse(void* p, size_t n) { (void)memset_s(p, n, 0, n); } 86 | #endif 87 | 88 | #define XOR(v, w) ((v) ^ (w)) 89 | 90 | int chacha20poly1305_init(struct chachapolyaead_ctx* ctx, const uint8_t* k_1, int k_1_len, const uint8_t* k_2, int k_2_len) 91 | { 92 | if (k_1_len != CHACHA20_POLY1305_AEAD_KEY_LEN || k_2_len != CHACHA20_POLY1305_AEAD_KEY_LEN) 93 | return -1; 94 | chacha_keysetup(&ctx->main_ctx, k_1, 256); 95 | chacha_keysetup(&ctx->header_ctx, k_2, 256); 96 | ctx->cached_aad_seqnr = UINT64_MAX; 97 | return 0; 98 | } 99 | 100 | int chacha20poly1305_crypt(struct chachapolyaead_ctx* ctx, uint64_t seqnr, uint64_t seqnr_aad, int pos_aad, uint8_t* dest, size_t dest_len, const uint8_t* src, size_t src_len, int is_encrypt) 101 | { 102 | const uint8_t one[8] = {1, 0, 0, 0, 0, 0, 0, 0}; /* NB little-endian */ 103 | uint64_t aad_chacha_nonce_hdr = 0; 104 | uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; 105 | int r = -1; 106 | int aad_pos = 0; 107 | 108 | if ( 109 | // if we encrypt, make sure the source contains at least the expected AAD and the destination has at least space for the source + MAC 110 | (is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN || dest_len < src_len + POLY1305_TAGLEN)) || 111 | // if we decrypt, make sure the source contains at least the expected AAD+MAC and the destination has at least space for the source - MAc 112 | (!is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN || dest_len < src_len - POLY1305_TAGLEN))) { 113 | return r; 114 | } 115 | 116 | uint64_t chacha_iv = htole64(seqnr); 117 | memset(poly_key, 0, sizeof(poly_key)); 118 | chacha_ivsetup(&ctx->main_ctx, (uint8_t*)&chacha_iv, NULL); 119 | chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key)); 120 | 121 | if (!is_encrypt) { 122 | const uint8_t* tag = src + src_len - POLY1305_TAGLEN; 123 | 124 | poly1305_auth(expected_tag, src, src_len - POLY1305_TAGLEN, poly_key); 125 | if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) { 126 | goto out; 127 | } 128 | /* MAC has been successfully verified, make sure we don't covert it in decryption */ 129 | src_len -= POLY1305_TAGLEN; 130 | } 131 | 132 | /* add AAD (encrypted length) */ 133 | if (ctx->cached_aad_seqnr != seqnr_aad) { 134 | ctx->cached_aad_seqnr = seqnr_aad; 135 | aad_chacha_nonce_hdr = htole64(seqnr_aad); 136 | chacha_ivsetup(&ctx->header_ctx, (uint8_t*)&aad_chacha_nonce_hdr, NULL); // block counter 0 137 | chacha_encrypt_bytes(&ctx->header_ctx, NULL, ctx->aad_keystream_buffer, CHACHA20_ROUND_OUTPUT); 138 | } 139 | /* crypt the AAD (3 byte length) */ 140 | dest[0] = XOR(src[0], ctx->aad_keystream_buffer[aad_pos + 0]); 141 | dest[1] = XOR(src[1], ctx->aad_keystream_buffer[aad_pos + 1]); 142 | dest[2] = XOR(src[2], ctx->aad_keystream_buffer[aad_pos + 2]); 143 | 144 | /* Set Chacha's block counter to 1 and encipher */ 145 | chacha_ivsetup(&ctx->main_ctx, (uint8_t*)&chacha_iv, one); 146 | chacha_encrypt_bytes(&ctx->main_ctx, src + CHACHA20_POLY1305_AEAD_AAD_LEN, dest + CHACHA20_POLY1305_AEAD_AAD_LEN, src_len - CHACHA20_POLY1305_AEAD_AAD_LEN); 147 | 148 | /* If encrypting, calculate and append tag */ 149 | if (is_encrypt) { 150 | poly1305_auth(dest + src_len, dest, src_len, poly_key); 151 | } 152 | r = 0; 153 | out: 154 | memory_cleanse(expected_tag, sizeof(expected_tag)); 155 | memory_cleanse(&chacha_iv, sizeof(chacha_iv)); 156 | memory_cleanse(poly_key, sizeof(poly_key)); 157 | return r; 158 | } 159 | 160 | int chacha20poly1305_get_length(struct chachapolyaead_ctx* ctx, 161 | uint32_t* len_out, 162 | uint64_t seqnr, 163 | const uint8_t* ciphertext) 164 | { 165 | uint8_t buf[3], seqbuf[8]; 166 | 167 | int pos = seqnr % AAD_PACKAGES_PER_ROUND * CHACHA20_POLY1305_AEAD_AAD_LEN; 168 | seqnr = seqnr / (float)AAD_PACKAGES_PER_ROUND; /* 21 x 3byte length packages fits in a ChaCha20 round */ 169 | if (ctx->cached_aad_seqnr != seqnr) { 170 | /* we need to calculate the 64 keystream bytes since we reached a new sequence number */ 171 | ctx->cached_aad_seqnr = seqnr; 172 | seqnr = htole64(seqnr); // use LE for the nonce 173 | chacha_ivsetup(&ctx->header_ctx, (uint8_t*)&seqnr, NULL); // block counter 0 174 | chacha_encrypt_bytes(&ctx->header_ctx, NULL, ctx->aad_keystream_buffer, CHACHA20_ROUND_OUTPUT); 175 | } 176 | 177 | /* decrypt the ciphertext length by XORing the right position of the 64byte keystream cache with the ciphertext */ 178 | *len_out = 0; 179 | *len_out = XOR(ciphertext[0], ctx->aad_keystream_buffer[pos + 0]) | 180 | XOR(ciphertext[1], ctx->aad_keystream_buffer[pos + 1]) << 8 | 181 | XOR(ciphertext[2], ctx->aad_keystream_buffer[pos + 2]) << 16; 182 | 183 | /* convert to host endianness 32bit integer (only 24bit though) */ 184 | *len_out = le32toh(*len_out); 185 | return 0; 186 | } -------------------------------------------------------------------------------- /chacha.c: -------------------------------------------------------------------------------- 1 | /* 2 | chacha-merged.c version 20080118 3 | D. J. Bernstein 4 | Public domain. 5 | */ 6 | 7 | #include "chacha.h" 8 | 9 | /* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */ 10 | 11 | typedef unsigned char u8; 12 | typedef unsigned int u32; 13 | 14 | typedef struct chacha_ctx chacha_ctx; 15 | 16 | #define U8C(v) (v##U) 17 | #define U32C(v) (v##U) 18 | 19 | #define U8V(v) ((u8)(v)&U8C(0xFF)) 20 | #define U32V(v) ((u32)(v)&U32C(0xFFFFFFFF)) 21 | 22 | #define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n)))) 23 | 24 | #define U8TO32_LITTLE(p) \ 25 | (((u32)((p)[0])) | ((u32)((p)[1]) << 8) | ((u32)((p)[2]) << 16) | \ 26 | ((u32)((p)[3]) << 24)) 27 | 28 | #define U32TO8_LITTLE(p, v) \ 29 | do { \ 30 | (p)[0] = U8V((v)); \ 31 | (p)[1] = U8V((v) >> 8); \ 32 | (p)[2] = U8V((v) >> 16); \ 33 | (p)[3] = U8V((v) >> 24); \ 34 | } while (0) 35 | 36 | #define ROTATE(v, c) (ROTL32(v, c)) 37 | #define XOR(v, w) ((v) ^ (w)) 38 | #define PLUS(v, w) (U32V((v) + (w))) 39 | #define PLUSONE(v) (PLUS((v), 1)) 40 | 41 | #define QUARTERROUND(a, b, c, d) \ 42 | a = PLUS(a, b); \ 43 | d = ROTATE(XOR(d, a), 16); \ 44 | c = PLUS(c, d); \ 45 | b = ROTATE(XOR(b, c), 12); \ 46 | a = PLUS(a, b); \ 47 | d = ROTATE(XOR(d, a), 8); \ 48 | c = PLUS(c, d); \ 49 | b = ROTATE(XOR(b, c), 7); 50 | 51 | static const char sigma[16] = "expand 32-byte k"; 52 | static const char tau[16] = "expand 16-byte k"; 53 | 54 | void chacha_keysetup(chacha_ctx *x, const u8 *k, u32 kbits) { 55 | const char *constants; 56 | 57 | x->input[4] = U8TO32_LITTLE(k + 0); 58 | x->input[5] = U8TO32_LITTLE(k + 4); 59 | x->input[6] = U8TO32_LITTLE(k + 8); 60 | x->input[7] = U8TO32_LITTLE(k + 12); 61 | if (kbits == 256) { /* recommended */ 62 | k += 16; 63 | constants = sigma; 64 | } else { /* kbits == 128 */ 65 | constants = tau; 66 | } 67 | x->input[8] = U8TO32_LITTLE(k + 0); 68 | x->input[9] = U8TO32_LITTLE(k + 4); 69 | x->input[10] = U8TO32_LITTLE(k + 8); 70 | x->input[11] = U8TO32_LITTLE(k + 12); 71 | x->input[0] = U8TO32_LITTLE(constants + 0); 72 | x->input[1] = U8TO32_LITTLE(constants + 4); 73 | x->input[2] = U8TO32_LITTLE(constants + 8); 74 | x->input[3] = U8TO32_LITTLE(constants + 12); 75 | } 76 | 77 | void chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) { 78 | x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); 79 | x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); 80 | x->input[14] = U8TO32_LITTLE(iv + 0); 81 | x->input[15] = U8TO32_LITTLE(iv + 4); 82 | } 83 | 84 | void chacha_encrypt_bytes(chacha_ctx *x, const u8 *m, u8 *c, u32 bytes) { 85 | u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; 86 | u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; 87 | u8 *ctarget = NULL; 88 | u8 tmp[64]; 89 | uint32_t i; 90 | 91 | if (!bytes) 92 | return; 93 | 94 | j0 = x->input[0]; 95 | j1 = x->input[1]; 96 | j2 = x->input[2]; 97 | j3 = x->input[3]; 98 | j4 = x->input[4]; 99 | j5 = x->input[5]; 100 | j6 = x->input[6]; 101 | j7 = x->input[7]; 102 | j8 = x->input[8]; 103 | j9 = x->input[9]; 104 | j10 = x->input[10]; 105 | j11 = x->input[11]; 106 | j12 = x->input[12]; 107 | j13 = x->input[13]; 108 | j14 = x->input[14]; 109 | j15 = x->input[15]; 110 | 111 | for (;;) { 112 | if (bytes < 64) { 113 | if (m != NULL) { 114 | for (i = 0; i < bytes; ++i) { 115 | tmp[i] = m[i]; 116 | } 117 | m = tmp; 118 | } 119 | ctarget = c; 120 | c = tmp; 121 | } 122 | x0 = j0; 123 | x1 = j1; 124 | x2 = j2; 125 | x3 = j3; 126 | x4 = j4; 127 | x5 = j5; 128 | x6 = j6; 129 | x7 = j7; 130 | x8 = j8; 131 | x9 = j9; 132 | x10 = j10; 133 | x11 = j11; 134 | x12 = j12; 135 | x13 = j13; 136 | x14 = j14; 137 | x15 = j15; 138 | for (i = 20; i > 0; i -= 2) { 139 | QUARTERROUND(x0, x4, x8, x12) 140 | QUARTERROUND(x1, x5, x9, x13) 141 | QUARTERROUND(x2, x6, x10, x14) 142 | QUARTERROUND(x3, x7, x11, x15) 143 | QUARTERROUND(x0, x5, x10, x15) 144 | QUARTERROUND(x1, x6, x11, x12) 145 | QUARTERROUND(x2, x7, x8, x13) 146 | QUARTERROUND(x3, x4, x9, x14) 147 | } 148 | x0 = PLUS(x0, j0); 149 | x1 = PLUS(x1, j1); 150 | x2 = PLUS(x2, j2); 151 | x3 = PLUS(x3, j3); 152 | x4 = PLUS(x4, j4); 153 | x5 = PLUS(x5, j5); 154 | x6 = PLUS(x6, j6); 155 | x7 = PLUS(x7, j7); 156 | x8 = PLUS(x8, j8); 157 | x9 = PLUS(x9, j9); 158 | x10 = PLUS(x10, j10); 159 | x11 = PLUS(x11, j11); 160 | x12 = PLUS(x12, j12); 161 | x13 = PLUS(x13, j13); 162 | x14 = PLUS(x14, j14); 163 | x15 = PLUS(x15, j15); 164 | 165 | if (m != NULL) { 166 | x0 = XOR(x0, U8TO32_LITTLE(m + 0)); 167 | x1 = XOR(x1, U8TO32_LITTLE(m + 4)); 168 | x2 = XOR(x2, U8TO32_LITTLE(m + 8)); 169 | x3 = XOR(x3, U8TO32_LITTLE(m + 12)); 170 | x4 = XOR(x4, U8TO32_LITTLE(m + 16)); 171 | x5 = XOR(x5, U8TO32_LITTLE(m + 20)); 172 | x6 = XOR(x6, U8TO32_LITTLE(m + 24)); 173 | x7 = XOR(x7, U8TO32_LITTLE(m + 28)); 174 | x8 = XOR(x8, U8TO32_LITTLE(m + 32)); 175 | x9 = XOR(x9, U8TO32_LITTLE(m + 36)); 176 | x10 = XOR(x10, U8TO32_LITTLE(m + 40)); 177 | x11 = XOR(x11, U8TO32_LITTLE(m + 44)); 178 | x12 = XOR(x12, U8TO32_LITTLE(m + 48)); 179 | x13 = XOR(x13, U8TO32_LITTLE(m + 52)); 180 | x14 = XOR(x14, U8TO32_LITTLE(m + 56)); 181 | x15 = XOR(x15, U8TO32_LITTLE(m + 60)); 182 | } 183 | j12 = PLUSONE(j12); 184 | if (!j12) { 185 | j13 = PLUSONE(j13); 186 | /* stopping at 2^70 bytes per nonce is user's responsibility */ 187 | } 188 | 189 | U32TO8_LITTLE(c + 0, x0); 190 | U32TO8_LITTLE(c + 4, x1); 191 | U32TO8_LITTLE(c + 8, x2); 192 | U32TO8_LITTLE(c + 12, x3); 193 | U32TO8_LITTLE(c + 16, x4); 194 | U32TO8_LITTLE(c + 20, x5); 195 | U32TO8_LITTLE(c + 24, x6); 196 | U32TO8_LITTLE(c + 28, x7); 197 | U32TO8_LITTLE(c + 32, x8); 198 | U32TO8_LITTLE(c + 36, x9); 199 | U32TO8_LITTLE(c + 40, x10); 200 | U32TO8_LITTLE(c + 44, x11); 201 | U32TO8_LITTLE(c + 48, x12); 202 | U32TO8_LITTLE(c + 52, x13); 203 | U32TO8_LITTLE(c + 56, x14); 204 | U32TO8_LITTLE(c + 60, x15); 205 | 206 | if (bytes <= 64) { 207 | if (bytes < 64) { 208 | for (i = 0; i < bytes; ++i) 209 | ctarget[i] = c[i]; 210 | } 211 | x->input[12] = j12; 212 | x->input[13] = j13; 213 | return; 214 | } 215 | bytes -= 64; 216 | c += 64; 217 | if (m != NULL) { 218 | m += 64; 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /tests.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Copyright (c) 2016 Jonas Schnelli * 3 | * Distributed under the MIT software license, see the accompanying * 4 | * file COPYING or http://www.opensource.org/licenses/mit-license.php.* 5 | **********************************************************************/ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "chacha.h" 13 | #include "chachapoly_aead.h" 14 | #include "poly1305.h" 15 | 16 | struct chacha20_testvector { 17 | uint8_t key[32]; 18 | uint8_t nonce[8]; 19 | uint8_t resulting_keystream[512]; 20 | int keystream_check_size; 21 | }; 22 | 23 | struct poly1305_testvector { 24 | uint8_t input[64]; 25 | int inputlen; 26 | uint8_t key[64]; 27 | uint8_t resulting_tag[16]; 28 | }; 29 | 30 | /* 31 | Testvectors have been taken from the draft RFC 32 | https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 33 | */ 34 | 35 | static const struct chacha20_testvector chacha20_testvectors[] = { 36 | {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 39 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 40 | {0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d, 0x6a, 41 | 0xe5, 0x53, 0x86, 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 42 | 0xed, 0x1a, 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, 0xda, 43 | 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, 0x77, 0x24, 0xe0, 0x3f, 44 | 0xb8, 0xd8, 0x4a, 0x37, 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 45 | 0x1c, 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86}, 46 | 64}, 47 | {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 50 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 51 | {0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96, 0xd7, 0x73, 0x6e, 52 | 0x7b, 0x20, 0x8e, 0x3c, 0x96, 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 53 | 0xd2, 0x60, 0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41, 0xbb, 54 | 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2, 0xa5, 0xd1, 0xe7, 0xe2, 55 | 0x0d, 0x42, 0xaf, 0x2c, 0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 56 | 0x81, 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63}, 57 | 64}, 58 | {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 61 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, 62 | {0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5, 0xe7, 0x86, 0xdc, 0x63, 63 | 0x97, 0x3f, 0x65, 0x3a, 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13, 64 | 0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31, 0xe8, 0x5a, 0x05, 0x02, 65 | 0x78, 0xa7, 0x08, 0x45, 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b, 66 | 0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e, 0x44, 0x5f, 0x41, 0xe3}, 67 | 60}, 68 | {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 71 | {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 72 | {0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb, 0xf5, 0xcf, 0x35, 73 | 0xbd, 0x3d, 0xd3, 0x3b, 0x80, 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 74 | 0x42, 0xac, 0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32, 0x11, 75 | 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c, 0xa8, 0xad, 0x64, 0x26, 76 | 0x19, 0x4a, 0x88, 0x54, 0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 77 | 0x7d, 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b}, 78 | 64}, 79 | {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 80 | 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 81 | 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}, 82 | {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 83 | {0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69, 0x82, 0x10, 0x5f, 0xfb, 84 | 0x64, 0x0b, 0xb7, 0x75, 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93, 85 | 0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1, 0x34, 0xa4, 0x54, 0x7b, 86 | 0x73, 0x3b, 0x46, 0x41, 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69, 87 | 0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1, 0x59, 0x16, 0x15, 0x5c, 88 | 0x2b, 0xe8, 0x24, 0x1a, 0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94, 89 | 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66, 0x89, 0xde, 0x95, 0x26, 90 | 0x49, 0x86, 0xd9, 0x58, 0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd, 91 | 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56, 0x3e, 0xb9, 0xb3, 0xa4, 92 | 0xa4, 0x72, 0xf8, 0x2e, 0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e, 93 | 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7, 0x9d, 0xb9, 0xd4, 0xf7, 94 | 0xc7, 0xa8, 0x99, 0x15, 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3, 95 | 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a, 0x97, 0xa5, 0xf5, 0x76, 96 | 0xfe, 0x06, 0x40, 0x25, 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5, 97 | 0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69, 0x59, 0x66, 0x09, 0x96, 98 | 0x54, 0x6c, 0xc9, 0xc4, 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7, 99 | 0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79, 0xe5, 0xc5, 0x36, 0x0c, 100 | 0x33, 0x17, 0x16, 0x6a, 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a, 101 | 0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2, 0xcc, 0xb2, 0x7d, 0x5a, 102 | 0xaa, 0xe0, 0xad, 0x7a, 0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09, 103 | 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a, 0x6d, 0xeb, 0x3a, 0xb7, 104 | 0x8f, 0xab, 0x78, 0xc9}, 105 | 256}}; 106 | 107 | static const struct poly1305_testvector poly1305_testvectors[] = { 108 | { 109 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 112 | 32, 113 | {0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, 114 | 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, 115 | 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35}, 116 | {0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 117 | 0x1c, 0xcc, 0x03, 0x07}, 118 | }, 119 | {{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21}, 120 | 12, 121 | {0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, 122 | 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, 123 | 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35}, 124 | {0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 125 | 0xee, 0xf2, 0xb2, 0xf0}}}; 126 | 127 | int main(void) 128 | { 129 | struct chacha_ctx ctx; 130 | uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 131 | unsigned int i = 0; 132 | uint8_t keystream[512]; 133 | uint8_t poly1305_tag[16]; 134 | 135 | /* test chacha20 */ 136 | for (i = 0; 137 | i < (sizeof(chacha20_testvectors) / sizeof(chacha20_testvectors[0])); 138 | i++) { 139 | chacha_ivsetup(&ctx, chacha20_testvectors[i].nonce, NULL); 140 | memset(keystream, 0, 512); 141 | chacha_keysetup(&ctx, chacha20_testvectors[i].key, 256); 142 | chacha_encrypt_bytes(&ctx, keystream, keystream, 512); 143 | assert(memcmp(keystream, chacha20_testvectors[i].resulting_keystream, 144 | chacha20_testvectors[i].keystream_check_size) == 0); 145 | } 146 | 147 | /* test poly1305 */ 148 | for (i = 0; 149 | i < (sizeof(poly1305_testvectors) / sizeof(poly1305_testvectors[0])); 150 | i++) { 151 | memset(poly1305_tag, 0, 16); 152 | poly1305_auth(poly1305_tag, poly1305_testvectors[i].input, 153 | poly1305_testvectors[i].inputlen, 154 | poly1305_testvectors[i].key); 155 | assert(memcmp(poly1305_tag, poly1305_testvectors[i].resulting_tag, 16) == 156 | 0); 157 | int i = 100; 158 | } 159 | 160 | /* test chacha20poly1305 AEAD */ 161 | struct chachapolyaead_ctx aead_ctx; 162 | uint32_t seqnr = 0; 163 | uint32_t seqnr_aad = 0; 164 | int pos_aad = 0; 165 | uint8_t aead_k_1[64] = { 166 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 167 | 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 168 | 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; 169 | uint8_t aead_k_2[64] = { 170 | 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 171 | 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 172 | 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; 173 | 174 | uint8_t plaintext_buf[256] = { 175 | 0xff, 0x00, 0x00, 0xf1, 0x95, 0xe6, 0x69, 0x82, 0x10, 0x5f, 0xfb, 176 | 0x64, 0x0b, 0xb7, 0x75, 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93, 177 | 0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1, 0x34, 0xa4, 0x54, 0x7b, 178 | 0x73, 0x3b, 0x46, 0x41, 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69, 179 | 0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1, 0x59, 0x16, 0x15, 0x5c, 180 | 0x2b, 0xe8, 0x24, 0x1a, 0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94, 181 | 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66, 0x89, 0xde, 0x95, 0x26, 182 | 0x49, 0x86, 0xd9, 0x58, 0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd, 183 | 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56, 0x3e, 0xb9, 0xb3, 0xa4, 184 | 0xa4, 0x72, 0xf8, 0x2e, 0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e, 185 | 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7, 0x9d, 0xb9, 0xd4, 0xf7, 186 | 0xc7, 0xa8, 0x99, 0x15, 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3, 187 | 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a, 0x97, 0xa5, 0xf5, 0x76, 188 | 0xfe, 0x06, 0x40, 0x25, 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5, 189 | 0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69, 0x59, 0x66, 0x09, 0x96, 190 | 0x54, 0x6c, 0xc9, 0xc4, 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7, 191 | 0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79, 0xe5, 0xc5, 0x36, 0x0c, 192 | 0x33, 0x17, 0x16, 0x6a, 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a, 193 | 0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2, 0xcc, 0xb2, 0x7d, 0x5a, 194 | 0xaa, 0xe0, 0xad, 0x7a, 0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09, 195 | 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a, 0x6d, 0xeb, 0x3a, 0xb7, 196 | 0x8f, 0xab, 0x78, 0xc9}; 197 | 198 | uint8_t ciphertext_buf[255 + 16] = {0}; 199 | uint8_t plaintext_buf_new[255] = {0}; 200 | chacha20poly1305_init(&aead_ctx, aead_k_1, 32, aead_k_2, 32); 201 | assert((uint32_t)plaintext_buf[0] == 255); 202 | chacha20poly1305_crypt(&aead_ctx, seqnr, seqnr_aad, pos_aad, ciphertext_buf, 300, plaintext_buf, 255, 1); 203 | uint32_t out_len = 0; 204 | chacha20poly1305_get_length(&aead_ctx, &out_len, seqnr, ciphertext_buf); 205 | assert(out_len == 255); 206 | chacha20poly1305_crypt(&aead_ctx, seqnr, seqnr_aad, pos_aad, plaintext_buf_new, 255, ciphertext_buf, 207 | sizeof(ciphertext_buf), 0); 208 | assert(memcmp(plaintext_buf, plaintext_buf_new, 252) == 0); 209 | } 210 | --------------------------------------------------------------------------------