diff --git a/aead_chacha20_poly1305.c b/aead_chacha20_poly1305.c index c1def9f..c565a1c 100644 --- a/aead_chacha20_poly1305.c +++ b/aead_chacha20_poly1305.c @@ -101,10 +101,89 @@ chacha20_poly1305_seal(const uint8_t *key, size_t keylen, const uint8_t *iv, return 1; } +static int +chacha20_poly1305_open(const uint8_t *key, size_t keylen, const uint8_t *iv, + size_t ivlen, uint8_t *out, size_t *outlen, const uint8_t *aad, + size_t aadlen, const uint8_t *in, size_t inlen) +{ + const uint8_t *tagp; + struct chacha20_ctx cctx; + struct poly1305_ctx pctx; + uint8_t poly1305_key[LC_POLY1305_KEYLEN]; + uint8_t tag[LC_POLY1305_TAGLEN]; + uint8_t buf[sizeof(uint64_t) * 2]; + size_t i, olen, ctlen; + + if (inlen < LC_POLY1305_TAGLEN || + inlen > UINT64_MAX || aadlen > UINT64_MAX || + inlen > SIZE_MAX - LC_POLY1305_TAGLEN || + inlen > SIZE_MAX - CHACHA20_CHUNK + 1 || + (inlen + CHACHA20_CHUNK - 1) / CHACHA20_CHUNK > + CHACHA20_CTRMAX - 1) { + if (out == NULL) + *outlen = 0; + return 0; + } + + if (out == NULL) { + *outlen = inlen - LC_POLY1305_TAGLEN; + return 1; + } + + *outlen = 0; + ctlen = inlen - LC_POLY1305_TAGLEN; + tagp = in + ctlen; + + for (i = 0; i < LC_POLY1305_KEYLEN; i++) + poly1305_key[i] = 0; + if (!chacha20_x_init(&cctx, key, keylen, iv, ivlen) || + !chacha20_x_update(&cctx, poly1305_key, &olen, poly1305_key, + LC_POLY1305_KEYLEN)) + return 0; + for (i = 0; i < LC_POLY1305_KEYLEN / sizeof(uint32_t); i++) + store32le(&poly1305_key[i * 4], cctx.s[i]); + + if (!poly1305_init(&pctx, poly1305_key, LC_POLY1305_KEYLEN) || + !poly1305_update(&pctx, aad, aadlen)) + return 0; + if (aadlen % 16 != 0) + if (!poly1305_update(&pctx, zeropad, 16 - (aadlen % 16))) + return 0; + + if (!poly1305_update(&pctx, in, ctlen)) + return 0; + if (ctlen % 16 != 0) + if (!poly1305_update(&pctx, zeropad, 16 - (ctlen % 16))) + return 0; + + store64le(&buf[0], aadlen); + store64le(&buf[sizeof(uint64_t)], ctlen); + if (!poly1305_update(&pctx, buf, sizeof(buf)) || + !poly1305_final(&pctx, tag, &olen)) + return 0; + + if (lc_ct_cmp(tag, tagp, LC_POLY1305_TAGLEN) != 0) + return 0; + + lc_scrub(buf, sizeof(buf)); + lc_scrub(poly1305_key, sizeof(poly1305_key)); + + if (!chacha20_x_init_from(&cctx, key, keylen, iv, ivlen, 1)) + return 0; + if (!chacha20_x_update(&cctx, out, &olen, in, ctlen)) + return 0; + *outlen = olen; + if (!chacha20_x_final(&cctx, out + olen, &olen)) + return 0; + *outlen += olen; + + return 1; +} + static struct lc_aead_impl chacha20_poly1305_impl = { .seal = &chacha20_poly1305_seal, - .open = NULL, //&chacha20_poly1305_open, + .open = &chacha20_poly1305_open, }; const struct lc_aead_impl *