chachapoly.c revision 1.5
1/* 2 * Copyright (c) 2015 Mike Belopuhov 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include <sys/param.h> 18#include <sys/systm.h> 19#include <lib/libkern/libkern.h> 20 21#include <crypto/chacha_private.h> 22#include <crypto/poly1305.h> 23#include <crypto/chachapoly.h> 24 25int 26chacha20_setkey(void *sched, u_int8_t *key, int len) 27{ 28 struct chacha20_ctx *ctx = (struct chacha20_ctx *)sched; 29 30 if (len != CHACHA20_KEYSIZE + CHACHA20_SALT) 31 return (-1); 32 33 /* initial counter is 1 */ 34 ctx->nonce[0] = 1; 35 memcpy(ctx->nonce + CHACHA20_CTR, key + CHACHA20_KEYSIZE, 36 CHACHA20_SALT); 37 chacha_keysetup((chacha_ctx *)&ctx->block, key, CHACHA20_KEYSIZE * 8); 38 return (0); 39} 40 41void 42chacha20_reinit(caddr_t key, u_int8_t *iv) 43{ 44 struct chacha20_ctx *ctx = (struct chacha20_ctx *)key; 45 46 chacha_ivsetup((chacha_ctx *)ctx->block, iv, ctx->nonce); 47} 48 49void 50chacha20_crypt(caddr_t key, u_int8_t *data) 51{ 52 struct chacha20_ctx *ctx = (struct chacha20_ctx *)key; 53 54 chacha_encrypt_bytes((chacha_ctx *)ctx->block, data, data, 55 CHACHA20_BLOCK_LEN); 56} 57 58void 59Chacha20_Poly1305_Init(void *xctx) 60{ 61 CHACHA20_POLY1305_CTX *ctx = xctx; 62 63 memset(ctx, 0, sizeof(*ctx)); 64} 65 66void 67Chacha20_Poly1305_Setkey(void *xctx, const uint8_t *key, uint16_t klen) 68{ 69 CHACHA20_POLY1305_CTX *ctx = xctx; 70 71 /* salt is provided with the key material */ 72 memcpy(ctx->nonce + CHACHA20_CTR, key + CHACHA20_KEYSIZE, 73 CHACHA20_SALT); 74 chacha_keysetup((chacha_ctx *)&ctx->chacha, key, CHACHA20_KEYSIZE * 8); 75} 76 77void 78Chacha20_Poly1305_Reinit(void *xctx, const uint8_t *iv, uint16_t ivlen) 79{ 80 CHACHA20_POLY1305_CTX *ctx = xctx; 81 82 /* initial counter is 0 */ 83 chacha_ivsetup((chacha_ctx *)&ctx->chacha, iv, ctx->nonce); 84 chacha_encrypt_bytes((chacha_ctx *)&ctx->chacha, ctx->key, ctx->key, 85 POLY1305_KEYLEN); 86 poly1305_init((poly1305_state *)&ctx->poly, ctx->key); 87} 88 89int 90Chacha20_Poly1305_Update(void *xctx, const uint8_t *data, uint16_t len) 91{ 92 static const char zeroes[POLY1305_BLOCK_LEN]; 93 CHACHA20_POLY1305_CTX *ctx = xctx; 94 size_t rem; 95 96 poly1305_update((poly1305_state *)&ctx->poly, data, len); 97 98 /* number of bytes in the last 16 byte block */ 99 rem = (len + POLY1305_BLOCK_LEN) & (POLY1305_BLOCK_LEN - 1); 100 if (rem > 0) 101 poly1305_update((poly1305_state *)&ctx->poly, zeroes, 102 POLY1305_BLOCK_LEN - rem); 103 return (0); 104} 105 106void 107Chacha20_Poly1305_Final(uint8_t tag[POLY1305_TAGLEN], void *xctx) 108{ 109 CHACHA20_POLY1305_CTX *ctx = xctx; 110 111 poly1305_finish((poly1305_state *)&ctx->poly, tag); 112 explicit_bzero(ctx, sizeof(*ctx)); 113} 114 115static const uint8_t pad0[16] = { 0 }; 116 117void 118chacha20poly1305_encrypt( 119 uint8_t *dst, 120 const uint8_t *src, 121 const size_t src_len, 122 const uint8_t *ad, 123 const size_t ad_len, 124 const uint64_t nonce, 125 const uint8_t key[CHACHA20POLY1305_KEY_SIZE] 126) { 127 poly1305_state poly1305_ctx; 128 chacha_ctx chacha_ctx; 129 union { 130 uint8_t b0[CHACHA20POLY1305_KEY_SIZE]; 131 uint64_t lens[2]; 132 } b = { { 0 } }; 133 uint64_t le_nonce = htole64(nonce); 134 135 chacha_keysetup(&chacha_ctx, key, CHACHA20POLY1305_KEY_SIZE * 8); 136 chacha_ivsetup(&chacha_ctx, (uint8_t *) &le_nonce, NULL); 137 chacha_encrypt_bytes(&chacha_ctx, b.b0, b.b0, sizeof(b.b0)); 138 poly1305_init(&poly1305_ctx, b.b0); 139 140 poly1305_update(&poly1305_ctx, ad, ad_len); 141 poly1305_update(&poly1305_ctx, pad0, (0x10 - ad_len) & 0xf); 142 143 chacha_encrypt_bytes(&chacha_ctx, (uint8_t *) src, dst, src_len); 144 145 poly1305_update(&poly1305_ctx, dst, src_len); 146 poly1305_update(&poly1305_ctx, pad0, (0x10 - src_len) & 0xf); 147 148 b.lens[0] = htole64(ad_len); 149 b.lens[1] = htole64(src_len); 150 poly1305_update(&poly1305_ctx, (uint8_t *)b.lens, sizeof(b.lens)); 151 152 poly1305_finish(&poly1305_ctx, dst + src_len); 153 154 explicit_bzero(&chacha_ctx, sizeof(chacha_ctx)); 155 explicit_bzero(&b, sizeof(b)); 156} 157 158int 159chacha20poly1305_decrypt( 160 uint8_t *dst, 161 const uint8_t *src, 162 const size_t src_len, 163 const uint8_t *ad, 164 const size_t ad_len, 165 const uint64_t nonce, 166 const uint8_t key[CHACHA20POLY1305_KEY_SIZE] 167) { 168 poly1305_state poly1305_ctx; 169 chacha_ctx chacha_ctx; 170 int ret; 171 size_t dst_len; 172 union { 173 uint8_t b0[CHACHA20POLY1305_KEY_SIZE]; 174 uint8_t mac[CHACHA20POLY1305_AUTHTAG_SIZE]; 175 uint64_t lens[2]; 176 } b = { { 0 } }; 177 uint64_t le_nonce = htole64(nonce); 178 179 if (src_len < CHACHA20POLY1305_AUTHTAG_SIZE) 180 return 0; 181 182 chacha_keysetup(&chacha_ctx, key, CHACHA20POLY1305_KEY_SIZE * 8); 183 chacha_ivsetup(&chacha_ctx, (uint8_t *) &le_nonce, NULL); 184 chacha_encrypt_bytes(&chacha_ctx, b.b0, b.b0, sizeof(b.b0)); 185 poly1305_init(&poly1305_ctx, b.b0); 186 187 poly1305_update(&poly1305_ctx, ad, ad_len); 188 poly1305_update(&poly1305_ctx, pad0, (0x10 - ad_len) & 0xf); 189 190 dst_len = src_len - CHACHA20POLY1305_AUTHTAG_SIZE; 191 poly1305_update(&poly1305_ctx, src, dst_len); 192 poly1305_update(&poly1305_ctx, pad0, (0x10 - dst_len) & 0xf); 193 194 b.lens[0] = htole64(ad_len); 195 b.lens[1] = htole64(dst_len); 196 poly1305_update(&poly1305_ctx, (uint8_t *)b.lens, sizeof(b.lens)); 197 198 poly1305_finish(&poly1305_ctx, b.mac); 199 200 ret = timingsafe_bcmp(b.mac, src + dst_len, CHACHA20POLY1305_AUTHTAG_SIZE); 201 if (!ret) 202 chacha_encrypt_bytes(&chacha_ctx, (uint8_t *) src, dst, dst_len); 203 204 explicit_bzero(&chacha_ctx, sizeof(chacha_ctx)); 205 explicit_bzero(&b, sizeof(b)); 206 207 return !ret; 208} 209 210void 211xchacha20poly1305_encrypt( 212 uint8_t *dst, 213 const uint8_t *src, 214 const size_t src_len, 215 const uint8_t *ad, 216 const size_t ad_len, 217 const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], 218 const uint8_t key[CHACHA20POLY1305_KEY_SIZE] 219) { 220 int i; 221 uint32_t derived_key[CHACHA20POLY1305_KEY_SIZE / sizeof(uint32_t)]; 222 uint64_t h_nonce; 223 224 memcpy(&h_nonce, nonce + 16, sizeof(h_nonce)); 225 h_nonce = le64toh(h_nonce); 226 hchacha20(derived_key, nonce, key); 227 228 for(i = 0; i < (sizeof(derived_key)/sizeof(derived_key[0])); i++) 229 (derived_key[i]) = htole32((derived_key[i])); 230 231 chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, 232 h_nonce, (uint8_t *)derived_key); 233 explicit_bzero(derived_key, CHACHA20POLY1305_KEY_SIZE); 234} 235 236int 237xchacha20poly1305_decrypt( 238 uint8_t *dst, 239 const uint8_t *src, 240 const size_t src_len, 241 const uint8_t *ad, 242 const size_t ad_len, 243 const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], 244 const uint8_t key[CHACHA20POLY1305_KEY_SIZE] 245) { 246 int ret, i; 247 uint32_t derived_key[CHACHA20POLY1305_KEY_SIZE / sizeof(uint32_t)]; 248 uint64_t h_nonce; 249 250 memcpy(&h_nonce, nonce + 16, sizeof(h_nonce)); 251 h_nonce = le64toh(h_nonce); 252 hchacha20(derived_key, nonce, key); 253 for(i = 0; i < (sizeof(derived_key)/sizeof(derived_key[0])); i++) 254 (derived_key[i]) = htole32((derived_key[i])); 255 256 ret = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, 257 h_nonce, (uint8_t *)derived_key); 258 explicit_bzero(derived_key, CHACHA20POLY1305_KEY_SIZE); 259 260 return ret; 261} 262