diff options
Diffstat (limited to '')
-rw-r--r-- | web/server/h2o/libh2o/deps/picotls/deps/cifra/src/chacha20poly1305.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/chacha20poly1305.c b/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/chacha20poly1305.c new file mode 100644 index 00000000..0aef7254 --- /dev/null +++ b/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/chacha20poly1305.c @@ -0,0 +1,148 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com> + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#include "chacha20poly1305.h" +#include "salsa20.h" +#include "poly1305.h" +#include "bitops.h" +#include "handy.h" + +#define ENCRYPT 1 +#define DECRYPT 0 + +#define SUCCESS 0 +#define FAILURE 1 + +static int process(const uint8_t key[32], + const uint8_t nonce[12], + const uint8_t *header, size_t nheader, + const uint8_t *input, size_t nbytes, + uint8_t *output, + int mode, + uint8_t tag[16]) +{ + /* First, generate the Poly1305 key by running ChaCha20 with the + * given key and a zero counter. The first half of the + * 64-byte output is the key. */ + uint8_t fullnonce[16] = { 0 }; + memcpy(fullnonce + 4, nonce, 12); + + uint8_t polykey[32] = { 0 }; + cf_chacha20_ctx chacha; + cf_chacha20_init_custom(&chacha, key, 32, fullnonce, 4); + cf_chacha20_cipher(&chacha, polykey, polykey, sizeof polykey); + + /* Now initialise Poly1305. */ + cf_poly1305 poly; + cf_poly1305_init(&poly, polykey, polykey + 16); + mem_clean(polykey, sizeof polykey); + + /* Discard next 32 bytes of chacha20 key stream. */ + cf_chacha20_cipher(&chacha, polykey, polykey, sizeof polykey); + mem_clean(polykey, sizeof polykey); + + /* The input to Poly1305 is: + * AAD || pad(AAD) || cipher || pad(cipher) || len_64(aad) || len_64(cipher) */ + uint8_t padbuf[16] = { 0 }; + +#define PADLEN(x) (16 - ((x) & 0xf)) + + /* AAD || pad(AAD) */ + cf_poly1305_update(&poly, header, nheader); + cf_poly1305_update(&poly, padbuf, PADLEN(nheader)); + + /* || cipher */ + if (mode == ENCRYPT) + { + /* If we're encrypting, we compute the ciphertext + * before inputting it into the MAC. */ + cf_chacha20_cipher(&chacha, input, output, nbytes); + cf_poly1305_update(&poly, output, nbytes); + } else { + /* Otherwise: decryption -- input the ciphertext. + * Delay actual decryption until we checked the MAC. */ + cf_poly1305_update(&poly, input, nbytes); + } + + /* || pad(cipher) */ + cf_poly1305_update(&poly, padbuf, PADLEN(nbytes)); + + /* || len_64(aad) || len_64(cipher) */ + write64_le(nheader, padbuf); + write64_le(nbytes, padbuf + 8); + cf_poly1305_update(&poly, padbuf, sizeof padbuf); + + /* MAC computation is now complete. */ + + if (mode == ENCRYPT) + { + cf_poly1305_finish(&poly, tag); + mem_clean(&chacha, sizeof chacha); + return SUCCESS; + } + + /* Decrypt mode: calculate tag, and check it. + * If it's correct, proceed with decryption. */ + uint8_t checktag[16]; + cf_poly1305_finish(&poly, checktag); + + if (mem_eq(checktag, tag, sizeof checktag)) + { + cf_chacha20_cipher(&chacha, input, output, nbytes); + mem_clean(&chacha, sizeof chacha); + mem_clean(checktag, sizeof checktag); + return SUCCESS; + } else { + mem_clean(output, nbytes); + mem_clean(&chacha, sizeof chacha); + mem_clean(checktag, sizeof checktag); + return FAILURE; + } +} + +void cf_chacha20poly1305_encrypt(const uint8_t key[32], + const uint8_t nonce[12], + const uint8_t *header, size_t nheader, + const uint8_t *plaintext, size_t nbytes, + uint8_t *ciphertext, + uint8_t tag[16]) +{ + process(key, + nonce, + header, nheader, + plaintext, nbytes, + ciphertext, + ENCRYPT, + tag); +} + +int cf_chacha20poly1305_decrypt(const uint8_t key[32], + const uint8_t nonce[12], + const uint8_t *header, size_t nheader, + const uint8_t *ciphertext, size_t nbytes, + const uint8_t tag[16], + uint8_t *plaintext) +{ + uint8_t ourtag[16]; + memcpy(ourtag, tag, sizeof ourtag); + + return process(key, + nonce, + header, nheader, + ciphertext, nbytes, + plaintext, + DECRYPT, + ourtag); +} + |