initial import

This commit is contained in:
Lucas Gabriel Vuotto 2024-05-31 10:59:58 +00:00
commit 7bc527c769
28 changed files with 2071 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
obj/

3
Makefile Normal file
View File

@ -0,0 +1,3 @@
SUBDIR= lib wycheproof
.include <bsd.subdir.mk>

17
Makefile.inc Normal file
View File

@ -0,0 +1,17 @@
LC_SRCS+= auth.c auth_poly1305.c
LC_SRCS+= cipher.c cipher_chacha20.c
LC_SRCS+= aead.c aead_chacha20_poly1305.c
LC_SRCS+= impl_chacha20.c impl_poly1305.c
LC_SRCS+= ct.c util.c
CFLAGS+= -Wall
CFLAGS+= -Wextra
CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wmissing-prototypes
CFLAGS+= -Wpointer-arith
CFLAGS+= -Wshadow
CFLAGS+= -Wstrict-prototypes
CFLAGS+= -Wunused
CFLAGS+= -Wno-unused-parameter
.include <bsd.own.mk>

79
README Normal file
View File

@ -0,0 +1,79 @@
lilcrypto
=========
> They see me rollin', they hatin'.
Experiment on rolling my own crypto. Kinda. I'm not creating any new
protocol, but implementing known algorithms and constructions. The main
focus is to understand how to implement the math behind the algorithms,
and to get to know the constructions better.
Algorithms
==========
Utilities
---------
- Constant-time operations
- [/] compare: returns `0` if match, non-`0` otherwise. The non-`0`
case might leak information. Would be better to return `0xffffffff`
if match, `0` otherwise.
Authentication
--------------
- [x] Poly1305
- [ ] SHA-512 (needed for Ed25519)
Ciphers
-------
- [x] ChaCha20
- [ ] XChaCha20
AEAD
----
- [/] ChaCha20-Poly1305 (missing aead_open)
- [ ] XChaCha20-Poly1305
ECC
---
- Curve25519
- [ ] Ed25519 (EdDSA)
- [ ] X25519 (ECDH)
Nice-to-haves
=============
Utilities
---------
- [ ] Portable Makefile
- [ ] NaCl interface
- [ ] signify interface
Authentication
--------------
- [ ] GMAC
Ciphers
-------
- [ ] AES
- [ ] Camellia
- [ ] Salsa20 (no Wycheproof test vector suite)
- [ ] XSalsa20 (no Wycheproof test vector suite)
AEAD
----
- [ ] AES-GCM
- [ ] Camellia-GCM
- [ ] Salsa20-Poly1305 (no Wycherproof test vector suite)
- [ ] XSalsa20-Poly1305 (no Wycherproof test vector suite)
KDF?
----

39
aead.c Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilcrypto.h"
#include "aead.h"
int
lc_aead_seal(const struct lc_aead_impl *impl, 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)
{
return impl->seal(key, keylen, iv, ivlen, out, outlen, aad, aadlen, in,
inlen);
}
int
lc_aead_open(const struct lc_aead_impl *impl, 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)
{
return impl->open(key, keylen, iv, ivlen, out, outlen, aad, aadlen, in,
inlen);
}

28
aead.h Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
struct lc_aead_impl {
int (*seal)(const uint8_t *, size_t, const uint8_t *, size_t,
uint8_t *, size_t *, const uint8_t *, size_t,
const uint8_t *, size_t);
int (*open)(const uint8_t *, size_t, const uint8_t *, size_t,
uint8_t *, size_t *, const uint8_t *, size_t,
const uint8_t *, size_t);
};

