@@ -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>
@@ -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>
@@ -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);
@@ -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,
@@ -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
@@ -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@strongswan.org>");
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@linaro.org> --- 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(-) -- 2.20.1