crypto: lib/poly1305 - Add block-only interface

Add a block-only interface for poly1305.  Implement the generic
code first.

Also use the generic partial block helper.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Herbert Xu 2025-04-28 12:56:07 +08:00
parent 74a43a2cf5
commit 9b84cb8978
3 changed files with 68 additions and 39 deletions

View file

@ -6,9 +6,8 @@
#ifndef _CRYPTO_INTERNAL_POLY1305_H
#define _CRYPTO_INTERNAL_POLY1305_H
#include <linux/unaligned.h>
#include <linux/types.h>
#include <crypto/poly1305.h>
#include <linux/types.h>
/*
* Poly1305 core functions. These only accept whole blocks; the caller must
@ -31,4 +30,29 @@ void poly1305_core_blocks(struct poly1305_state *state,
void poly1305_core_emit(const struct poly1305_state *state, const u32 nonce[4],
void *dst);
void poly1305_block_init_arch(struct poly1305_block_state *state,
const u8 raw_key[POLY1305_BLOCK_SIZE]);
void poly1305_block_init_generic(struct poly1305_block_state *state,
const u8 raw_key[POLY1305_BLOCK_SIZE]);
void poly1305_blocks_arch(struct poly1305_block_state *state, const u8 *src,
unsigned int len, u32 padbit);
static inline void poly1305_blocks_generic(struct poly1305_block_state *state,
const u8 *src, unsigned int len,
u32 padbit)
{
poly1305_core_blocks(&state->h, &state->core_r, src,
len / POLY1305_BLOCK_SIZE, padbit);
}
void poly1305_emit_arch(const struct poly1305_state *state,
u8 digest[POLY1305_DIGEST_SIZE], const u32 nonce[4]);
static inline void poly1305_emit_generic(const struct poly1305_state *state,
u8 digest[POLY1305_DIGEST_SIZE],
const u32 nonce[4])
{
poly1305_core_emit(state, nonce, digest);
}
#endif

View file

@ -7,7 +7,6 @@
#define _CRYPTO_POLY1305_H
#include <linux/types.h>
#include <linux/crypto.h>
#define POLY1305_BLOCK_SIZE 16
#define POLY1305_KEY_SIZE 32
@ -38,6 +37,17 @@ struct poly1305_state {
};
};
/* Combined state for block function. */
struct poly1305_block_state {
/* accumulator */
struct poly1305_state h;
/* key */
union {
struct poly1305_key opaque_r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE];
struct poly1305_core_key core_r;
};
};
struct poly1305_desc_ctx {
/* partial buffer */
u8 buf[POLY1305_BLOCK_SIZE];
@ -45,12 +55,15 @@ struct poly1305_desc_ctx {
unsigned int buflen;
/* finalize key */
u32 s[4];
/* accumulator */
struct poly1305_state h;
/* key */
union {
struct poly1305_key opaque_r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE];
struct poly1305_core_key core_r;
struct {
struct poly1305_state h;
union {
struct poly1305_key opaque_r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE];
struct poly1305_core_key core_r;
};
};
struct poly1305_block_state state;
};
};

View file

@ -7,54 +7,45 @@
* Based on public domain code by Andrew Moon and Daniel J. Bernstein.
*/
#include <crypto/internal/blockhash.h>
#include <crypto/internal/poly1305.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/unaligned.h>
void poly1305_block_init_generic(struct poly1305_block_state *desc,
const u8 raw_key[POLY1305_BLOCK_SIZE])
{
poly1305_core_init(&desc->h);
poly1305_core_setkey(&desc->core_r, raw_key);
}
EXPORT_SYMBOL_GPL(poly1305_block_init_generic);
void poly1305_init_generic(struct poly1305_desc_ctx *desc,
const u8 key[POLY1305_KEY_SIZE])
{
poly1305_core_setkey(&desc->core_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;
poly1305_block_init_generic(&desc->state, key);
}
EXPORT_SYMBOL_GPL(poly1305_init_generic);
static inline void poly1305_blocks(struct poly1305_block_state *state,
const u8 *src, unsigned int len)
{
poly1305_blocks_generic(state, src, len, 1);
}
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->core_r, desc->buf,
1, 1);
desc->buflen = 0;
}
}
if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
poly1305_core_blocks(&desc->h, &desc->core_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);
}
desc->buflen = BLOCK_HASH_UPDATE(poly1305_blocks, &desc->state,
src, nbytes, POLY1305_BLOCK_SIZE,
desc->buf, desc->buflen);
}
EXPORT_SYMBOL_GPL(poly1305_update_generic);
@ -64,10 +55,11 @@ void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *dst)
desc->buf[desc->buflen++] = 1;
memset(desc->buf + desc->buflen, 0,
POLY1305_BLOCK_SIZE - desc->buflen);
poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf, 1, 0);
poly1305_blocks_generic(&desc->state, desc->buf,
POLY1305_BLOCK_SIZE, 0);
}
poly1305_core_emit(&desc->h, desc->s, dst);
poly1305_emit_generic(&desc->h, dst, desc->s);
*desc = (struct poly1305_desc_ctx){};
}
EXPORT_SYMBOL_GPL(poly1305_final_generic);