|  | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | 
|  | From: Ard Biesheuvel <ardb@kernel.org> | 
|  | Date: Fri, 8 Nov 2019 13:22:21 +0100 | 
|  | Subject: [PATCH] crypto: poly1305 - expose init/update/final library interface | 
|  |  | 
|  | commit a1d93064094cc5e24d64e35cf093e7191d0c9344 upstream. | 
|  |  | 
|  | 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> | 
|  | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> | 
|  | --- | 
|  | crypto/poly1305_generic.c | 22 +----------- | 
|  | include/crypto/poly1305.h | 38 +++++++++++++++++++- | 
|  | lib/crypto/Kconfig        | 26 ++++++++++++++ | 
|  | lib/crypto/poly1305.c     | 74 +++++++++++++++++++++++++++++++++++++++ | 
|  | 4 files changed, 138 insertions(+), 22 deletions(-) | 
|  |  | 
|  | --- a/crypto/poly1305_generic.c | 
|  | +++ b/crypto/poly1305_generic.c | 
|  | @@ -85,31 +85,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_generic(dctx, dst); | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(crypto_poly1305_final); | 
|  | --- a/include/crypto/poly1305.h | 
|  | +++ b/include/crypto/poly1305.h | 
|  | @@ -35,7 +35,43 @@ struct poly1305_desc_ctx { | 
|  | /* accumulator */ | 
|  | struct poly1305_state h; | 
|  | /* key */ | 
|  | -	struct poly1305_key r[1]; | 
|  | +	struct poly1305_key r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE]; | 
|  | }; | 
|  |  | 
|  | +void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key); | 
|  | +void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key); | 
|  | + | 
|  | +static inline void poly1305_init(struct poly1305_desc_ctx *desc, const u8 *key) | 
|  | +{ | 
|  | +	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305)) | 
|  | +		poly1305_init_arch(desc, key); | 
|  | +	else | 
|  | +		poly1305_init_generic(desc, key); | 
|  | +} | 
|  | + | 
|  | +void poly1305_update_arch(struct poly1305_desc_ctx *desc, const u8 *src, | 
|  | +			  unsigned int nbytes); | 
|  | +void poly1305_update_generic(struct poly1305_desc_ctx *desc, const u8 *src, | 
|  | +			     unsigned int nbytes); | 
|  | + | 
|  | +static inline void poly1305_update(struct poly1305_desc_ctx *desc, | 
|  | +				   const u8 *src, unsigned int nbytes) | 
|  | +{ | 
|  | +	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305)) | 
|  | +		poly1305_update_arch(desc, src, nbytes); | 
|  | +	else | 
|  | +		poly1305_update_generic(desc, src, nbytes); | 
|  | +} | 
|  | + | 
|  | +void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *digest); | 
|  | +void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *digest); | 
|  | + | 
|  | +static inline void poly1305_final(struct poly1305_desc_ctx *desc, u8 *digest) | 
|  | +{ | 
|  | +	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305)) | 
|  | +		poly1305_final_arch(desc, digest); | 
|  | +	else | 
|  | +		poly1305_final_generic(desc, digest); | 
|  | +} | 
|  | + | 
|  | #endif | 
|  | --- a/lib/crypto/Kconfig | 
|  | +++ b/lib/crypto/Kconfig | 
|  | @@ -37,8 +37,34 @@ config CRYPTO_LIB_CHACHA | 
|  | config CRYPTO_LIB_DES | 
|  | tristate | 
|  |  | 
|  | +config CRYPTO_LIB_POLY1305_RSIZE | 
|  | +	int | 
|  | +	default 1 | 
|  | + | 
|  | +config CRYPTO_ARCH_HAVE_LIB_POLY1305 | 
|  | +	tristate | 
|  | +	help | 
|  | +	  Declares whether the architecture provides an arch-specific | 
|  | +	  accelerated implementation of the Poly1305 library interface, | 
|  | +	  either builtin or as a module. | 
|  | + | 
|  | config CRYPTO_LIB_POLY1305_GENERIC | 
|  | tristate | 
|  | +	help | 
|  | +	  This symbol can be depended upon by arch implementations of the | 
|  | +	  Poly1305 library interface that require the generic code as a | 
|  | +	  fallback, e.g., for SIMD implementations. If no arch specific | 
|  | +	  implementation is enabled, this implementation serves the users | 
|  | +	  of CRYPTO_LIB_POLY1305. | 
|  | + | 
|  | +config CRYPTO_LIB_POLY1305 | 
|  | +	tristate "Poly1305 library interface" | 
|  | +	depends on CRYPTO_ARCH_HAVE_LIB_POLY1305 || !CRYPTO_ARCH_HAVE_LIB_POLY1305 | 
|  | +	select CRYPTO_LIB_POLY1305_GENERIC if CRYPTO_ARCH_HAVE_LIB_POLY1305=n | 
|  | +	help | 
|  | +	  Enable the Poly1305 library interface. This interface may be fulfilled | 
|  | +	  by either the generic implementation or an arch-specific one, if one | 
|  | +	  is available and enabled. | 
|  |  | 
|  | config CRYPTO_LIB_SHA256 | 
|  | tristate | 
|  | --- a/lib/crypto/poly1305.c | 
|  | +++ b/lib/crypto/poly1305.c | 
|  | @@ -154,5 +154,79 @@ void poly1305_core_emit(const struct pol | 
|  | } | 
|  | 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>"); |