114
aead_chacha20_poly1305.c Normal file
View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#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"
/*
* Implements ChaCha20-Poly1305 according to RFC 8439.
*/
static uint8_t zeropad[16];
static int
chacha20_poly1305_seal(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)
{
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;
}
*outlen = 0;
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 (!chacha20_x_init_from(&cctx, key, keylen, iv, ivlen, 1))
return 0;
if (!chacha20_x_update(&cctx, out, &olen, in, inlen))
return 0;
*outlen = olen;
if (!chacha20_x_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 struct lc_aead_impl chacha20_poly1305_impl = {
.seal = &chacha20_poly1305_seal,
.open = NULL, //&chacha20_poly1305_open,
};
const struct lc_aead_impl *
lc_aead_impl_chacha20_poly1305(void)
{
return &chacha20_poly1305_impl;
}

78
auth.c Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include "lilcrypto.h"
#include "auth.h"
int
lc_auth_init(struct lc_auth_ctx *ctx, const uint8_t *key, size_t keylen)
{
return ctx->impl->init(ctx->arg, key, keylen);
}
int
lc_auth_update(struct lc_auth_ctx *ctx, const uint8_t *in, size_t inlen)
{
return ctx->impl->update(ctx->arg, in, inlen);
}
int
lc_auth_final(struct lc_auth_ctx *ctx, uint8_t *out, size_t *outlen)
{
return ctx->impl->final(ctx->arg, out, outlen);
}
int
lc_auth(const struct lc_auth_impl *impl, const uint8_t *key, size_t keylen,
uint8_t *out, size_t *outlen, const uint8_t *in, size_t inlen)
{
return impl->auth(key, keylen, out, outlen, in, inlen);
}
struct lc_auth_ctx *
lc_auth_ctx_new(const struct lc_auth_impl *impl)
{
struct lc_auth_ctx *ctx;
void *arg;
ctx = malloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
if (impl->argsz > 0) {
arg = malloc(impl->argsz);
if (arg == NULL) {
free(ctx);
return NULL;
}
ctx->arg = arg;
} else
ctx->arg = NULL;
ctx->impl = impl;
return ctx;
}
void
lc_auth_ctx_free(struct lc_auth_ctx *ctx)
{
if (ctx != NULL)
free(ctx->arg);
free(ctx);
}

34
auth.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
struct lc_auth_impl {
int (*init)(void *, const uint8_t *, size_t);
int (*update)(void *, const uint8_t *, size_t);
int (*final)(void *, uint8_t *, size_t *);
int (*auth)(const uint8_t *, size_t, uint8_t *, size_t *,
const uint8_t *, size_t);
size_t argsz;
};
struct lc_auth_ctx {
const struct lc_auth_impl *impl;
void *arg;
};

168
auth_poly1305.c Normal file
View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilcrypto.h"
#include "auth.h"
#include "auth_poly1305.h"
#include "impl_poly1305.h"
#include "util.h"
int
poly1305_init(void *arg, const uint8_t *key, size_t keylen)
{
struct poly1305_ctx *ctx = arg;
size_t i;
uint32_t t0, t1, t2, t3;
if (keylen != LC_POLY1305_KEYLEN)
return 0;
ctx->h0 = 0;
ctx->h1 = 0;
ctx->h2 = 0;
ctx->h3 = 0;
ctx->h4 = 0;
t0 = load32le(&key[0]);
t1 = load32le(&key[4]);
t2 = load32le(&key[8]);
t3 = load32le(&key[12]);
ctx->r0 = t0 & 0x3ffffff;
ctx->r1 = ((t1 << 6) | (t0 >> 26)) & 0x3ffff03;
ctx->r2 = ((t2 << 12) | (t1 >> 20)) & 0x3ffc0ff;
ctx->r3 = ((t3 << 18) | (t2 >> 14)) & 0x3f03fff;
ctx->r4 = (t3 >> 8) & 0xfffff;
ctx->x1 = 5 * ctx->r1;
ctx->x2 = 5 * ctx->r2;
ctx->x3 = 5 * ctx->r3;
ctx->x4 = 5 * ctx->r4;
ctx->s0 = load32le(&key[16]);
ctx->s1 = load32le(&key[20]);
ctx->s2 = load32le(&key[24]);
ctx->s3 = load32le(&key[28]);
ctx->mlen = 0;
for (i = 0; i < POLY1305_CHUNK; i++)
ctx->m[i] = 0;
return 1;
}
int
poly1305_update(void *arg, const uint8_t *in, size_t inlen)
{
struct poly1305_ctx *ctx = arg;
size_t i;
for (i = 0; i + ctx->mlen < POLY1305_CHUNK && i < inlen; i++)
ctx->m[i + ctx->mlen] = in[i];
ctx->mlen += i;
in += i;
inlen -= i;
if (ctx->mlen == POLY1305_CHUNK) {
poly1305_block(ctx, 1);
ctx->mlen = 0;
}
if (inlen == 0)
return 1;
while (inlen >= POLY1305_CHUNK) {
for (i = 0; i < POLY1305_CHUNK; i++)
ctx->m[i] = in[i];
poly1305_block(ctx, 1);
in += POLY1305_CHUNK;
inlen -= POLY1305_CHUNK;
}
for (i = 0; i < inlen; i++)
ctx->m[i] = in[i];
ctx->mlen = inlen;
return 1;
}
int
poly1305_final(void *arg, uint8_t *out, size_t *outlen)
{
struct poly1305_ctx *ctx = arg;
uint32_t tag[POLY1305_TAGLEN_WORDS];
size_t i;
*outlen = LC_POLY1305_TAGLEN;
if (out == NULL)
return 1;
i = ctx->mlen;
if (i > 0) {
if (i < POLY1305_CHUNK) {
ctx->m[i++] = 1;
for (; i < POLY1305_CHUNK; i++)
ctx->m[i] = 0;
poly1305_block(ctx, 0);
} else
poly1305_block(ctx, 1);
}
poly1305_reduce(ctx, tag);
store32le(&out[0], tag[0]);
store32le(&out[4], tag[1]);
store32le(&out[8], tag[2]);
store32le(&out[12], tag[3]);
lc_scrub(ctx, sizeof(*ctx));
return 1;
}
static int
poly1305_auth(const uint8_t *key, size_t keylen, uint8_t *out, size_t *outlen,
const uint8_t *in, size_t inlen)
{
struct poly1305_ctx ctx;
if (out == NULL) {
*outlen = LC_POLY1305_TAGLEN;
return 1;
}
return poly1305_init(&ctx, key, keylen) &&
poly1305_update(&ctx, in, inlen) &&
poly1305_final(&ctx, out, outlen);
}
static struct lc_auth_impl poly1305_impl = {
.init = &poly1305_init,
.update = &poly1305_update,
.final = &poly1305_final,
.auth = &poly1305_auth,
.argsz = sizeof(struct poly1305_ctx),
};
const struct lc_auth_impl *
lc_auth_impl_poly1305(void)
{
return &poly1305_impl;
}

23
auth_poly1305.h Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
int poly1305_init(void *, const uint8_t *, size_t);
int poly1305_update(void *, const uint8_t *, size_t);
int poly1305_final(void *, uint8_t *, size_t *);

110
cipher.c Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include "lilcrypto.h"
#include "cipher.h"
int
lc_cipher_encrypt_init(struct lc_cipher_ctx *ctx, const uint8_t *key,
size_t keylen, const uint8_t *iv, size_t ivlen)
{
return ctx->impl->encrypt_init(ctx->arg, key, keylen, iv, ivlen);
}
int
lc_cipher_encrypt_update(struct lc_cipher_ctx *ctx, uint8_t *out,
size_t *outlen, const uint8_t *in, size_t inlen)
{
return ctx->impl->encrypt_update(ctx->arg, out, outlen, in, inlen);
}
int
lc_cipher_encrypt_final(struct lc_cipher_ctx *ctx, uint8_t *out,
size_t *outlen)
{
return ctx->impl->encrypt_final(ctx->arg, out, outlen);
}
int
lc_cipher_encrypt(const struct lc_cipher_impl *impl, const uint8_t *key,
size_t keylen, const uint8_t *iv, size_t ivlen, uint8_t *out,
size_t *outlen, const uint8_t *in, size_t inlen)
{
return impl->encrypt(key, keylen, iv, ivlen, out, outlen, in, inlen);
}
int
lc_cipher_decrypt_init(struct lc_cipher_ctx *ctx, const uint8_t *key,
size_t keylen, const uint8_t *iv, size_t ivlen)
{
return ctx->impl->decrypt_init(ctx->arg, key, keylen, iv, ivlen);
}
int
lc_cipher_decrypt_update(struct lc_cipher_ctx *ctx, uint8_t *out,
size_t *outlen, const uint8_t *in, size_t inlen)
{
return ctx->impl->decrypt_update(ctx->arg, out, outlen, in, inlen);
}
int
lc_cipher_decrypt_final(struct lc_cipher_ctx *ctx, uint8_t *out,
size_t *outlen)
{
return ctx->impl->decrypt_final(ctx->arg, out, outlen);
}
int
lc_cipher_decrypt(const struct lc_cipher_impl *impl, const uint8_t *key,
size_t keylen, const uint8_t *iv, size_t ivlen, uint8_t *out,
size_t *outlen, const uint8_t *in, size_t inlen)
{
return impl->decrypt(key, keylen, iv, ivlen, out, outlen, in, inlen);
}
struct lc_cipher_ctx *
lc_cipher_ctx_new(const struct lc_cipher_impl *impl)
{
struct lc_cipher_ctx *ctx;
void *arg;
ctx = malloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
if (impl->argsz > 0) {
arg = malloc(impl->argsz);
if (arg == NULL) {
free(ctx);
return NULL;
}
ctx->arg = arg;
} else
ctx->arg = NULL;
ctx->impl = impl;
return ctx;
}
void
lc_cipher_ctx_free(struct lc_cipher_ctx *ctx)
{
if (ctx != NULL)
free(ctx->arg);
free(ctx);
}

44
cipher.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
struct lc_cipher_impl {
int (*encrypt_init)(void *, const uint8_t *, size_t,
const uint8_t *, size_t);
int (*encrypt_update)(void *, uint8_t *, size_t *, const uint8_t *,
size_t);
int (*encrypt_final)(void *, uint8_t *, size_t *);
int (*encrypt)(const uint8_t *, size_t, const uint8_t *, size_t,
uint8_t *, size_t *, const uint8_t *, size_t);
int (*decrypt_init)(void *, const uint8_t *, size_t,
const uint8_t *, size_t);
int (*decrypt_update)(void *, uint8_t *, size_t *, const uint8_t *,
size_t);
int (*decrypt_final)(void *, uint8_t *, size_t *);
int (*decrypt)(const uint8_t *, size_t, const uint8_t *, size_t,
uint8_t *, size_t *, const uint8_t *, size_t);
size_t argsz;
};
struct lc_cipher_ctx {
const struct lc_cipher_impl *impl;
void *arg;
};

199
cipher_chacha20.c Normal file
View File

@ -0,0 +1,199 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <limits.h>
#include "lilcrypto.h"
#include "cipher.h"
#include "cipher_chacha20.h"
#include "impl_chacha20.h"
#include "util.h"
int
chacha20_x_init_from(void *arg, const uint8_t *key, size_t keylen,
const uint8_t *iv, size_t ivlen, uint32_t counter)
{
struct chacha20_ctx *ctx = arg;
size_t i;
if (keylen != LC_CHACHA20_KEYLEN || ivlen != LC_CHACHA20_IVLEN)
return 0;
for (i = 0; i < CHACHA20_CHUNK_WORDS; i++)
ctx->s[i] = 0;
for (i = 0; i < CHACHA20_KEY_WORDS; i++)
ctx->k[i] = load32le(&key[i * 4]);
ctx->c = counter;
for (i = 0; i < CHACHA20_NONCE_WORDS; i++)
ctx->n[i] = load32le(&iv[i * 4]);
ctx->blen = 0;
return 1;
}
int
chacha20_x_init(void *arg, const uint8_t *key, size_t keylen,
const uint8_t *iv, size_t ivlen)
{
return chacha20_x_init_from(arg, key, keylen, iv, ivlen, 0);
}
int
chacha20_x_update(void *arg, uint8_t *out, size_t *outlen, const uint8_t *in,
size_t inlen)
{
struct chacha20_ctx *ctx = arg;
uint32_t h;
uint8_t s[4];
size_t i, blocks, off, pad;
*outlen = 0;
if (inlen > SIZE_MAX - (CHACHA20_CHUNK - 1) - ctx->blen)
return 0;
blocks = inlen + ctx->blen + CHACHA20_CHUNK - 1;
if (blocks / CHACHA20_CHUNK + ctx->c > CHACHA20_CTRMAX)
return 0;
if (out == NULL) {
*outlen = inlen;
return 1;
}
*outlen = inlen;
if (ctx->blen == 0)
goto fullblock;
off = ctx->blen % 4;
if (off != 0) {
store32le(s, ctx->s[ctx->blen / 4]);
for (i = 0; i + off < 4 && i < inlen; i++)
out[i] = in[i] ^ s[i + off];
ctx->blen += i;
out += i;
in += i;
inlen -= i;
}
pad = inlen % 4;
for (i = 0; i + ctx->blen < CHACHA20_CHUNK && i < inlen - pad; i += 4) {
h = load32le(&in[i * 4]);
h ^= ctx->s[(i + ctx->blen) / 4];
store32le(&out[i * 4], h);
}
ctx->blen += i * 4;
out += i * 4;
in += i * 4;
inlen -= i * 4;
fullblock:
while (inlen >= CHACHA20_CHUNK) {
chacha20_block(ctx);
ctx->c++;
for (i = 0; i < CHACHA20_CHUNK_WORDS; i++) {
h = load32le(&in[i * 4]);
h ^= ctx->s[i];
store32le(&out[i * 4], h);
}
out += CHACHA20_CHUNK;
in += CHACHA20_CHUNK;
inlen -= CHACHA20_CHUNK;
}
chacha20_block(ctx);
ctx->c++;
ctx->blen = inlen;
pad = inlen % 4;
for (i = 0; i < (inlen - pad) / 4; i++) {
h = load32le(&in[i * 4]);
h ^= ctx->s[i];
store32le(&out[i * 4], h);
}
out += i * 4;
in += i * 4;
inlen -= i * 4;
store32le(s, ctx->s[i]);
for (i = 0; i < pad; i++)
out[i] = in[i] ^ s[i];
return 1;
}
int
chacha20_x_final(void *arg, uint8_t *out, size_t *outlen)
{
struct chacha20_ctx *ctx = arg;
*outlen = 0;
lc_scrub(ctx, sizeof(*ctx));
return 1;
}
int
chacha20_x(const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
uint8_t *out, size_t *outlen, const uint8_t *in, size_t inlen)
{
struct chacha20_ctx ctx;
size_t l0, l1;
int rc;
*outlen = 0;
if (inlen > SIZE_MAX - (CHACHA20_CHUNK - 1) ||
(inlen + CHACHA20_CHUNK - 1) / CHACHA20_CHUNK > CHACHA20_CTRMAX)
return 0;
if (out == NULL) {
*outlen = inlen;
return 1;
}
rc = chacha20_x_init(&ctx, key, keylen, iv, ivlen) &&
chacha20_x_update(&ctx, out, &l0, in, inlen) &
chacha20_x_final(&ctx, out + l0, &l1);
if (rc)
*outlen = l0 + l1;
return rc;
}
static struct lc_cipher_impl chacha20_impl = {
.encrypt_init = &chacha20_x_init,
.encrypt_update = &chacha20_x_update,
.encrypt_final = &chacha20_x_final,
.encrypt = &chacha20_x,
.decrypt_init = &chacha20_x_init,
.decrypt_update = &chacha20_x_update,
.decrypt_final = &chacha20_x_final,
.decrypt = &chacha20_x,
.argsz = sizeof(struct chacha20_ctx),
};
const struct lc_cipher_impl *
lc_cipher_impl_chacha20(void)
{
return &chacha20_impl;
}

29
cipher_chacha20.h Normal file
View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
int chacha20_x_init_from(void *, const uint8_t *, size_t, const uint8_t *,
size_t, uint32_t);
int chacha20_x_init(void *, const uint8_t *, size_t, const uint8_t *,
size_t);
int chacha20_x_update(void *, uint8_t *, size_t *, const uint8_t *,
size_t);
int chacha20_x_final(void *, uint8_t *, size_t *);
int chacha20_x(const uint8_t *, size_t, const uint8_t *, size_t, uint8_t *,
size_t *, const uint8_t *, size_t);

29
ct.c Normal file
View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "lilcrypto.h"
uint32_t
lc_ct_cmp(const uint8_t *x, const uint8_t *y, size_t l)
{
uint32_t r = 0;
for (; l > 0; l--)
r |= *x++ ^ *y++;
return r;
}

85
impl_chacha20.c Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
#include "impl_chacha20.h"
#include "util.h"
/*
* ChaCha20 implementation.
*
* ChaCha originally designed by Daniel J. Bernstein, "ChaCha, a variant of
* Salsa20", https://cr.yp.to/chacha/chacha-20080128.pdf .
*/
/* "expand 32-byte k" */
#define SIGMA0 UINT32_C(0x61707865)
#define SIGMA1 UINT32_C(0x3320646e)
#define SIGMA2 UINT32_C(0x79622d32)
#define SIGMA3 UINT32_C(0x6b206574)
#define QUARTERROUND(a, b, c, d) do { \
a += b; d ^= a; d = rotl32(d, 16); \
c += d; b ^= c; b = rotl32(b, 12); \
a += b; d ^= a; d = rotl32(d, 8); \
c += d; b ^= c; b = rotl32(b, 7); \
} while (0)
void
chacha20_block(struct chacha20_ctx *ctx)
{
uint32_t x[CHACHA20_CHUNK_WORDS];
size_t i;
x[0] = SIGMA0;
x[1] = SIGMA1;
x[2] = SIGMA2;
x[3] = SIGMA3;
x[4] = ctx->k[0];
x[5] = ctx->k[1];
x[6] = ctx->k[2];
x[7] = ctx->k[3];
x[8] = ctx->k[4];
x[9] = ctx->k[5];
x[10] = ctx->k[6];
x[11] = ctx->k[7];
x[12] = ctx->c;
x[13] = ctx->n[0];
x[14] = ctx->n[1];
x[15] = ctx->n[2];
for (i = 0; i < CHACHA20_CHUNK_WORDS; i++)
ctx->s[i] = x[i];
for (i = 0; i < CHACHA20_ROUNDS; i++) {
QUARTERROUND(x[0], x[4], x[8], x[12]);
QUARTERROUND(x[1], x[5], x[9], x[13]);
QUARTERROUND(x[2], x[6], x[10], x[14]);
QUARTERROUND(x[3], x[7], x[11], x[15]);
QUARTERROUND(x[0], x[5], x[10], x[15]);
QUARTERROUND(x[1], x[6], x[11], x[12]);
QUARTERROUND(x[2], x[7], x[8], x[13]);
QUARTERROUND(x[3], x[4], x[9], x[14]);
}
for (i = 0; i < CHACHA20_CHUNK_WORDS; i++)
ctx->s[i] += x[i];
}

