Commit 67a99386 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull crypto fix from Herbert Xu:
 "This fixes a regression where wp512 can no longer be used with hmac"

* tag 'v6.16-p6' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6:
  crypto: wp512 - Use API partial block handling
parents 6f2a71a9 20d71750
Loading
Loading
Loading
Loading
+45 −76
Original line number Diff line number Diff line
@@ -21,10 +21,10 @@
 */
#include <crypto/internal/hash.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <asm/byteorder.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/unaligned.h>

#define WP512_DIGEST_SIZE 64
#define WP384_DIGEST_SIZE 48
@@ -37,9 +37,6 @@

struct wp512_ctx {
	u8  bitLength[WP512_LENGTHBYTES];
	u8  buffer[WP512_BLOCK_SIZE];
	int bufferBits;
	int bufferPos;
	u64 hash[WP512_DIGEST_SIZE/8];
};

@@ -779,16 +776,16 @@ static const u64 rc[WHIRLPOOL_ROUNDS] = {
 * The core Whirlpool transform.
 */

static __no_kmsan_checks void wp512_process_buffer(struct wp512_ctx *wctx) {
static __no_kmsan_checks void wp512_process_buffer(struct wp512_ctx *wctx,
						   const u8 *buffer) {
	int i, r;
	u64 K[8];        /* the round key */
	u64 block[8];    /* mu(buffer) */
	u64 state[8];    /* the cipher state */
	u64 L[8];
	const __be64 *buffer = (const __be64 *)wctx->buffer;

	for (i = 0; i < 8; i++)
		block[i] = be64_to_cpu(buffer[i]);
		block[i] = get_unaligned_be64(buffer + i * 8);

	state[0] = block[0] ^ (K[0] = wctx->hash[0]);
	state[1] = block[1] ^ (K[1] = wctx->hash[1]);
@@ -991,8 +988,6 @@ static int wp512_init(struct shash_desc *desc) {
	int i;

	memset(wctx->bitLength, 0, 32);
	wctx->bufferBits = wctx->bufferPos = 0;
	wctx->buffer[0] = 0;
	for (i = 0; i < 8; i++) {
		wctx->hash[i] = 0L;
	}
@@ -1000,84 +995,54 @@ static int wp512_init(struct shash_desc *desc) {
	return 0;
}

static int wp512_update(struct shash_desc *desc, const u8 *source,
			 unsigned int len)
static void wp512_add_length(u8 *bitLength, u64 value)
{
	struct wp512_ctx *wctx = shash_desc_ctx(desc);
	int sourcePos    = 0;
	unsigned int bits_len = len * 8; // convert to number of bits
	int sourceGap    = (8 - ((int)bits_len & 7)) & 7;
	int bufferRem    = wctx->bufferBits & 7;
	u32 carry;
	int i;
	u32 b, carry;
	u8 *buffer       = wctx->buffer;
	u8 *bitLength    = wctx->bitLength;
	int bufferBits   = wctx->bufferBits;
	int bufferPos    = wctx->bufferPos;

	u64 value = bits_len;
	for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != 0ULL); i--) {
		carry += bitLength[i] + ((u32)value & 0xff);
		bitLength[i] = (u8)carry;
		carry >>= 8;
		value >>= 8;
	}
	while (bits_len > 8) {
		b = ((source[sourcePos] << sourceGap) & 0xff) |
		((source[sourcePos + 1] & 0xff) >> (8 - sourceGap));
		buffer[bufferPos++] |= (u8)(b >> bufferRem);
		bufferBits += 8 - bufferRem;
		if (bufferBits == WP512_BLOCK_SIZE * 8) {
			wp512_process_buffer(wctx);
			bufferBits = bufferPos = 0;
		}
		buffer[bufferPos] = b << (8 - bufferRem);
		bufferBits += bufferRem;
		bits_len -= 8;
		sourcePos++;
	}
	if (bits_len > 0) {
		b = (source[sourcePos] << sourceGap) & 0xff;
		buffer[bufferPos] |= b >> bufferRem;
	} else {
		b = 0;
	}
	if (bufferRem + bits_len < 8) {
		bufferBits += bits_len;
	} else {
		bufferPos++;
		bufferBits += 8 - bufferRem;
		bits_len -= 8 - bufferRem;
		if (bufferBits == WP512_BLOCK_SIZE * 8) {
			wp512_process_buffer(wctx);
			bufferBits = bufferPos = 0;
		}
		buffer[bufferPos] = b << (8 - bufferRem);
		bufferBits += (int)bits_len;
}

	wctx->bufferBits   = bufferBits;
	wctx->bufferPos    = bufferPos;
static int wp512_update(struct shash_desc *desc, const u8 *source,
			 unsigned int len)
{
	struct wp512_ctx *wctx = shash_desc_ctx(desc);
	unsigned int remain = len % WP512_BLOCK_SIZE;
	u64 bits_len = (len - remain) * 8ull;
	u8 *bitLength    = wctx->bitLength;

	return 0;
	wp512_add_length(bitLength, bits_len);
	do {
		wp512_process_buffer(wctx, source);
		source += WP512_BLOCK_SIZE;
		bits_len -= WP512_BLOCK_SIZE * 8;
	} while (bits_len);

	return remain;
}

static int wp512_final(struct shash_desc *desc, u8 *out)
static int wp512_finup(struct shash_desc *desc, const u8 *src,
		       unsigned int bufferPos, u8 *out)
{
	struct wp512_ctx *wctx = shash_desc_ctx(desc);
	int i;
	u8 *buffer      = wctx->buffer;
	u8 *bitLength   = wctx->bitLength;
	int bufferBits  = wctx->bufferBits;
	int bufferPos   = wctx->bufferPos;
	__be64 *digest  = (__be64 *)out;
	u8 buffer[WP512_BLOCK_SIZE];

	buffer[bufferPos] |= 0x80U >> (bufferBits & 7);
	wp512_add_length(bitLength, bufferPos * 8);
	memcpy(buffer, src, bufferPos);
	buffer[bufferPos] = 0x80U;
	bufferPos++;
	if (bufferPos > WP512_BLOCK_SIZE - WP512_LENGTHBYTES) {
		if (bufferPos < WP512_BLOCK_SIZE)
			memset(&buffer[bufferPos], 0, WP512_BLOCK_SIZE - bufferPos);
		wp512_process_buffer(wctx);
		wp512_process_buffer(wctx, buffer);
		bufferPos = 0;
	}
	if (bufferPos < WP512_BLOCK_SIZE - WP512_LENGTHBYTES)
@@ -1086,31 +1051,32 @@ static int wp512_final(struct shash_desc *desc, u8 *out)
	bufferPos = WP512_BLOCK_SIZE - WP512_LENGTHBYTES;
	memcpy(&buffer[WP512_BLOCK_SIZE - WP512_LENGTHBYTES],
		   bitLength, WP512_LENGTHBYTES);
	wp512_process_buffer(wctx);
	wp512_process_buffer(wctx, buffer);
	memzero_explicit(buffer, sizeof(buffer));
	for (i = 0; i < WP512_DIGEST_SIZE/8; i++)
		digest[i] = cpu_to_be64(wctx->hash[i]);
	wctx->bufferBits   = bufferBits;
	wctx->bufferPos    = bufferPos;

	return 0;
}

static int wp384_final(struct shash_desc *desc, u8 *out)
static int wp384_finup(struct shash_desc *desc, const u8 *src,
		       unsigned int len, u8 *out)
{
	u8 D[64];

	wp512_final(desc, D);
	wp512_finup(desc, src, len, D);
	memcpy(out, D, WP384_DIGEST_SIZE);
	memzero_explicit(D, WP512_DIGEST_SIZE);

	return 0;
}

static int wp256_final(struct shash_desc *desc, u8 *out)
static int wp256_finup(struct shash_desc *desc, const u8 *src,
		       unsigned int len, u8 *out)
{
	u8 D[64];

	wp512_final(desc, D);
	wp512_finup(desc, src, len, D);
	memcpy(out, D, WP256_DIGEST_SIZE);
	memzero_explicit(D, WP512_DIGEST_SIZE);

@@ -1121,11 +1087,12 @@ static struct shash_alg wp_algs[3] = { {
	.digestsize	=	WP512_DIGEST_SIZE,
	.init		=	wp512_init,
	.update		=	wp512_update,
	.final		=	wp512_final,
	.finup		=	wp512_finup,
	.descsize	=	sizeof(struct wp512_ctx),
	.base		=	{
		.cra_name	 =	"wp512",
		.cra_driver_name =	"wp512-generic",
		.cra_flags	 =	CRYPTO_AHASH_ALG_BLOCK_ONLY,
		.cra_blocksize	 =	WP512_BLOCK_SIZE,
		.cra_module	 =	THIS_MODULE,
	}
@@ -1133,11 +1100,12 @@ static struct shash_alg wp_algs[3] = { {
	.digestsize	=	WP384_DIGEST_SIZE,
	.init		=	wp512_init,
	.update		=	wp512_update,
	.final		=	wp384_final,
	.finup		=	wp384_finup,
	.descsize	=	sizeof(struct wp512_ctx),
	.base		=	{
		.cra_name	 =	"wp384",
		.cra_driver_name =	"wp384-generic",
		.cra_flags	 =	CRYPTO_AHASH_ALG_BLOCK_ONLY,
		.cra_blocksize	 =	WP512_BLOCK_SIZE,
		.cra_module	 =	THIS_MODULE,
	}
@@ -1145,11 +1113,12 @@ static struct shash_alg wp_algs[3] = { {
	.digestsize	=	WP256_DIGEST_SIZE,
	.init		=	wp512_init,
	.update		=	wp512_update,
	.final		=	wp256_final,
	.finup		=	wp256_finup,
	.descsize	=	sizeof(struct wp512_ctx),
	.base		=	{
		.cra_name	 =	"wp256",
		.cra_driver_name =	"wp256-generic",
		.cra_flags	 =	CRYPTO_AHASH_ALG_BLOCK_ONLY,
		.cra_blocksize	 =	WP512_BLOCK_SIZE,
		.cra_module	 =	THIS_MODULE,
	}