aead: replace init args with implementation-specific params struct
This unbreaks {,X}ChaCha20-Poly1305. Thanks to the use of params, the {,X}ChaCha20-Poly1305 doesn't need to reach into the guts of ChaCha20 state. Move {en,de}cryption and key setup into its own functions. This breaks the tests, which will be fixed in the following commit.
This commit is contained in:
parent
79ce4400dd
commit
a6208487e4
14
aead.c
14
aead.c
@ -20,18 +20,16 @@
|
||||
|
||||
int
|
||||
lc_aead_seal(const struct lc_aead_impl *impl, uint8_t *out, size_t *outlen,
|
||||
const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
|
||||
const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen)
|
||||
const void *argparams, const uint8_t *aad, size_t aadlen,
|
||||
const uint8_t *in, size_t inlen)
|
||||
{
|
||||
return impl->seal(out, outlen, key, keylen, iv, ivlen, aad, aadlen, in,
|
||||
inlen);
|
||||
return impl->seal(out, outlen, argparams, aad, aadlen, in, inlen);
|
||||
}
|
||||
|
||||
int
|
||||
lc_aead_open(const struct lc_aead_impl *impl, uint8_t *out, size_t *outlen,
|
||||
const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
|
||||
const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen)
|
||||
const void *argparams, const uint8_t *aad, size_t aadlen,
|
||||
const uint8_t *in, size_t inlen)
|
||||
{
|
||||
return impl->open(out, outlen, key, keylen, iv, ivlen, aad, aadlen, in,
|
||||
inlen);
|
||||
return impl->open(out, outlen, argparams, aad, aadlen, in, inlen);
|
||||
}
|
||||
|
10
aead.h
10
aead.h
@ -19,10 +19,8 @@
|
||||
|
||||
|
||||
struct lc_aead_impl {
|
||||
int (*seal)(uint8_t *, size_t *, const uint8_t *, size_t,
|
||||
const uint8_t *, size_t, const uint8_t *, size_t,
|
||||
const uint8_t *, size_t);
|
||||
int (*open)(uint8_t *, size_t *, const uint8_t *, size_t,
|
||||
const uint8_t *, size_t, const uint8_t *, size_t,
|
||||
const uint8_t *, size_t);
|
||||
int (*seal)(uint8_t *, size_t *, const void *, const uint8_t *,
|
||||
size_t, const uint8_t *, size_t);
|
||||
int (*open)(uint8_t *, size_t *, const void *, const uint8_t *,
|
||||
size_t, const uint8_t *, size_t);
|
||||
};
|
||||
|
@ -16,10 +16,7 @@
|
||||
|
||||
#include "lilcrypto.h"
|
||||
#include "aead.h"
|
||||
#include "auth_poly1305.h"
|
||||
#include "cipher_chacha20.h"
|
||||
#include "impl_chacha20.h"
|
||||
#include "impl_poly1305.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
@ -31,99 +28,230 @@
|
||||
|
||||
static const uint8_t zeropad[16];
|
||||
|
||||
static int
|
||||
aead_poly1305_keysetup(struct lc_cipher_ctx *cctx,
|
||||
uint8_t akey[LC_POLY1305_KEYLEN], const void *initparams)
|
||||
{
|
||||
size_t i, olen, akeylen;
|
||||
|
||||
for (i = 0; i < LC_POLY1305_KEYLEN; i++)
|
||||
akey[i] = 0;
|
||||
if (!lc_cipher_encrypt_init(cctx, initparams) ||
|
||||
!lc_cipher_encrypt_update(cctx, akey, &olen, akey,
|
||||
LC_POLY1305_KEYLEN))
|
||||
return 0;
|
||||
akeylen = olen;
|
||||
if (!lc_cipher_encrypt_final(cctx, akey + olen, &olen))
|
||||
return 0;
|
||||
akeylen += olen;
|
||||
|
||||
return akeylen == LC_POLY1305_KEYLEN;
|
||||
}
|
||||
|
||||
static int
|
||||
chacha20_poly1305_seal(uint8_t *out, size_t *outlen, const uint8_t *key,
|
||||
size_t keylen, const uint8_t *iv, size_t ivlen, const uint8_t *aad,
|
||||
size_t aadlen, const uint8_t *in, size_t inlen)
|
||||
aead_poly1305_anycrypt(struct lc_cipher_ctx *cctx, uint8_t *out,
|
||||
size_t *outlen, const void *initparams, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
struct chacha20_ctx cctx;
|
||||
struct poly1305_ctx pctx;
|
||||
uint8_t poly1305_key[LC_POLY1305_KEYLEN];
|
||||
uint8_t buf[sizeof(uint64_t) * 2];
|
||||
size_t i, olen;
|
||||
size_t olen;
|
||||
|
||||
if (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;
|
||||
if (!lc_cipher_encrypt_init(cctx, initparams) ||
|
||||
!lc_cipher_encrypt_update(cctx, out, &olen, in, inlen))
|
||||
return 0;
|
||||
*outlen = olen;
|
||||
if (!lc_cipher_encrypt_final(cctx, out + olen, &olen))
|
||||
return 0;
|
||||
*outlen += olen;
|
||||
|
||||
return *outlen == inlen;
|
||||
}
|
||||
|
||||
static int
|
||||
chacha20_poly1305_seal(uint8_t *out, size_t *outlen, const void *initparams,
|
||||
const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
const struct lc_chacha20_poly1305_params *params = initparams;
|
||||
struct lc_cipher_ctx *cctx = NULL;
|
||||
struct lc_auth_ctx *actx = NULL;
|
||||
struct lc_chacha20_params cparams;
|
||||
struct lc_poly1305_params aparams;
|
||||
uint8_t buf[sizeof(uint64_t) * 2];
|
||||
size_t i, olen;
|
||||
int ret = 0;
|
||||
|
||||
*outlen = 0;
|
||||
/* inlen and aadlen are capped by design; enough space of tag. */
|
||||
if (inlen > UINT64_MAX || aadlen > UINT64_MAX ||
|
||||
inlen > SIZE_MAX - LC_POLY1305_TAGLEN)
|
||||
return 0;
|
||||
/* Counter 0 is used for deriving Poly1305 key. */
|
||||
if (inlen > SIZE_MAX - (CHACHA20_CHUNK - 1) ||
|
||||
(inlen + CHACHA20_CHUNK - 1) / CHACHA20_CHUNK >
|
||||
CHACHA20_CTRMAX - 1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out == NULL) {
|
||||
*outlen = inlen + LC_POLY1305_TAGLEN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*outlen = 0;
|
||||
cctx = lc_cipher_ctx_new(lc_cipher_impl_chacha20());
|
||||
if (cctx == NULL)
|
||||
goto cleanup;
|
||||
actx = lc_auth_ctx_new(lc_auth_impl_poly1305());
|
||||
if (actx == NULL)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < LC_POLY1305_KEYLEN; i++)
|
||||
poly1305_key[i] = 0;
|
||||
if (!chacha20_common_init(&cctx, key, keylen, iv, ivlen) ||
|
||||
!chacha20_common_update(&cctx, poly1305_key, &olen, poly1305_key,
|
||||
LC_POLY1305_KEYLEN))
|
||||
return 0;
|
||||
if (!chacha20_common_final(&cctx, poly1305_key + olen, &olen))
|
||||
return 0;
|
||||
for (i = 0; i < sizeof(params->key); i++)
|
||||
cparams.key[i] = params->key[i];
|
||||
for (i = 0; i < sizeof(params->nonce); i++)
|
||||
cparams.nonce[i] = params->nonce[i];
|
||||
|
||||
if (!poly1305_init(&pctx, poly1305_key, LC_POLY1305_KEYLEN) ||
|
||||
!poly1305_update(&pctx, aad, aadlen))
|
||||
return 0;
|
||||
cparams.counter = 0;
|
||||
if (!aead_poly1305_keysetup(cctx, aparams.key, &cparams))
|
||||
goto cleanup;
|
||||
|
||||
if (!lc_auth_init(actx, &aparams) ||
|
||||
!lc_auth_update(actx, aad, aadlen))
|
||||
goto cleanup;
|
||||
if (aadlen % 16 != 0)
|
||||
if (!poly1305_update(&pctx, zeropad, 16 - (aadlen % 16)))
|
||||
return 0;
|
||||
if (!lc_auth_update(actx, zeropad, 16 - (aadlen % 16)))
|
||||
goto cleanup;
|
||||
|
||||
if (!chacha20_common_init_from(&cctx, key, keylen, iv, ivlen, 1))
|
||||
return 0;
|
||||
if (!chacha20_common_update(&cctx, out, &olen, in, inlen))
|
||||
return 0;
|
||||
*outlen = olen;
|
||||
if (!chacha20_common_final(&cctx, out + olen, &olen))
|
||||
return 0;
|
||||
if (!poly1305_update(&pctx, out, inlen))
|
||||
return 0;
|
||||
cparams.counter = 1;
|
||||
if (!aead_poly1305_anycrypt(cctx, out, outlen, &cparams, in, inlen))
|
||||
goto cleanup;
|
||||
|
||||
if (!lc_auth_update(actx, out, inlen))
|
||||
goto cleanup;
|
||||
if (inlen % 16 != 0)
|
||||
if (!poly1305_update(&pctx, zeropad, 16 - (inlen % 16)))
|
||||
return 0;
|
||||
if (!lc_auth_update(actx, zeropad, 16 - (inlen % 16)))
|
||||
goto cleanup;
|
||||
|
||||
store64le(&buf[0], aadlen);
|
||||
store64le(&buf[sizeof(uint64_t)], inlen);
|
||||
if (!poly1305_update(&pctx, buf, sizeof(buf)) ||
|
||||
!poly1305_final(&pctx, out + inlen, &olen))
|
||||
return 0;
|
||||
if (!lc_auth_update(actx, buf, sizeof(buf)) ||
|
||||
!lc_auth_final(actx, out + inlen, &olen))
|
||||
goto cleanup;
|
||||
*outlen += olen;
|
||||
if (*outlen != inlen + LC_POLY1305_TAGLEN)
|
||||
goto cleanup;
|
||||
ret = 1;
|
||||
|
||||
cleanup:
|
||||
lc_scrub(buf, sizeof(buf));
|
||||
lc_scrub(poly1305_key, sizeof(poly1305_key));
|
||||
lc_scrub(&aparams, sizeof(aparams));
|
||||
lc_scrub(&cparams, sizeof(cparams));
|
||||
lc_auth_ctx_free(actx);
|
||||
lc_cipher_ctx_free(cctx);
|
||||
|
||||
*outlen = inlen + LC_POLY1305_TAGLEN;
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
chacha20_poly1305_open(uint8_t *out, size_t *outlen, const uint8_t *key,
|
||||
size_t keylen, const uint8_t *iv, size_t ivlen, const uint8_t *aad,
|
||||
size_t aadlen, const uint8_t *in, size_t inlen)
|
||||
xchacha20_poly1305_seal(uint8_t *out, size_t *outlen, const void *initparams,
|
||||
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;
|
||||
const struct lc_xchacha20_poly1305_params *params = initparams;
|
||||
struct lc_cipher_ctx *cctx = NULL;
|
||||
struct lc_auth_ctx *actx = NULL;
|
||||
struct lc_xchacha20_params cparams;
|
||||
struct lc_poly1305_params aparams;
|
||||
uint8_t buf[sizeof(uint64_t) * 2];
|
||||
size_t i, olen;
|
||||
int ret = 0;
|
||||
|
||||
*outlen = 0;
|
||||
/* inlen and aadlen are capped by design; enough space of tag. */
|
||||
if (inlen > UINT64_MAX || aadlen > UINT64_MAX ||
|
||||
inlen > SIZE_MAX - LC_POLY1305_TAGLEN)
|
||||
return 0;
|
||||
/* Counter 0 is used for deriving Poly1305 key. */
|
||||
if (inlen > SIZE_MAX - (CHACHA20_CHUNK - 1) ||
|
||||
(inlen + CHACHA20_CHUNK - 1) / CHACHA20_CHUNK >
|
||||
CHACHA20_CTRMAX - 1)
|
||||
return 0;
|
||||
|
||||
if (out == NULL) {
|
||||
*outlen = inlen + LC_POLY1305_TAGLEN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
cctx = lc_cipher_ctx_new(lc_cipher_impl_xchacha20());
|
||||
if (cctx == NULL)
|
||||
goto cleanup;
|
||||
actx = lc_auth_ctx_new(lc_auth_impl_poly1305());
|
||||
if (actx == NULL)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < sizeof(params->key); i++)
|
||||
cparams.key[i] = params->key[i];
|
||||
for (i = 0; i < sizeof(params->nonce); i++)
|
||||
cparams.nonce[i] = params->nonce[i];
|
||||
|
||||
cparams.counter = 0;
|
||||
if (!aead_poly1305_keysetup(cctx, aparams.key, &cparams))
|
||||
goto cleanup;
|
||||
|
||||
if (!lc_auth_init(actx, &aparams) ||
|
||||
!lc_auth_update(actx, aad, aadlen))
|
||||
goto cleanup;
|
||||
if (aadlen % 16 != 0)
|
||||
if (!lc_auth_update(actx, zeropad, 16 - (aadlen % 16)))
|
||||
goto cleanup;
|
||||
|
||||
cparams.counter = 1;
|
||||
if (!aead_poly1305_anycrypt(cctx, out, outlen, &cparams, in, inlen))
|
||||
goto cleanup;
|
||||
|
||||
if (!lc_auth_update(actx, out, inlen))
|
||||
goto cleanup;
|
||||
if (inlen % 16 != 0)
|
||||
if (!lc_auth_update(actx, zeropad, 16 - (inlen % 16)))
|
||||
goto cleanup;
|
||||
|
||||
store64le(&buf[0], aadlen);
|
||||
store64le(&buf[sizeof(uint64_t)], inlen);
|
||||
if (!lc_auth_update(actx, buf, sizeof(buf)) ||
|
||||
!lc_auth_final(actx, out + inlen, &olen))
|
||||
goto cleanup;
|
||||
*outlen += olen;
|
||||
if (*outlen != inlen + LC_POLY1305_TAGLEN)
|
||||
goto cleanup;
|
||||
ret = 1;
|
||||
|
||||
cleanup:
|
||||
lc_scrub(buf, sizeof(buf));
|
||||
lc_scrub(&aparams, sizeof(aparams));
|
||||
lc_scrub(&cparams, sizeof(cparams));
|
||||
lc_auth_ctx_free(actx);
|
||||
lc_cipher_ctx_free(cctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
chacha20_poly1305_open(uint8_t *out, size_t *outlen, const void *initparams,
|
||||
const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
const struct lc_chacha20_poly1305_params *params = initparams;
|
||||
struct lc_cipher_ctx *cctx = NULL;
|
||||
struct lc_auth_ctx *actx = NULL;
|
||||
struct lc_chacha20_params cparams;
|
||||
struct lc_poly1305_params aparams;
|
||||
uint8_t tag[LC_POLY1305_TAGLEN];
|
||||
uint8_t buf[sizeof(uint64_t) * 2];
|
||||
size_t i, olen, ctlen;
|
||||
int ret = 0;
|
||||
|
||||
*outlen = 0;
|
||||
/* inlen includes the tag; inlen and aadlen are capped by design. */
|
||||
if (inlen < LC_POLY1305_TAGLEN ||
|
||||
inlen > UINT64_MAX || aadlen > UINT64_MAX ||
|
||||
inlen > SIZE_MAX - LC_POLY1305_TAGLEN ||
|
||||
inlen > SIZE_MAX - CHACHA20_CHUNK + 1 ||
|
||||
inlen > UINT64_MAX || aadlen > UINT64_MAX)
|
||||
return 0;
|
||||
/* Counter 0 is used for deriving Poly1305 key. */
|
||||
if (inlen > SIZE_MAX - (CHACHA20_CHUNK - 1) ||
|
||||
(inlen + CHACHA20_CHUNK - 1) / CHACHA20_CHUNK >
|
||||
CHACHA20_CTRMAX - 1) {
|
||||
if (out == NULL)
|
||||
*outlen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -132,148 +260,85 @@ chacha20_poly1305_open(uint8_t *out, size_t *outlen, const uint8_t *key,
|
||||
return 1;
|
||||
}
|
||||
|
||||
*outlen = 0;
|
||||
ctlen = inlen - LC_POLY1305_TAGLEN;
|
||||
tagp = in + ctlen;
|
||||
cctx = lc_cipher_ctx_new(lc_cipher_impl_chacha20());
|
||||
if (cctx == NULL)
|
||||
goto cleanup;
|
||||
actx = lc_auth_ctx_new(lc_auth_impl_poly1305());
|
||||
if (actx == NULL)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < LC_POLY1305_KEYLEN; i++)
|
||||
poly1305_key[i] = 0;
|
||||
if (!chacha20_common_init(&cctx, key, keylen, iv, ivlen) ||
|
||||
!chacha20_common_update(&cctx, poly1305_key, &olen, poly1305_key,
|
||||
LC_POLY1305_KEYLEN))
|
||||
return 0;
|
||||
if (!chacha20_common_final(&cctx, poly1305_key + olen, &olen))
|
||||
return 0;
|
||||
for (i = 0; i < sizeof(params->key); i++)
|
||||
cparams.key[i] = params->key[i];
|
||||
for (i = 0; i < sizeof(params->nonce); i++)
|
||||
cparams.nonce[i] = params->nonce[i];
|
||||
|
||||
if (!poly1305_init(&pctx, poly1305_key, LC_POLY1305_KEYLEN) ||
|
||||
!poly1305_update(&pctx, aad, aadlen))
|
||||
return 0;
|
||||
cparams.counter = 0;
|
||||
if (!aead_poly1305_keysetup(cctx, aparams.key, &cparams))
|
||||
goto cleanup;
|
||||
|
||||
if (!lc_auth_init(actx, &aparams) ||
|
||||
!lc_auth_update(actx, aad, aadlen))
|
||||
goto cleanup;
|
||||
if (aadlen % 16 != 0)
|
||||
if (!poly1305_update(&pctx, zeropad, 16 - (aadlen % 16)))
|
||||
return 0;
|
||||
if (!lc_auth_update(actx, zeropad, 16 - (aadlen % 16)))
|
||||
goto cleanup;
|
||||
|
||||
if (!poly1305_update(&pctx, in, ctlen))
|
||||
return 0;
|
||||
ctlen = inlen - LC_POLY1305_TAGLEN;
|
||||
if (!lc_auth_update(actx, in, ctlen))
|
||||
goto cleanup;
|
||||
if (ctlen % 16 != 0)
|
||||
if (!poly1305_update(&pctx, zeropad, 16 - (ctlen % 16)))
|
||||
return 0;
|
||||
if (!lc_auth_update(actx, zeropad, 16 - (ctlen % 16)))
|
||||
goto cleanup;
|
||||
|
||||
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_auth_update(actx, buf, sizeof(buf)) ||
|
||||
!lc_auth_final(actx, tag, &olen))
|
||||
goto cleanup;
|
||||
if (olen != LC_POLY1305_TAGLEN)
|
||||
goto cleanup;
|
||||
if (!lc_ct_cmp(tag, in + ctlen, LC_POLY1305_TAGLEN))
|
||||
goto cleanup;
|
||||
|
||||
if (!lc_ct_cmp(tag, tagp, LC_POLY1305_TAGLEN))
|
||||
return 0;
|
||||
cparams.counter = 1;
|
||||
if (!aead_poly1305_anycrypt(cctx, out, outlen, &cparams, in, ctlen))
|
||||
goto cleanup;
|
||||
ret = 1;
|
||||
|
||||
cleanup:
|
||||
lc_scrub(buf, sizeof(buf));
|
||||
lc_scrub(poly1305_key, sizeof(poly1305_key));
|
||||
lc_scrub(&aparams, sizeof(aparams));
|
||||
lc_scrub(&cparams, sizeof(cparams));
|
||||
lc_scrub(tag, sizeof(tag));
|
||||
lc_auth_ctx_free(actx);
|
||||
lc_cipher_ctx_free(cctx);
|
||||
|
||||
if (!chacha20_common_init_from(&cctx, key, keylen, iv, ivlen, 1))
|
||||
return 0;
|
||||
if (!chacha20_common_update(&cctx, out, &olen, in, ctlen))
|
||||
return 0;
|
||||
*outlen = olen;
|
||||
if (!chacha20_common_final(&cctx, out + olen, &olen))
|
||||
return 0;
|
||||
*outlen += olen;
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
xchacha20_poly1305_seal(uint8_t *out, size_t *outlen, const uint8_t *key,
|
||||
size_t keylen, const uint8_t *iv, size_t ivlen, const uint8_t *aad,
|
||||
size_t aadlen, const uint8_t *in, size_t inlen)
|
||||
xchacha20_poly1305_open(uint8_t *out, size_t *outlen, const void *initparams,
|
||||
const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
struct chacha20_ctx cctx;
|
||||
struct poly1305_ctx pctx;
|
||||
uint8_t poly1305_key[LC_POLY1305_KEYLEN];
|
||||
uint8_t buf[sizeof(uint64_t) * 2];
|
||||
size_t i, olen;
|
||||
|
||||
if (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;
|
||||
}
|
||||
const struct lc_xchacha20_poly1305_params *params = initparams;
|
||||
struct lc_cipher_ctx *cctx = NULL;
|
||||
struct lc_auth_ctx *actx = NULL;
|
||||
struct lc_xchacha20_params cparams;
|
||||
struct lc_poly1305_params aparams;
|
||||
uint8_t tag[LC_POLY1305_TAGLEN];
|
||||
uint8_t buf[sizeof(uint64_t) * 2];
|
||||
size_t i, olen, ctlen;
|
||||
int ret = 0;
|
||||
|
||||
*outlen = 0;
|
||||
|
||||
for (i = 0; i < LC_POLY1305_KEYLEN; i++)
|
||||
poly1305_key[i] = 0;
|
||||
if (!xchacha20_common_init(&cctx, key, keylen, iv, ivlen) ||
|
||||
!chacha20_common_update(&cctx, poly1305_key, &olen, poly1305_key,
|
||||
LC_POLY1305_KEYLEN))
|
||||
return 0;
|
||||
if (!chacha20_common_final(&cctx, poly1305_key + olen, &olen))
|
||||
return 0;
|
||||
|
||||
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 (!xchacha20_common_init_from(&cctx, key, keylen, iv, ivlen, 1))
|
||||
return 0;
|
||||
if (!chacha20_common_update(&cctx, out, &olen, in, inlen))
|
||||
return 0;
|
||||
*outlen = olen;
|
||||
if (!chacha20_common_final(&cctx, out + olen, &olen))
|
||||
return 0;
|
||||
if (!poly1305_update(&pctx, out, inlen))
|
||||
return 0;
|
||||
if (inlen % 16 != 0)
|
||||
if (!poly1305_update(&pctx, zeropad, 16 - (inlen % 16)))
|
||||
return 0;
|
||||
|
||||
store64le(&buf[0], aadlen);
|
||||
store64le(&buf[sizeof(uint64_t)], inlen);
|
||||
if (!poly1305_update(&pctx, buf, sizeof(buf)) ||
|
||||
!poly1305_final(&pctx, out + inlen, &olen))
|
||||
return 0;
|
||||
|
||||
lc_scrub(buf, sizeof(buf));
|
||||
lc_scrub(poly1305_key, sizeof(poly1305_key));
|
||||
|
||||
*outlen = inlen + LC_POLY1305_TAGLEN;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
xchacha20_poly1305_open(uint8_t *out, size_t *outlen, const uint8_t *key,
|
||||
size_t keylen, const uint8_t *iv, size_t ivlen, 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;
|
||||
|
||||
/* inlen includes the tag; inlen and aadlen are capped by design. */
|
||||
if (inlen < LC_POLY1305_TAGLEN ||
|
||||
inlen > UINT64_MAX || aadlen > UINT64_MAX ||
|
||||
inlen > SIZE_MAX - LC_POLY1305_TAGLEN ||
|
||||
inlen > SIZE_MAX - CHACHA20_CHUNK + 1 ||
|
||||
inlen > UINT64_MAX || aadlen > UINT64_MAX)
|
||||
return 0;
|
||||
/* Counter 0 is used for deriving Poly1305 key. */
|
||||
if (inlen > SIZE_MAX - (CHACHA20_CHUNK - 1) ||
|
||||
(inlen + CHACHA20_CHUNK - 1) / CHACHA20_CHUNK >
|
||||
CHACHA20_CTRMAX - 1) {
|
||||
if (out == NULL)
|
||||
*outlen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -282,54 +347,60 @@ xchacha20_poly1305_open(uint8_t *out, size_t *outlen, const uint8_t *key,
|
||||
return 1;
|
||||
}
|
||||
|
||||
*outlen = 0;
|
||||
ctlen = inlen - LC_POLY1305_TAGLEN;
|
||||
tagp = in + ctlen;
|
||||
cctx = lc_cipher_ctx_new(lc_cipher_impl_xchacha20());
|
||||
if (cctx == NULL)
|
||||
goto cleanup;
|
||||
actx = lc_auth_ctx_new(lc_auth_impl_poly1305());
|
||||
if (actx == NULL)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < LC_POLY1305_KEYLEN; i++)
|
||||
poly1305_key[i] = 0;
|
||||
if (!xchacha20_common_init(&cctx, key, keylen, iv, ivlen) ||
|
||||
!chacha20_common_update(&cctx, poly1305_key, &olen, poly1305_key,
|
||||
LC_POLY1305_KEYLEN))
|
||||
return 0;
|
||||
if (!chacha20_common_final(&cctx, poly1305_key + olen, &olen))
|
||||
return 0;
|
||||
for (i = 0; i < sizeof(params->key); i++)
|
||||
cparams.key[i] = params->key[i];
|
||||
for (i = 0; i < sizeof(params->nonce); i++)
|
||||
cparams.nonce[i] = params->nonce[i];
|
||||
|
||||
if (!poly1305_init(&pctx, poly1305_key, LC_POLY1305_KEYLEN) ||
|
||||
!poly1305_update(&pctx, aad, aadlen))
|
||||
return 0;
|
||||
cparams.counter = 0;
|
||||
if (!aead_poly1305_keysetup(cctx, aparams.key, &cparams))
|
||||
goto cleanup;
|
||||
|
||||
if (!lc_auth_init(actx, &aparams) ||
|
||||
!lc_auth_update(actx, aad, aadlen))
|
||||
goto cleanup;
|
||||
if (aadlen % 16 != 0)
|
||||
if (!poly1305_update(&pctx, zeropad, 16 - (aadlen % 16)))
|
||||
return 0;
|
||||
if (!lc_auth_update(actx, zeropad, 16 - (aadlen % 16)))
|
||||
goto cleanup;
|
||||
|
||||
if (!poly1305_update(&pctx, in, ctlen))
|
||||
return 0;
|
||||
ctlen = inlen - LC_POLY1305_TAGLEN;
|
||||
if (!lc_auth_update(actx, in, ctlen))
|
||||
goto cleanup;
|
||||
if (ctlen % 16 != 0)
|
||||
if (!poly1305_update(&pctx, zeropad, 16 - (ctlen % 16)))
|
||||
return 0;
|
||||
if (!lc_auth_update(actx, zeropad, 16 - (ctlen % 16)))
|
||||
goto cleanup;
|
||||
|
||||
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_auth_update(actx, buf, sizeof(buf)) ||
|
||||
!lc_auth_final(actx, tag, &olen))
|
||||
goto cleanup;
|
||||
if (olen != LC_POLY1305_TAGLEN)
|
||||
goto cleanup;
|
||||
if (!lc_ct_cmp(tag, in + ctlen, LC_POLY1305_TAGLEN))
|
||||
goto cleanup;
|
||||
|
||||
if (!lc_ct_cmp(tag, tagp, LC_POLY1305_TAGLEN))
|
||||
return 0;
|
||||
cparams.counter = 1;
|
||||
if (!aead_poly1305_anycrypt(cctx, out, outlen, &cparams, in, ctlen))
|
||||
goto cleanup;
|
||||
ret = 1;
|
||||
|
||||
cleanup:
|
||||
lc_scrub(buf, sizeof(buf));
|
||||
lc_scrub(poly1305_key, sizeof(poly1305_key));
|
||||
lc_scrub(&aparams, sizeof(aparams));
|
||||
lc_scrub(&cparams, sizeof(cparams));
|
||||
lc_scrub(tag, sizeof(tag));
|
||||
lc_auth_ctx_free(actx);
|
||||
lc_cipher_ctx_free(cctx);
|
||||
|
||||
if (!xchacha20_common_init_from(&cctx, key, keylen, iv, ivlen, 1))
|
||||
return 0;
|
||||
if (!chacha20_common_update(&cctx, out, &olen, in, ctlen))
|
||||
return 0;
|
||||
*outlen = olen;
|
||||
if (!chacha20_common_final(&cctx, out + olen, &olen))
|
||||
return 0;
|
||||
*outlen += olen;
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,11 +175,9 @@ struct lc_aead_impl;
|
||||
|
||||
|
||||
int lc_aead_seal(const struct lc_aead_impl *, uint8_t *, size_t *,
|
||||
const uint8_t *, size_t, const uint8_t *, size_t, const uint8_t *,
|
||||
size_t, const uint8_t *, size_t);
|
||||
const void *, const uint8_t *, size_t, const uint8_t *, size_t);
|
||||
int lc_aead_open(const struct lc_aead_impl *, uint8_t *, size_t *,
|
||||
const uint8_t *, size_t, const uint8_t *, size_t, const uint8_t *,
|
||||
size_t, const uint8_t *, size_t);
|
||||
const void *, const uint8_t *, size_t, const uint8_t *, size_t);
|
||||
|
||||
const struct lc_aead_impl *lc_aead_impl_chacha20_poly1305(void);
|
||||
const struct lc_aead_impl *lc_aead_impl_xchacha20_poly1305(void);
|
||||
|
Loading…
Reference in New Issue
Block a user