40
impl_chacha20.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
#include "lilcrypto.h"
#define CHACHA20_CHUNK 64
#define CHACHA20_CHUNK_WORDS (CHACHA20_CHUNK / sizeof(uint32_t))
#define CHACHA20_CTRMAX 4294967295 /* 2^32 - 1 */
#define CHACHA20_KEY_WORDS (LC_CHACHA20_KEYLEN / sizeof(uint32_t))
#define CHACHA20_NONCE_WORDS (LC_CHACHA20_IVLEN / sizeof(uint32_t))
#define CHACHA20_ROUNDS 10
struct chacha20_ctx {
uint32_t s[CHACHA20_CHUNK_WORDS];
uint32_t k[CHACHA20_KEY_WORDS];
uint32_t c;
uint32_t n[CHACHA20_NONCE_WORDS];
size_t blen;
};
void chacha20_block(struct chacha20_ctx *);

243
impl_poly1305.c Normal file
View File

@ -0,0 +1,243 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
#include "impl_poly1305.h"
#include "util.h"
/*
* Poly1305 implementation.
*
* Poly1305 originally designed by Daniel J. Bernstein, "The Poly1305-AES
* message-authentication code", https://cr.yp.to/mac/poly1305-20050329.pdf .
*
* This implementation is written from scratch, but consulting poly1305-donna
* by Andrew Moon, https://github.com/floodyberry/poly1305-donna, released
* under MIT license. Similarities are to be expected.
*/
/*
* Copyright 2011-2016 Andrew Moon <liquidsun@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* To ease reduction modulo p = 2^130 - 5, work in base 2^130, as 2^130 = 5 mod
* p, allowing for easier operations. 2^130 splits evenly into 5 limbs of 26
* bits.
*
* Addition is performed limb-wise:
*
* h = h4 h3 h2 h1 h0
* c = c4 c3 c2 c1 c0
* -----------------------------------
* h+c = h4+c4 h3+c3 h2+c2 h1+c1 h0+c0
*
* Carry won't be propagated at this step.
*
* Considering h = h + c, multiplication is performed as school multiplication
* / long multiplication:
*
* h = h4 h3 h2 h1 h0
* r = r4 r3 r2 r1 r0
* -----------------------------------------------------------
* h4*r0 h3*r0 h2*r0 h1*r0 h0*r0
* h4*r1 h3*r1 h2*r1 h1*r1 h0*r1
* h4*r2 h3*r2 h2*r2 h1*r2 h0*r2
* h4*r3 h3*r3 h2*r3 h1*r3 h0*r3
* h4*r4 h3*r4 h2*r4 h1*r4 h0*r4
*
* Each hn*rn fits in 53 bits. Carry won't be propagated at this step. Partial
* reduction modulo p starts here:
*
* 2^130
* h = | h4 h3 h2 h1 h0
* r = | r4 r3 r2 r1 r0
* ------------------------------|------------------------------
* | h4*r0 h3*r0 h2*r0 h1*r0 h0*r0
* h4*r1 | h3*r1 h2*r1 h1*r1 h0*r1
* h4*r2 h3*r2 | h2*r2 h1*r2 h0*r2
* h4*r3 h3*r3 h2*r3 | h1*r3 h0*r3
* h4*r4 h3*r4 h2*r4 h1*r4 | h0*r4
*
* 2^130
* h = | h4 h3 h2 h1 h0
* r = | r4 r3 r2 r1 r0
* --------|--------------------------------------
* | h4*r0 h3*r0 h2*r0 h1*r0 h0*r0
* | h3*r1 h2*r1 h1*r1 h0*r1 5*h4*r1
* | h2*r2 h1*r2 h0*r2 5*h4*r2 5*h3*r2
* | h1*r3 h0*r3 5*h4*r3 5*h3*r3 5*h2*r3
* | h0*r4 5*h4*r4 5*h3*r4 5*h2*r4 5*h1*r4
* --------|--------------------------------------
* h*r = | t4 t3 t2 t1 t0
*
* All the carry propagations are performed after this step. h0 is set t0 low
* 26 bits of t0; h1 thru h4 are set to tn + (tn-1 >> 26) to propagate the
* carry. t4 might overflow so it needs to be backpropagated to h0 and h1. h1
* won't carry into h2: given the highest possible h, c, and r,
*
* h = 0xffffffffffffffffffffffffffffffff
* c = 0x1ffffffffffffffffffffffffffffffff
* r = 0x0ffffffc0ffffffc0ffffffc0fffffff
*
* the limbs and t4 before h0 and h1 second propagation are
*
* h4 = 0x257ffff
* h3 = 0x3a95fff
* h2 = 0x3fea57f
* h1 = 0x3fffa70
* h0 = 0x2000002
* t4 = 0x77fffffa57ffff
*
* which becomes
*
* h4 = 0x257ffff
* h3 = 0x3a95fff
* h2 = 0x3fea57f
* h1 = 0x3fffa95
* h0 = 0x3fffff8
*
* To perform the final reduction modulo p, observe that each hn is bound by
* 2^26, which means that h is bound by 2^130. Define minusp = 2^136 - p.
* - If h < p, minusp + h < 2^136.
* - If h >= p, then h = p + k with k in {0,1,2,3,4}, and minusp + h =
* 2^136 - p + p + k = 2^136 + k >= 2^136, and both minusp + h = k mod 2^136
* and h = k mod p for all possible values of k.
*
* To avoid information leaking via side channels, define g = minusp + h, and
* select g if bit 136 is set, h otherwise. In particular, define a 32-bit
* mask = ~(g >> 136) + 1.
* - If bit 136 of g is 1, mask = ~1 + 1 = 0xffffffff.
* - If bit 136 of g is 0, mask = ~0 + 1 = 0.
* Then perform (h & ~mask) | (g & mask).
*/
void
poly1305_block(struct poly1305_ctx *ctx, uint32_t hibit)
{
uint64_t h0, h1, h2, h3, h4, t0, t1, t2, t3, t4;
uint32_t r0, r1, r2, r3, r4, x1, x2, x3, x4;
h0 = ctx->h0;
h1 = ctx->h1;
h2 = ctx->h2;
h3 = ctx->h3;
h4 = ctx->h4;
r0 = ctx->r0;
r1 = ctx->r1;
r2 = ctx->r2;
r3 = ctx->r3;
r4 = ctx->r4;
x1 = ctx->x1;
x2 = ctx->x2;
x3 = ctx->x3;
x4 = ctx->x4;
t0 = load32le(&ctx->m[0]);
t1 = load32le(&ctx->m[4]);
t2 = load32le(&ctx->m[8]);
t3 = load32le(&ctx->m[12]);
t4 = hibit;
h0 += t0 & 0x3ffffff;
h1 += ((t1 << 6) | (t0 >> 26)) & 0x3ffffff;
h2 += ((t2 << 12) | (t1 >> 20)) & 0x3ffffff;
h3 += ((t3 << 18) | (t2 >> 14)) & 0x3ffffff;
h4 += (t4 << 24) | (t3 >> 8);
t0 = h0 * r0 + h4 * x1 + h3 * x2 + h2 * x3 + h1 * x4;
t1 = h1 * r0 + h0 * r1 + h4 * x2 + h3 * x3 + h2 * x4;
t2 = h2 * r0 + h1 * r1 + h0 * r2 + h4 * x3 + h3 * x4;
t3 = h3 * r0 + h2 * r1 + h1 * r2 + h0 * r3 + h4 * x4;
t4 = h4 * r0 + h3 * r1 + h2 * r2 + h1 * r3 + h0 * r4;
h0 = t0 & 0x3ffffff;
t1 += t0 >> 26;
h1 = t1 & 0x3ffffff;
t2 += t1 >> 26;
h2 = t2 & 0x3ffffff;
t3 += t2 >> 26;
h3 = t3 & 0x3ffffff;
t4 += t3 >> 26;
h4 = t4 & 0x3ffffff;
h0 += 5 * (t4 >> 26);
h1 += h0 >> 26;
h0 &= 0x3ffffff;
ctx->h0 = h0;
ctx->h1 = h1;
ctx->h2 = h2;
ctx->h3 = h3;
ctx->h4 = h4;
}
void
poly1305_reduce(struct poly1305_ctx *ctx, uint32_t a[POLY1305_TAGLEN_WORDS])
{
uint64_t t0, t1, t2, t3, t4, g0, g1, g2, g3, g4;
uint32_t mask;
t0 = (ctx->h0 | (ctx->h1 << 26)) & 0xffffffff;
t1 = ((ctx->h1 >> 6) | (ctx->h2 << 20)) & 0xffffffff;
t2 = ((ctx->h2 >> 12) | (ctx->h3 << 14)) & 0xffffffff;
t3 = ((ctx->h3 >> 18) | (ctx->h4 << 8)) & 0xffffffff;
t4 = ctx->h4 >> 24;
g0 = t0 + 5;
g1 = t1 + (g0 >> 32);
g2 = t2 + (g1 >> 32);
g3 = t3 + (g2 >> 32);
g4 = t4 + (g3 >> 32) + 252;
mask = ~(g4 >> 8) + 1;
t0 = (t0 & ~mask) | (g0 & mask);
t1 = (t1 & ~mask) | (g1 & mask);
t2 = (t2 & ~mask) | (g2 & mask);
t3 = (t3 & ~mask) | (g3 & mask);
t0 += ctx->s0;
t1 += ctx->s1 + (t0 >> 32);
t2 += ctx->s2 + (t1 >> 32);
t3 += ctx->s3 + (t2 >> 32);
a[0] = t0 & 0xffffffff;
a[1] = t1 & 0xffffffff;
a[2] = t2 & 0xffffffff;
a[3] = t3 & 0xffffffff;
}

39
impl_poly1305.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
#include "lilcrypto.h"
#define POLY1305_CHUNK 16
#define POLY1305_TAGLEN_WORDS (LC_POLY1305_TAGLEN / sizeof(uint32_t))
struct poly1305_ctx {
uint32_t h0, h1, h2, h3, h4;
uint32_t r0, r1, r2, r3, r4;
uint32_t x1, x2, x3, x4;
uint32_t s0, s1, s2, s3;
size_t mlen;
uint8_t m[POLY1305_CHUNK];
};
void poly1305_block(struct poly1305_ctx *, uint32_t);
void poly1305_reduce(struct poly1305_ctx *,
uint32_t [POLY1305_TAGLEN_WORDS]);

7
lib/Makefile Normal file
View File

@ -0,0 +1,7 @@
.PATH: ${.CURDIR}/..
LIB= lilcrypto
NOMAN= noman
SRCS= ${LC_SRCS}
.include <bsd.lib.mk>

1
lib/shlib_version Normal file
View File

@ -0,0 +1 @@
LIBlilcrypto_VERSION=0.0

106
lilcrypto.h Normal file
View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
/*
* Constants.
*/
/* Authentitcation. */
#define LC_POLY1305_KEYLEN 32
#define LC_POLY1305_TAGLEN 16
/* Ciphers. */
#define LC_CHACHA20_KEYLEN 32
#define LC_CHACHA20_IVLEN 12
/*
* Constant-time operations.
*/
uint32_t lc_ct_cmp(const uint8_t *, const uint8_t *, size_t);
/*
* Message authentication code.
*/
struct lc_auth_ctx;
struct lc_auth_impl;
int lc_auth_init(struct lc_auth_ctx *, const uint8_t *, size_t);
int lc_auth_update(struct lc_auth_ctx *, const uint8_t *, size_t);
int lc_auth_final(struct lc_auth_ctx *, uint8_t *, size_t *);
int lc_auth(const struct lc_auth_impl *, const uint8_t *, size_t,
uint8_t *, size_t *, const uint8_t *, size_t);
struct lc_auth_ctx *lc_auth_ctx_new(const struct lc_auth_impl *);
void lc_auth_ctx_free(struct lc_auth_ctx *);
const struct lc_auth_impl *lc_auth_impl_poly1305(void);
/*
* Ciphers.
*/
struct lc_cipher_ctx;
struct lc_cipher_impl;
int lc_cipher_encrypt_init(struct lc_cipher_ctx *, const uint8_t *, size_t,
const uint8_t *, size_t);
int lc_cipher_encrypt_update(struct lc_cipher_ctx *, uint8_t *, size_t *,
const uint8_t *, size_t);
int lc_cipher_encrypt_final(struct lc_cipher_ctx *, uint8_t *, size_t *);
int lc_cipher_encrypt(const struct lc_cipher_impl *, const uint8_t *,
size_t, const uint8_t *, size_t, uint8_t *, size_t *,
const uint8_t *, size_t);
int lc_cipher_decrypt_init(struct lc_cipher_ctx *, const uint8_t *, size_t,
const uint8_t *, size_t);
int lc_cipher_decrypt_update(struct lc_cipher_ctx *, uint8_t *, size_t *,
const uint8_t *, size_t);
int lc_cipher_decrypt_final(struct lc_cipher_ctx *, uint8_t *, size_t *);
int lc_cipher_decrypt(const struct lc_cipher_impl *, const uint8_t *,
size_t, const uint8_t *, size_t, uint8_t *, size_t *,
const uint8_t *, size_t);
struct lc_cipher_ctx *lc_cipher_ctx_new(const struct lc_cipher_impl *);
void lc_cipher_ctx_free(struct lc_cipher_ctx *);
const struct lc_cipher_impl *lc_cipher_impl_chacha20(void);
/*
* Authenticated encryption with additional data.
*/
struct lc_aead_impl;
int lc_aead_seal(const struct lc_aead_impl *, const uint8_t *, size_t,
const uint8_t *, size_t, uint8_t *, size_t *, const uint8_t *, size_t,
const uint8_t *, size_t);
int lc_aead_open(const struct lc_aead_impl *, const uint8_t *, size_t,
const uint8_t *, size_t, uint8_t *, size_t *, const uint8_t *, size_t,
const uint8_t *, size_t);
const struct lc_aead_impl *lc_aead_impl_chacha20_poly1305(void);

26
util.c Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "util.h"
void
lc_scrub(void *b, size_t len)
{
explicit_bzero(b, len);
}

109
util.h Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stddef.h>
#include <stdint.h>
#define nelems(_a) (sizeof((_a)) / sizeof((_a)[0]))
/*
* External definitions.
*/
void lc_scrub(void *, size_t);
/*
* Endianness.
*/
static inline uint16_t
load16le(const uint8_t *x)
{
return x[0] | (x[1] << 8);
}
static inline uint32_t
load32le(const uint8_t *x)
{
return x[0] | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
}
static inline uint64_t
load64le(const uint8_t *x)
{
return load32le(x) | (((uint64_t)load32le(x + 4)) << 32);
}
static inline void
store16le(uint8_t *x, uint64_t v)
{
x[0] = v & 0xff;
x[1] = v >> 8;
}
static inline void
store32le(uint8_t *x, uint32_t v)
{
x[0] = v & 0xff;
x[1] = (v >> 8) & 0xff;
x[2] = (v >> 16) & 0xff;
x[3] = v >> 24;
}
static inline void
store64le(uint8_t *x, uint64_t v)
{
x[0] = v & 0xff;
x[1] = (v >> 8) & 0xff;
x[2] = (v >> 16) & 0xff;
x[3] = (v >> 24) & 0xff;
x[4] = (v >> 32) & 0xff;
x[5] = (v >> 40) & 0xff;
x[6] = (v >> 48) & 0xff;
x[7] = v >> 56;
}
/*
* rotr and rotl.
*/
static inline uint32_t
rotl32(uint32_t x, uint32_t r)
{
return (x << r) | (x >> (32 - r));
}
static inline uint64_t
rotl64(uint64_t x, uint64_t r)
{
return (x << r) | (x >> (64 - r));
}
static inline uint32_t
rotr32(uint32_t x, uint32_t r)
{
return rotl32(x, 32 - r);
}
static inline uint64_t
rotr64(uint64_t x, uint64_t r)
{
return rotl64(x, 64 - r);
}

