Add the usual init/update/final library routines for the Poly1305 keyed hash library. Since this will be the external interface of the library, move the poly1305_core_* routines to the internal header (and update the users to refer to it where needed) Signed-off-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx> --- crypto/adiantum.c | 1 + crypto/nhpoly1305.c | 1 + crypto/poly1305_generic.c | 57 +++++++------------ include/crypto/internal/poly1305.h | 16 ++---- include/crypto/poly1305.h | 34 ++++++++++-- lib/crypto/poly1305.c | 58 ++++++++++++++++++++ 6 files changed, 115 insertions(+), 52 deletions(-) diff --git a/crypto/adiantum.c b/crypto/adiantum.c index 775ed1418e2b..aded26092268 100644 --- a/crypto/adiantum.c +++ b/crypto/adiantum.c @@ -33,6 +33,7 @@ #include <crypto/b128ops.h> #include <crypto/chacha.h> #include <crypto/internal/hash.h> +#include <crypto/internal/poly1305.h> #include <crypto/internal/skcipher.h> #include <crypto/nhpoly1305.h> #include <crypto/scatterwalk.h> diff --git a/crypto/nhpoly1305.c b/crypto/nhpoly1305.c index b88a6a71e3e2..f6b6a52092b4 100644 --- a/crypto/nhpoly1305.c +++ b/crypto/nhpoly1305.c @@ -33,6 +33,7 @@ #include <asm/unaligned.h> #include <crypto/algapi.h> #include <crypto/internal/hash.h> +#include <crypto/internal/poly1305.h> #include <crypto/nhpoly1305.h> #include <linux/crypto.h> #include <linux/kernel.h> diff --git a/crypto/poly1305_generic.c b/crypto/poly1305_generic.c index 46a2da1abac7..69241e7e85be 100644 --- a/crypto/poly1305_generic.c +++ b/crypto/poly1305_generic.c @@ -23,8 +23,8 @@ int crypto_poly1305_init(struct shash_desc *desc) { struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); - poly1305_core_init(&dctx->h); - dctx->buflen = 0; + poly1305_core_init(&dctx->desc.h); + dctx->desc.buflen = 0; dctx->rset = false; dctx->sset = false; @@ -42,16 +42,16 @@ unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, { if (!dctx->sset) { if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { - poly1305_core_setkey(&dctx->r, src); + poly1305_core_setkey(&dctx->desc.r, src); src += POLY1305_BLOCK_SIZE; srclen -= POLY1305_BLOCK_SIZE; dctx->rset = true; } if (srclen >= POLY1305_BLOCK_SIZE) { - dctx->s[0] = get_unaligned_le32(src + 0); - dctx->s[1] = get_unaligned_le32(src + 4); - dctx->s[2] = get_unaligned_le32(src + 8); - dctx->s[3] = get_unaligned_le32(src + 12); + dctx->desc.s[0] = get_unaligned_le32(src + 0); + dctx->desc.s[1] = get_unaligned_le32(src + 4); + dctx->desc.s[2] = get_unaligned_le32(src + 8); + dctx->desc.s[3] = get_unaligned_le32(src + 12); src += POLY1305_BLOCK_SIZE; srclen -= POLY1305_BLOCK_SIZE; dctx->sset = true; @@ -72,7 +72,7 @@ static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src, srclen = datalen; } - poly1305_core_blocks(&dctx->h, &dctx->r, src, + poly1305_core_blocks(&dctx->desc.h, &dctx->desc.r, src, srclen / POLY1305_BLOCK_SIZE, 1); } @@ -82,16 +82,17 @@ int crypto_poly1305_update(struct shash_desc *desc, struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); unsigned int bytes; - if (unlikely(dctx->buflen)) { - bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen); - memcpy(dctx->buf + dctx->buflen, src, bytes); + if (unlikely(dctx->desc.buflen)) { + bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->desc.buflen); + memcpy(dctx->desc.buf + dctx->desc.buflen, src, bytes); src += bytes; srclen -= bytes; - dctx->buflen += bytes; + dctx->desc.buflen += bytes; - if (dctx->buflen == POLY1305_BLOCK_SIZE) { - poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE); - dctx->buflen = 0; + if (dctx->desc.buflen == POLY1305_BLOCK_SIZE) { + poly1305_blocks(dctx, dctx->desc.buf, + POLY1305_BLOCK_SIZE); + dctx->desc.buflen = 0; } } @@ -102,8 +103,8 @@ int crypto_poly1305_update(struct shash_desc *desc, } if (unlikely(srclen)) { - dctx->buflen = srclen; - memcpy(dctx->buf, src, srclen); + dctx->desc.buflen = srclen; + memcpy(dctx->desc.buf, src, srclen); } return 0; @@ -113,31 +114,11 @@ EXPORT_SYMBOL_GPL(crypto_poly1305_update); int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) { struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); - __le32 digest[4]; - u64 f = 0; if (unlikely(!dctx->sset)) return -ENOKEY; - if (unlikely(dctx->buflen)) { - dctx->buf[dctx->buflen++] = 1; - memset(dctx->buf + dctx->buflen, 0, - POLY1305_BLOCK_SIZE - dctx->buflen); - poly1305_core_blocks(&dctx->h, &dctx->r, dctx->buf, 1, 0); - } - - poly1305_core_emit(&dctx->h, digest); - - /* mac = (h + s) % (2^128) */ - f = (f >> 32) + le32_to_cpu(digest[0]) + dctx->s[0]; - put_unaligned_le32(f, dst + 0); - f = (f >> 32) + le32_to_cpu(digest[1]) + dctx->s[1]; - put_unaligned_le32(f, dst + 4); - f = (f >> 32) + le32_to_cpu(digest[2]) + dctx->s[2]; - put_unaligned_le32(f, dst + 8); - f = (f >> 32) + le32_to_cpu(digest[3]) + dctx->s[3]; - put_unaligned_le32(f, dst + 12); - + poly1305_final(&dctx->desc, dst); return 0; } EXPORT_SYMBOL_GPL(crypto_poly1305_final); diff --git a/include/crypto/internal/poly1305.h b/include/crypto/internal/poly1305.h index ae0466c4ce59..619705200e70 100644 --- a/include/crypto/internal/poly1305.h +++ b/include/crypto/internal/poly1305.h @@ -10,22 +10,18 @@ #include <crypto/poly1305.h> struct poly1305_desc_ctx { - /* key */ - struct poly1305_key r; - /* finalize key */ - u32 s[4]; - /* accumulator */ - struct poly1305_state h; - /* partial buffer */ - u8 buf[POLY1305_BLOCK_SIZE]; - /* bytes used in partial buffer */ - unsigned int buflen; + struct poly1305_desc desc; /* r key has been set */ bool rset; /* s key has been set */ bool sset; }; +void poly1305_core_blocks(struct poly1305_state *state, + const struct poly1305_key *key, const void *src, + unsigned int nblocks, u32 hibit); +void poly1305_core_emit(const struct poly1305_state *state, void *dst); + /* Crypto API helper functions for the Poly1305 MAC */ int crypto_poly1305_init(struct shash_desc *desc); unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, diff --git a/include/crypto/poly1305.h b/include/crypto/poly1305.h index 83e4b4c69a5a..148d9049b906 100644 --- a/include/crypto/poly1305.h +++ b/include/crypto/poly1305.h @@ -6,6 +6,7 @@ #ifndef _CRYPTO_POLY1305_H #define _CRYPTO_POLY1305_H +#include <asm/unaligned.h> #include <linux/types.h> #include <linux/crypto.h> @@ -21,6 +22,19 @@ struct poly1305_state { u32 h[5]; /* accumulator, base 2^26 */ }; +struct poly1305_desc { + /* key */ + struct poly1305_key r; + /* finalize key */ + u32 s[4]; + /* accumulator */ + struct poly1305_state h; + /* partial buffer */ + u8 buf[POLY1305_BLOCK_SIZE]; + /* bytes used in partial buffer */ + unsigned int buflen; +}; + /* * Poly1305 core functions. These implement the ε-almost-∆-universal hash * function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce @@ -31,8 +45,20 @@ static inline void poly1305_core_init(struct poly1305_state *state) { *state = (struct poly1305_state){}; } -void poly1305_core_blocks(struct poly1305_state *state, - const struct poly1305_key *key, const void *src, - unsigned int nblocks, u32 hibit); -void poly1305_core_emit(const struct poly1305_state *state, void *dst); + +static inline void poly1305_init(struct poly1305_desc *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; +} + +void poly1305_update(struct poly1305_desc *desc, const u8 *src, + unsigned int nbytes); +void poly1305_final(struct poly1305_desc *desc, u8 *digest); + #endif diff --git a/lib/crypto/poly1305.c b/lib/crypto/poly1305.c index abe6fccf7b9c..9af7cb5364af 100644 --- a/lib/crypto/poly1305.c +++ b/lib/crypto/poly1305.c @@ -154,5 +154,63 @@ void poly1305_core_emit(const struct poly1305_state *state, void *dst) } EXPORT_SYMBOL_GPL(poly1305_core_emit); +void poly1305_update(struct poly1305_desc *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); + +void poly1305_final(struct poly1305_desc *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); +} +EXPORT_SYMBOL_GPL(poly1305_final); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Martin Willi <martin@xxxxxxxxxxxxxx>"); -- 2.20.1