* Failure in HMAC with Whirlpool hash in 6.16-rc2
@ 2025-06-19 21:18 Milan Broz
2025-06-20 4:19 ` Herbert Xu
2025-06-20 5:47 ` [PATCH] crypto: wp512 - Use API partial block handling Herbert Xu
0 siblings, 2 replies; 9+ messages in thread
From: Milan Broz @ 2025-06-19 21:18 UTC (permalink / raw)
To: Herbert Xu; +Cc: linux-crypto@vger.kernel.org
Hi Herbert,
another regression in kernel 6.16-rc2, this time in AF_ALF for Whirlpool hash.
Cryptsetup can use kernel userspace API instead of userspace crypto lib and we
have some testvectors to detect breakage of crypto.
It now fails with PBKDF with Whirlpool hash (HMAC).
You can reproduce it compiling cryptsetup with kernel API backend and run vector test:
./autogen.sh
./configure --with-crypto_backend=kernel
make check-programs
tests/vectors-test
...
PBKDF vector 17 pbkdf2-sha1 [OK]
PBKDF vector 18 pbkdf2-sha256 [OK]
PBKDF vector 19 pbkdf2-sha512 [OK]
PBKDF vector 20 pbkdf2-whirlpool [API FAILED]
PBKDF test failed.
The bisect points to
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date: Thu May 15 13:54:42 2025 +0800
crypto: hmac - Add export_core and import_core
Add export_import and import_core so that hmac can be used as a
fallback by block-only drivers.
Please let me know if you need more info.
Milan
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Failure in HMAC with Whirlpool hash in 6.16-rc2
2025-06-19 21:18 Failure in HMAC with Whirlpool hash in 6.16-rc2 Milan Broz
@ 2025-06-20 4:19 ` Herbert Xu
2025-06-20 5:47 ` [PATCH] crypto: wp512 - Use API partial block handling Herbert Xu
1 sibling, 0 replies; 9+ messages in thread
From: Herbert Xu @ 2025-06-20 4:19 UTC (permalink / raw)
To: Milan Broz; +Cc: linux-crypto@vger.kernel.org
On Thu, Jun 19, 2025 at 11:18:13PM +0200, Milan Broz wrote:
> Hi Herbert,
>
> another regression in kernel 6.16-rc2, this time in AF_ALF for Whirlpool hash.
>
> Cryptsetup can use kernel userspace API instead of userspace crypto lib and we
> have some testvectors to detect breakage of crypto.
>
> It now fails with PBKDF with Whirlpool hash (HMAC).
I grepped for hmac(wp512) and didn't find any hits so I assumed
that nobody used that.
I will convert wp512 to block-only so that it may be used with
hmac again.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH] crypto: wp512 - Use API partial block handling
2025-06-19 21:18 Failure in HMAC with Whirlpool hash in 6.16-rc2 Milan Broz
2025-06-20 4:19 ` Herbert Xu
@ 2025-06-20 5:47 ` Herbert Xu
2025-06-20 8:10 ` Milan Broz
1 sibling, 1 reply; 9+ messages in thread
From: Herbert Xu @ 2025-06-20 5:47 UTC (permalink / raw)
To: Milan Broz; +Cc: linux-crypto@vger.kernel.org
On Thu, Jun 19, 2025 at 11:18:13PM +0200, Milan Broz wrote:
>
> The bisect points to
>
> Author: Herbert Xu <herbert@gondor.apana.org.au>
> Date: Thu May 15 13:54:42 2025 +0800
>
> crypto: hmac - Add export_core and import_core
>
> Add export_import and import_core so that hmac can be used as a
> fallback by block-only drivers.
>
> Please let me know if you need more info.
Please try this patch:
---8<---
Use the Crypto API partial block handling.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/crypto/wp512.c b/crypto/wp512.c
index 41f13d490333..4aa9d2cbeab9 100644
--- a/crypto/wp512.c
+++ b/crypto/wp512.c
@@ -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;
}
@@ -1004,16 +999,11 @@ static int wp512_update(struct shash_desc *desc, const u8 *source,
unsigned int len)
{
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;
+ unsigned int remain = len % WP512_BLOCK_SIZE;
+ unsigned int bits_len = (len - remain) * 8;
+ 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--) {
@@ -1022,62 +1012,31 @@ static int wp512_update(struct shash_desc *desc, const u8 *source,
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;
- }
+ do {
+ wp512_process_buffer(wctx, source);
+ source += WP512_BLOCK_SIZE;
+ bits_len -= WP512_BLOCK_SIZE * 8;
+ } while (bits_len);
- wctx->bufferBits = bufferBits;
- wctx->bufferPos = bufferPos;
-
- return 0;
+ 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);
+ 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 +1045,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 +1081,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 +1094,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 +1107,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,
}
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] crypto: wp512 - Use API partial block handling
2025-06-20 5:47 ` [PATCH] crypto: wp512 - Use API partial block handling Herbert Xu
@ 2025-06-20 8:10 ` Milan Broz
2025-06-20 8:37 ` [v2 PATCH] " Herbert Xu
0 siblings, 1 reply; 9+ messages in thread
From: Milan Broz @ 2025-06-20 8:10 UTC (permalink / raw)
To: Herbert Xu; +Cc: linux-crypto@vger.kernel.org
On 6/20/25 7:47 AM, Herbert Xu wrote:
> On Thu, Jun 19, 2025 at 11:18:13PM +0200, Milan Broz wrote:
>>
>> The bisect points to
>>
>> Author: Herbert Xu <herbert@gondor.apana.org.au>
>> Date: Thu May 15 13:54:42 2025 +0800
>>
>> crypto: hmac - Add export_core and import_core
>>
>> Add export_import and import_core so that hmac can be used as a
>> fallback by block-only drivers.
>>
>> Please let me know if you need more info.
>
> Please try this patch:
>
> ---8<---
> Use the Crypto API partial block handling.
>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Hi,
Now I get wrong data instead of fail (both on 32bit and 64bit).
Patch just applied over today's Linus' tree
...
PBKDF vector 20 pbkdf2-whirlpool [FAILED]
got: 58 55 1e ef 29 40 d6 a2 f0 59 e0 d9 4a 50 c5 df 01 25 be ee 27 5b 35 47 6d 37 38 13 0f e0 da 29
want: 9c 1c 74 f5 88 26 e7 6a 53 58 f4 0c 39 e7 80 89 07 c0 31 19 9a 50 a2 48 f1 d9 fe 78 64 e5 84 50
PBKDF test failed.
(Whirlpool is translated to wp512 in the crypto backend and despite it is a quite rare use, some people
used if for LUKS PBKDF2. Actually the whole vector test was reaction to wrong Whirlpool implementation
in gcrypt years ago. It apparently can find breakage even today :-)
Milan
^ permalink raw reply [flat|nested] 9+ messages in thread
* [v2 PATCH] crypto: wp512 - Use API partial block handling
2025-06-20 8:10 ` Milan Broz
@ 2025-06-20 8:37 ` Herbert Xu
2025-06-20 8:52 ` Milan Broz
0 siblings, 1 reply; 9+ messages in thread
From: Herbert Xu @ 2025-06-20 8:37 UTC (permalink / raw)
To: Milan Broz; +Cc: linux-crypto@vger.kernel.org
On Fri, Jun 20, 2025 at 10:10:53AM +0200, Milan Broz wrote:
>
> Now I get wrong data instead of fail (both on 32bit and 64bit).
> Patch just applied over today's Linus' tree
>
> ...
> PBKDF vector 20 pbkdf2-whirlpool [FAILED]
> got: 58 55 1e ef 29 40 d6 a2 f0 59 e0 d9 4a 50 c5 df 01 25 be ee 27 5b 35 47 6d 37 38 13 0f e0 da 29
> want: 9c 1c 74 f5 88 26 e7 6a 53 58 f4 0c 39 e7 80 89 07 c0 31 19 9a 50 a2 48 f1 d9 fe 78 64 e5 84 50
> PBKDF test failed.
>
> (Whirlpool is translated to wp512 in the crypto backend and despite it is a quite rare use, some people
> used if for LUKS PBKDF2. Actually the whole vector test was reaction to wrong Whirlpool implementation
> in gcrypt years ago. It apparently can find breakage even today :-)
Oops, I forgot to increment the hash length for the final partial
update :)
---8<---
Use the Crypto API partial block handling.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/crypto/wp512.c b/crypto/wp512.c
index 41f13d490333..ee0f1357358d 100644
--- a/crypto/wp512.c
+++ b/crypto/wp512.c
@@ -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;
-
- return 0;
}
-static int wp512_final(struct shash_desc *desc, u8 *out)
+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;
+
+ 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_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,
}
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [v2 PATCH] crypto: wp512 - Use API partial block handling
2025-06-20 8:37 ` [v2 PATCH] " Herbert Xu
@ 2025-06-20 8:52 ` Milan Broz
2025-06-20 12:15 ` [v3 " Herbert Xu
0 siblings, 1 reply; 9+ messages in thread
From: Milan Broz @ 2025-06-20 8:52 UTC (permalink / raw)
To: Herbert Xu; +Cc: linux-crypto@vger.kernel.org
On 6/20/25 10:37 AM, Herbert Xu wrote:
> On Fri, Jun 20, 2025 at 10:10:53AM +0200, Milan Broz wrote:
>>
>> Now I get wrong data instead of fail (both on 32bit and 64bit).
>> Patch just applied over today's Linus' tree
>>
>> ...
>> PBKDF vector 20 pbkdf2-whirlpool [FAILED]
>> got: 58 55 1e ef 29 40 d6 a2 f0 59 e0 d9 4a 50 c5 df 01 25 be ee 27 5b 35 47 6d 37 38 13 0f e0 da 29
>> want: 9c 1c 74 f5 88 26 e7 6a 53 58 f4 0c 39 e7 80 89 07 c0 31 19 9a 50 a2 48 f1 d9 fe 78 64 e5 84 50
>> PBKDF test failed.
>>
>> (Whirlpool is translated to wp512 in the crypto backend and despite it is a quite rare use, some people
>> used if for LUKS PBKDF2. Actually the whole vector test was reaction to wrong Whirlpool implementation
>> in gcrypt years ago. It apparently can find breakage even today :-)
>
> Oops, I forgot to increment the hash length for the final partial
> update :)
It s still failing for me for that userspace crypt API.
Milan
^ permalink raw reply [flat|nested] 9+ messages in thread
* [v3 PATCH] crypto: wp512 - Use API partial block handling
2025-06-20 8:52 ` Milan Broz
@ 2025-06-20 12:15 ` Herbert Xu
2025-06-20 13:22 ` Milan Broz
0 siblings, 1 reply; 9+ messages in thread
From: Herbert Xu @ 2025-06-20 12:15 UTC (permalink / raw)
To: Milan Broz; +Cc: linux-crypto@vger.kernel.org
On Fri, Jun 20, 2025 at 10:52:49AM +0200, Milan Broz wrote:
>
> It s still failing for me for that userspace crypt API.
OK I screwed up the final marker. The old code always left a
zero byte in the buffer so the finalisation could simply or it
with 0x80. With the new code, we need to set it to 0x80 explicitly
instead of oring.
---8<---
Use the Crypto API partial block handling.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/crypto/wp512.c b/crypto/wp512.c
index 41f13d490333..229b189a7988 100644
--- a/crypto/wp512.c
+++ b/crypto/wp512.c
@@ -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;
-
- return 0;
}
-static int wp512_final(struct shash_desc *desc, u8 *out)
+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;
+
+ 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_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,
}
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [v3 PATCH] crypto: wp512 - Use API partial block handling
2025-06-20 12:15 ` [v3 " Herbert Xu
@ 2025-06-20 13:22 ` Milan Broz
2025-06-21 3:06 ` Herbert Xu
0 siblings, 1 reply; 9+ messages in thread
From: Milan Broz @ 2025-06-20 13:22 UTC (permalink / raw)
To: Herbert Xu; +Cc: linux-crypto@vger.kernel.org
On 6/20/25 2:15 PM, Herbert Xu wrote:
> On Fri, Jun 20, 2025 at 10:52:49AM +0200, Milan Broz wrote:
>>
>> It s still failing for me for that userspace crypt API.
>
> OK I screwed up the final marker. The old code always left a
> zero byte in the buffer so the finalisation could simply or it
> with 0x80. With the new code, we need to set it to 0x80 explicitly
> instead of oring.
>
> ---8<---
> Use the Crypto API partial block handling.
>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Yes, we have a winner ;-) It works now, thanks!
Tested-by: Milan Broz <gmazyland@gmail.com>
I guess this will go to the next crypto update pull request.
Thanks,
Milan
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [v3 PATCH] crypto: wp512 - Use API partial block handling
2025-06-20 13:22 ` Milan Broz
@ 2025-06-21 3:06 ` Herbert Xu
0 siblings, 0 replies; 9+ messages in thread
From: Herbert Xu @ 2025-06-21 3:06 UTC (permalink / raw)
To: Milan Broz; +Cc: linux-crypto@vger.kernel.org
On Fri, Jun 20, 2025 at 03:22:57PM +0200, Milan Broz wrote:
>
> I guess this will go to the next crypto update pull request.
Yes I will be pushing this for 6.16.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-06-21 3:06 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-19 21:18 Failure in HMAC with Whirlpool hash in 6.16-rc2 Milan Broz
2025-06-20 4:19 ` Herbert Xu
2025-06-20 5:47 ` [PATCH] crypto: wp512 - Use API partial block handling Herbert Xu
2025-06-20 8:10 ` Milan Broz
2025-06-20 8:37 ` [v2 PATCH] " Herbert Xu
2025-06-20 8:52 ` Milan Broz
2025-06-20 12:15 ` [v3 " Herbert Xu
2025-06-20 13:22 ` Milan Broz
2025-06-21 3:06 ` Herbert Xu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox