diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2020-06-21 10:50:02 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2020-06-21 10:50:02 +0000 |
commit | 1ee3d497a8c045a9637de8c7cb2011b6d1c08977 (patch) | |
tree | df1a405e7c7940101ec96adea564fb4845c54889 /sys/crypto | |
parent | 01bbaf06e9817ff51f18360b7e35d975381ec44c (diff) |
add constructions for wireguard.
from Matt Dunwoodie and Jason A. Donenfeld
ok deraadt@
Diffstat (limited to 'sys/crypto')
-rw-r--r-- | sys/crypto/chachapoly.c | 151 | ||||
-rw-r--r-- | sys/crypto/chachapoly.h | 23 |
2 files changed, 174 insertions, 0 deletions
diff --git a/sys/crypto/chachapoly.c b/sys/crypto/chachapoly.c index ffaabd24312..b96d6e9b1e7 100644 --- a/sys/crypto/chachapoly.c +++ b/sys/crypto/chachapoly.c @@ -16,6 +16,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <lib/libkern/libkern.h> #include <crypto/chacha_private.h> #include <crypto/poly1305.h> @@ -110,3 +111,153 @@ Chacha20_Poly1305_Final(uint8_t tag[POLY1305_TAGLEN], void *xctx) poly1305_finish((poly1305_state *)&ctx->poly, tag); explicit_bzero(ctx, sizeof(*ctx)); } + +static const uint8_t pad0[16] = { 0 }; + +void +chacha20poly1305_encrypt( + uint8_t *dst, + const uint8_t *src, + const size_t src_len, + const uint8_t *ad, + const size_t ad_len, + const uint64_t nonce, + const uint8_t key[CHACHA20POLY1305_KEY_SIZE] +) { + poly1305_state poly1305_ctx; + chacha_ctx chacha_ctx; + union { + uint8_t b0[CHACHA20POLY1305_KEY_SIZE]; + uint64_t lens[2]; + } b = { { 0 } }; + uint64_t le_nonce = htole64(nonce); + + chacha_keysetup(&chacha_ctx, key, CHACHA20POLY1305_KEY_SIZE * 8); + chacha_ivsetup(&chacha_ctx, (uint8_t *) &le_nonce, NULL); + chacha_encrypt_bytes(&chacha_ctx, b.b0, b.b0, sizeof(b.b0)); + poly1305_init(&poly1305_ctx, b.b0); + + poly1305_update(&poly1305_ctx, ad, ad_len); + poly1305_update(&poly1305_ctx, pad0, (0x10 - ad_len) & 0xf); + + chacha_encrypt_bytes(&chacha_ctx, (uint8_t *) src, dst, src_len); + + poly1305_update(&poly1305_ctx, dst, src_len); + poly1305_update(&poly1305_ctx, pad0, (0x10 - src_len) & 0xf); + + b.lens[0] = htole64(ad_len); + b.lens[1] = htole64(src_len); + poly1305_update(&poly1305_ctx, (uint8_t *)b.lens, sizeof(b.lens)); + + poly1305_finish(&poly1305_ctx, dst + src_len); + + explicit_bzero(&chacha_ctx, sizeof(chacha_ctx)); + explicit_bzero(&b, sizeof(b)); +} + +int +chacha20poly1305_decrypt( + uint8_t *dst, + const uint8_t *src, + const size_t src_len, + const uint8_t *ad, + const size_t ad_len, + const uint64_t nonce, + const uint8_t key[CHACHA20POLY1305_KEY_SIZE] +) { + poly1305_state poly1305_ctx; + chacha_ctx chacha_ctx; + int ret; + size_t dst_len; + union { + uint8_t b0[CHACHA20POLY1305_KEY_SIZE]; + uint8_t mac[CHACHA20POLY1305_AUTHTAG_SIZE]; + uint64_t lens[2]; + } b = { { 0 } }; + uint64_t le_nonce = htole64(nonce); + + if (src_len < CHACHA20POLY1305_AUTHTAG_SIZE) + return 0; + + chacha_keysetup(&chacha_ctx, key, CHACHA20POLY1305_KEY_SIZE * 8); + chacha_ivsetup(&chacha_ctx, (uint8_t *) &le_nonce, NULL); + chacha_encrypt_bytes(&chacha_ctx, b.b0, b.b0, sizeof(b.b0)); + poly1305_init(&poly1305_ctx, b.b0); + + poly1305_update(&poly1305_ctx, ad, ad_len); + poly1305_update(&poly1305_ctx, pad0, (0x10 - ad_len) & 0xf); + + dst_len = src_len - CHACHA20POLY1305_AUTHTAG_SIZE; + poly1305_update(&poly1305_ctx, src, dst_len); + poly1305_update(&poly1305_ctx, pad0, (0x10 - dst_len) & 0xf); + + b.lens[0] = htole64(ad_len); + b.lens[1] = htole64(dst_len); + poly1305_update(&poly1305_ctx, (uint8_t *)b.lens, sizeof(b.lens)); + + poly1305_finish(&poly1305_ctx, b.mac); + + ret = timingsafe_bcmp(b.mac, src + dst_len, CHACHA20POLY1305_AUTHTAG_SIZE); + if (!ret) + chacha_encrypt_bytes(&chacha_ctx, (uint8_t *) src, dst, dst_len); + + explicit_bzero(&chacha_ctx, sizeof(chacha_ctx)); + explicit_bzero(&b, sizeof(b)); + + return !ret; +} + +void +xchacha20poly1305_encrypt( + uint8_t *dst, + const uint8_t *src, + const size_t src_len, + const uint8_t *ad, + const size_t ad_len, + const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], + const uint8_t key[CHACHA20POLY1305_KEY_SIZE] +) { + int i; + uint32_t derived_key[CHACHA20POLY1305_KEY_SIZE / sizeof(uint32_t)] + __aligned(16); + uint64_t h_nonce; + + memcpy(&h_nonce, nonce + 16, sizeof(h_nonce)); + h_nonce = le64toh(h_nonce); + hchacha20(derived_key, nonce, key); + + for(i = 0; i < (sizeof(derived_key)/sizeof(derived_key[0])); i++) + (derived_key[i]) = htole32((derived_key[i])); + + chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, + h_nonce, (uint8_t *)derived_key); + explicit_bzero(derived_key, CHACHA20POLY1305_KEY_SIZE); +} + +int +xchacha20poly1305_decrypt( + uint8_t *dst, + const uint8_t *src, + const size_t src_len, + const uint8_t *ad, + const size_t ad_len, + const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], + const uint8_t key[CHACHA20POLY1305_KEY_SIZE] +) { + int ret, i; + uint32_t derived_key[CHACHA20POLY1305_KEY_SIZE / sizeof(uint32_t)] + __aligned(16); + uint64_t h_nonce; + + memcpy(&h_nonce, nonce + 16, sizeof(h_nonce)); + h_nonce = le64toh(h_nonce); + hchacha20(derived_key, nonce, key); + for(i = 0; i < (sizeof(derived_key)/sizeof(derived_key[0])); i++) + (derived_key[i]) = htole32((derived_key[i])); + + ret = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, + h_nonce, (uint8_t *)derived_key); + explicit_bzero(derived_key, CHACHA20POLY1305_KEY_SIZE); + + return ret; +} diff --git a/sys/crypto/chachapoly.h b/sys/crypto/chachapoly.h index 60ced96504a..4469d58c6de 100644 --- a/sys/crypto/chachapoly.h +++ b/sys/crypto/chachapoly.h @@ -59,4 +59,27 @@ void Chacha20_Poly1305_Reinit(void *, const uint8_t *, uint16_t); int Chacha20_Poly1305_Update(void *, const uint8_t *, uint16_t); void Chacha20_Poly1305_Final(uint8_t[POLY1305_TAGLEN], void *); +/* WireGuard crypto */ +#define CHACHA20POLY1305_KEY_SIZE CHACHA20_KEYSIZE +#define CHACHA20POLY1305_AUTHTAG_SIZE POLY1305_TAGLEN +#define XCHACHA20POLY1305_NONCE_SIZE 24 + +void chacha20poly1305_encrypt(uint8_t *, const uint8_t *, const size_t, + const uint8_t *, const size_t, const uint64_t, + const uint8_t[CHACHA20POLY1305_KEY_SIZE]); + +int chacha20poly1305_decrypt(uint8_t *, const uint8_t *, const size_t, + const uint8_t *, const size_t, const uint64_t, + const uint8_t[CHACHA20POLY1305_KEY_SIZE]); + +void xchacha20poly1305_encrypt(uint8_t *, const uint8_t *, const size_t, + const uint8_t *, const size_t, + const uint8_t[XCHACHA20POLY1305_NONCE_SIZE], + const uint8_t[CHACHA20POLY1305_KEY_SIZE]); + +int xchacha20poly1305_decrypt(uint8_t *, const uint8_t *, const size_t, + const uint8_t *, const size_t, + const uint8_t[XCHACHA20POLY1305_NONCE_SIZE], + const uint8_t[CHACHA20POLY1305_KEY_SIZE]); + #endif /* _CHACHAPOLY_H_ */ |