25
wycheproof/Makefile Normal file
View File

@ -0,0 +1,25 @@
.PATH: ${.CURDIR}/..
AEAD= wycheproof_aead
PROGS= ${AEAD}
NOMAN= noman
SRCS_wycheproof_aead= wycheproof_aead.c
LDADD+= ${.CURDIR}/../lib/obj/liblilcrypto.a
tests: all tests-aead
tests-aead:
.ifndef WYCHEPROOF_DIR
@echo Undefined WYCHEPROOF_DIR; false
.endif
.for p in ${AEAD}
perl ${.CURDIR}/aead.pl -x ./${p} \
${WYCHEPROOF_DIR}/testvectors/chacha20_poly1305_test.json \
${WYCHEPROOF_DIR}/testvectors_v1/chacha20_poly1305_test.json
.endfor
.include <bsd.prog.mk>

69
wycheproof/aead.pl Normal file
View File

@ -0,0 +1,69 @@
#!/usr/bin/env perl
use v5.38;;
use strict;
use warnings;
use Getopt::Std;
use JSON::PP;
my $progname = $0 =~ s@.*/@@r;
sub slurp ($fh) { local $/; <$fh> }
sub usage ()
{
say STDERR "Usage: $progname -x runner json_file [json_files ...]";
exit 1;
}
sub main ()
{
my %opts;
my $rc = 0;
getopts("x:", \%opts) && @ARGV > 0 or usage;
usage unless defined $opts{"x"};
for my $f (@ARGV) {
open(my $fh, "<", $f) or die "open failed: $!";
my $json = decode_json(slurp($fh));
for my $testgroup ($json->{testGroups}->@*) {
for my $test ($testgroup->{tests}->@*) {
my @args;
push(@args, $json->{algorithm});
push(@args, "-a", $test->{aad});
push(@args, "-c", $test->{ct});
push(@args, "-I", $testgroup->{ivSize});
push(@args, "-i", $test->{iv});
push(@args, "-K", $testgroup->{keySize});
push(@args, "-k", $test->{key});
push(@args, "-m", $test->{msg});
push(@args, "-T", $testgroup->{tagSize});
push(@args, "-t", $test->{tag});
open(my $th, "-|", $opts{"x"}, @args) or die;
my $result = slurp($th);
close($th);
chomp($result);
if ($result ne $test->{result}) {
$rc = 1;
say STDERR "case $test->{tcId}: ",
"expected $test->{result}: ",
"$test->{comment} [",
join(",", $test->{flags}->@*),
"]";
}
}
}
close($fh);
}
say "ALL TESTS PASSED!" if $rc == 0;
return $rc;
}
exit main;

