DF-3388 / chachapoly_user.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | /* * chacha20poly1305 buffer-only AEAD, userspace port of * sys/crypto/chachapoly.c (buffer functions only, no mbuf). */ #include <sys/types.h> #include <sys/endian.h> #include <sys/systm.h> #include <sys/param.h> #include <crypto/chacha20/chacha.h> #include <crypto/poly1305/poly1305.h> #define CHACHA20POLY1305_KEY_SIZE 32 #define CHACHA20POLY1305_AUTHTAG_SIZE 16 #define CHACHA20POLY1305_NONCE_SIZE 12 struct cp_ctx { struct chacha_ctx chacha; poly1305_state poly; uint8_t tag[16]; size_t ad_len; size_t data_len; int flags; }; #define PADDING_SIZE 16 #define PADDING_LEN(len) \ ((PADDING_SIZE - ((len) & (PADDING_SIZE - 1))) & (PADDING_SIZE - 1)) static const uint8_t pad0[PADDING_SIZE] = { 0 }; static void cp_init(struct cp_ctx *ctx, int enc, const uint8_t nonce[12], const uint8_t key[32]) { uint8_t poly_key[32]; uint8_t nonce64[CHACHA_NONCELEN], counter64[CHACHA_CTRLEN]; bzero(ctx, sizeof(*ctx)); bzero(poly_key, sizeof(poly_key)); bzero(nonce64, sizeof(nonce64)); bzero(counter64, sizeof(counter64)); memcpy(counter64 + 4, nonce, 4); memcpy(nonce64, nonce + 4, 8); chacha_keysetup(&ctx->chacha, key, 32 * 8); chacha_ivsetup(&ctx->chacha, nonce64, counter64); chacha_encrypt_bytes(&ctx->chacha, poly_key, poly_key, sizeof(poly_key)); poly1305_init(&ctx->poly, poly_key); ctx->flags = 2 | (enc ? 1 : 0); } static void cp_update_ad(struct cp_ctx *ctx, const uint8_t *ad, size_t ad_len) { if (ad_len == 0 || ad == NULL) return; poly1305_update(&ctx->poly, ad, ad_len); ctx->ad_len += ad_len; } static void cp_final(struct cp_ctx *ctx, uint8_t *dst, const uint8_t *src, size_t len) { uint64_t lens[2]; uint8_t tag[16]; if (ctx->ad_len > 0 && (ctx->flags & 4) == 0) { poly1305_update(&ctx->poly, pad0, PADDING_LEN(ctx->ad_len)); ctx->flags |= 4; } if (len > 0) { if (ctx->flags & 1) { chacha_encrypt_bytes(&ctx->chacha, src, dst, len); poly1305_update(&ctx->poly, dst, len); } else { poly1305_update(&ctx->poly, src, len); chacha_encrypt_bytes(&ctx->chacha, src, dst, len); } poly1305_update(&ctx->poly, pad0, PADDING_LEN(len)); ctx->data_len += len; } lens[0] = htole64(ctx->ad_len); lens[1] = htole64(ctx->data_len); poly1305_update(&ctx->poly, (uint8_t *)lens, sizeof(lens)); poly1305_finish(&ctx->poly, tag); memcpy(ctx->tag, tag, 16); } void cp_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t nonce[12], const uint8_t key[32]) { struct cp_ctx ctx; size_t len; cp_init(&ctx, 1, nonce, key); cp_update_ad(&ctx, ad, ad_len); len = rounddown2(src_len, CHACHA_BLOCKLEN); if (len) { /* complete blocks */ poly1305_update(&ctx.poly, pad0, PADDING_LEN(ctx.ad_len)); ctx.flags |= 4; chacha_encrypt_bytes(&ctx.chacha, src, dst, len); poly1305_update(&ctx.poly, dst, len); ctx.data_len += len; } cp_final(&ctx, dst + len, src + len, src_len - len); memcpy(dst + src_len, ctx.tag, 16); } |