crypto: poly1305 - expose init/update/final library interface

Expose the existing generic Poly1305 code via a init/update/final
library interface so that callers are not required to go through
the crypto API's shash abstraction to access it. At the same time,
make some preparations so that the library implementation can be
superseded by an accelerated arch-specific version in the future.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Ard Biesheuvel
2019-11-08 13:22:21 +01:00
committed by Herbert Xu
parent ad8f5b8838
commit a1d9306409
4 changed files with 138 additions and 22 deletions

View File

@@ -154,5 +154,79 @@ void poly1305_core_emit(const struct poly1305_state *state, void *dst)
}
EXPORT_SYMBOL_GPL(poly1305_core_emit);
void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key)
{
poly1305_core_setkey(desc->r, key);
desc->s[0] = get_unaligned_le32(key + 16);
desc->s[1] = get_unaligned_le32(key + 20);
desc->s[2] = get_unaligned_le32(key + 24);
desc->s[3] = get_unaligned_le32(key + 28);
poly1305_core_init(&desc->h);
desc->buflen = 0;
desc->sset = true;
desc->rset = 1;
}
EXPORT_SYMBOL_GPL(poly1305_init_generic);
void poly1305_update_generic(struct poly1305_desc_ctx *desc, const u8 *src,
unsigned int nbytes)
{
unsigned int bytes;
if (unlikely(desc->buflen)) {
bytes = min(nbytes, POLY1305_BLOCK_SIZE - desc->buflen);
memcpy(desc->buf + desc->buflen, src, bytes);
src += bytes;
nbytes -= bytes;
desc->buflen += bytes;
if (desc->buflen == POLY1305_BLOCK_SIZE) {
poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 1);
desc->buflen = 0;
}
}
if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
poly1305_core_blocks(&desc->h, desc->r, src,
nbytes / POLY1305_BLOCK_SIZE, 1);
src += nbytes - (nbytes % POLY1305_BLOCK_SIZE);
nbytes %= POLY1305_BLOCK_SIZE;
}
if (unlikely(nbytes)) {
desc->buflen = nbytes;
memcpy(desc->buf, src, nbytes);
}
}
EXPORT_SYMBOL_GPL(poly1305_update_generic);
void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *dst)
{
__le32 digest[4];
u64 f = 0;
if (unlikely(desc->buflen)) {
desc->buf[desc->buflen++] = 1;
memset(desc->buf + desc->buflen, 0,
POLY1305_BLOCK_SIZE - desc->buflen);
poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 0);
}
poly1305_core_emit(&desc->h, digest);
/* mac = (h + s) % (2^128) */
f = (f >> 32) + le32_to_cpu(digest[0]) + desc->s[0];
put_unaligned_le32(f, dst + 0);
f = (f >> 32) + le32_to_cpu(digest[1]) + desc->s[1];
put_unaligned_le32(f, dst + 4);
f = (f >> 32) + le32_to_cpu(digest[2]) + desc->s[2];
put_unaligned_le32(f, dst + 8);
f = (f >> 32) + le32_to_cpu(digest[3]) + desc->s[3];
put_unaligned_le32(f, dst + 12);
*desc = (struct poly1305_desc_ctx){};
}
EXPORT_SYMBOL_GPL(poly1305_final_generic);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");