326
wycheproof_aead.c Normal file
View File

@ -0,0 +1,326 @@
/*
* Copyright (c) 2024 Lucas Gabriel Vuotto <lucas@lgv5.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <ctype.h>
#include <err.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lilcrypto.h"
#define nelems(_a) (sizeof((_a)) / sizeof((_a)[0]))
static inline uint8_t
hex2num(char s)
{
return s >= 'A' ? 10 + (s >= 'a' ? s - 'a' : s - 'A') : s - '0';
}
static int
hexparse(const char *s, uint8_t *out, size_t *outlen)
{
size_t l;
l = strlen(s);
if (l % 2 != 0)
return 0;
if (out == NULL) {
*outlen = l / 2;
return 1;
}
*outlen = 0;
while (*s != '\0') {
if (!isxdigit(s[0]) || !isxdigit(s[1]))
return 0;
*out++ = (hex2num(s[0]) << 4) | hex2num(s[1]);
(*outlen)++;
s += 2;
}
return 1;
}
static void
hexdump(FILE *fp, const uint8_t *blob, size_t len)
{
size_t i, off;
int pad;
for (i = 0; len > (1 << (8 * i)); i++)
;
pad = (i + 1) * 2;
off = 0;
while (len >= 16) {
fprintf(fp, "%0*zx\t", pad, off);
for (i = 0; i < 8; i++)
fprintf(fp, "%02x ", blob[i]);
for (; i < 16; i++)
fprintf(fp, " %02x", blob[i]);
fprintf(fp, "\t|");
for (i = 0; i < 16; i++)
fprintf(fp, "%c", isprint(blob[i]) ? blob[i] : '.');
fprintf(fp, "|\n");
blob += 16;
off += 16;
len -= 16;
}
if (len == 0)
goto out;
fprintf(fp, "%0*zx\t", pad, off);
for (i = 0; i < len && i < 8; i++)
fprintf(fp, "%02x ", blob[i]);
for (; i < 8; i++)
fprintf(fp, " ");
for (; i < len && i < 16; i++)
fprintf(fp, " %02x", blob[i]);
for (; i < 16; i++)
fprintf(fp, " ");
fprintf(fp, "\t|");
for (i = 0; i < len; i++)
fprintf(fp, "%c", isprint(blob[i]) ? blob[i] : '.');
fprintf(fp, "|\n");
out:
fprintf(fp, "%0*zx\n", pad, off + len);
fflush(fp);
}
struct kwimpl {
const char *kw;
const struct lc_aead_impl *(*impl)(void);
};
static int
kwimpl_cmp(const void *k0, const void *h0)
{
const struct kwimpl *h = h0;
const char *k = k0;
return strcmp(k, h->kw);
}
static const struct lc_aead_impl *
kw2impl(const char *s)
{
static const struct kwimpl tbl[] = {
{ "CHACHA20-POLY1305", &lc_aead_impl_chacha20_poly1305 },
};
struct kwimpl *match;
match = bsearch(s, tbl, nelems(tbl), sizeof(struct kwimpl),
&kwimpl_cmp);
return match != NULL ? match->impl() : NULL;
}
static void
usage(void)
{
fprintf(stderr, "Usage: %s [options]\n", getprogname());
exit(1);
}
int
main(int argc, char *argv[])
{
const struct lc_aead_impl *impl;
uint8_t *aad, *ct, *iv, *key, *msg, *tag, *out;
const char *errstr;
size_t aadlen, ctlen, ivlen, keylen, msglen, taglen;
size_t ivlenarg, keylenarg, taglenarg;
size_t l, outlen;
int aflag, cflag, Iflag, iflag, Kflag, kflag, mflag,
Tflag, tflag;
int ch;
if (argc < 2)
usage();
impl = kw2impl(argv[1]);
if (impl == NULL)
errx(1, "unsupported algorithm: %s", argv[1]);
optind = 2;
aflag = cflag = Iflag = iflag = Kflag = kflag = mflag = Tflag = tflag =
0;
while ((ch = getopt(argc, argv, "a:c:I:i:K:k:m:T:t:")) != -1) {
switch (ch) {
case 'a':
aflag = 1;
(void)hexparse(optarg, NULL, &aadlen);
if (aadlen != 0) {
aad = malloc(aadlen);
if (aad == NULL)
err(1, "out of memory");
} else
aad = NULL;
if (!hexparse(optarg, aad, &l) || l != aadlen)
errx(1, "invalid hex string: %s", optarg);
break;
case 'c':
cflag = 1;
(void)hexparse(optarg, NULL, &ctlen);
if (ctlen != 0) {
ct = malloc(ctlen);
if (ct == NULL)
err(1, "out of memory");
} else
ct = NULL;
if (!hexparse(optarg, ct, &l) || l != ctlen)
errx(1, "invalid hex string: %s", optarg);
break;
case 'I':
Iflag = 1;
ivlenarg = strtonum(optarg, 0, LLONG_MAX, &errstr);
if (errstr != NULL)
errx(1, "ivlen is %s: %s", errstr, optarg);
break;
case 'i':
iflag = 1;
(void)hexparse(optarg, NULL, &ivlen);
if (ivlen != 0) {
iv = malloc(ivlen);
if (iv == NULL)
err(1, "out of memory");
} else
iv = NULL;
if (!hexparse(optarg, iv, &l) || l != ivlen)
errx(1, "invalid hex string: %s", optarg);
break;
case 'K':
Kflag = 1;
keylenarg = strtonum(optarg, 0, LLONG_MAX, &errstr);
if (errstr != NULL)
errx(1, "keylen is %s: %s", errstr, optarg);
if (keylenarg % 8 != 0)
errx(1, "unsupport K value: %zu", keylenarg);
break;
case 'k':
kflag = 1;
(void)hexparse(optarg, NULL, &keylen);
if (keylen != 0) {
key = malloc(keylen);
if (key == NULL)
err(1, "out of memory");
} else
key = NULL;
if (!hexparse(optarg, key, &l) || l != keylen)
errx(1, "invalid hex string: %s", optarg);
break;
case 'm':
mflag = 1;
(void)hexparse(optarg, NULL, &msglen);
if (msglen != 0) {
msg = malloc(msglen);
if (msg == NULL)
err(1, "out of memory");
} else
msg = NULL;
if (!hexparse(optarg, msg, &l) || l != msglen)
errx(1, "invalid hex string: %s", optarg);
break;
case 'T':
Tflag = 1;
taglenarg = strtonum(optarg, 0, LLONG_MAX, &errstr);
if (errstr != NULL)
errx(1, "taglen is %s: %s", errstr, optarg);
break;
case 't':
tflag = 1;
(void)hexparse(optarg, NULL, &taglen);
if (taglen != 0) {
tag = malloc(taglen);
if (tag == NULL)
err(1, "out of memory");
} else
tag = NULL;
if (!hexparse(optarg, tag, &l) || l != taglen)
errx(1, "invalid hex string: %s", optarg);
break;
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
if (!(aflag && cflag && Iflag && iflag && Kflag && kflag && mflag &&
Tflag && tflag))
errx(1, "missing required arguments");
if (!lc_aead_seal(impl, key, keylenarg, iv, ivlenarg, NULL, &outlen,
aad, aadlen, msg, msglen)) {
puts("invalid");
return 1;
}
ivlenarg /= 8;
keylenarg /= 8;
taglenarg /= 8;
out = malloc(outlen);
if (out == NULL)
err(1, "out of memory");
if (!lc_aead_seal(impl, key, keylenarg, iv, ivlenarg, out, &outlen,
aad, aadlen, msg, msglen)) {
puts("invalid");
return 1;
}
if (ctlen != outlen - LC_POLY1305_TAGLEN ||
lc_ct_cmp(out, ct, ctlen) != 0) {
fprintf(stderr, "ct (%zu, %zu)\n", ctlen,
outlen - LC_POLY1305_TAGLEN);
hexdump(stderr, msg, msglen);
fprintf(stderr, "\n");
hexdump(stderr, ct, ctlen);
fprintf(stderr, "\n");
hexdump(stderr, out, outlen - LC_POLY1305_TAGLEN);
fprintf(stderr, "\n");
puts("invalid");
return 1;
}
if (taglenarg != LC_POLY1305_TAGLEN ||
lc_ct_cmp(out + ctlen, tag, LC_POLY1305_TAGLEN) != 0) {
fprintf(stderr, "tag (%zu, %zu)\n", taglenarg,
(size_t)LC_POLY1305_TAGLEN);
hexdump(stderr, tag, taglen);
fprintf(stderr, "\n");
hexdump(stderr, out + ctlen, LC_POLY1305_TAGLEN);
fprintf(stderr, "\n");
puts("invalid");
return 1;
}
puts("valid");
return 0;
}