mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-10-05 16:46:35 -05:00
Crypto: fix portable C code on big-endian CPUs (#1899)
* Crypto: fix portable C code on big-endian CPUs On big-endian CPUs (e.g. MIPS and PowerPC) the portable C code of several algorithms assumes a little-endian host, so ciphertext, hashes and derived keys are wrong and "veracrypt --text --test" fails: - Twofish: the key-dependent S-box bytes are read back from 32-bit words through a union, and blocks are loaded/stored as native words. - Camellia: blocks and keys are always byte-swapped to big-endian. - Kuznyechik: keys and blocks are loaded/stored as native 64-bit words while the tables expect the little-endian interpretation. - SHA-256/SHA-512: message words, length and digest are always byte-swapped. - BLAKE2s: the parameter block and message words are read as native little-endian data. The parameter block is now built from its fields, so it is right for any parameters, not only the ones VeraCrypt uses. - Streebog: the existing big-endian code path is never enabled, and BSWAP64 used by it is not defined (its buffer512 initializer also has one pair of braces too many). Its add512() also differs from the little-endian one, which drops a carry on purpose (existing volumes depend on it); do the same limb arithmetic on big-endian. - misc.h: the rotate-based bswap_32 (non-Linux, non-Apple, non-MSVC builds) lacks outer parentheses, so "bswap_32(a) ^ b" is parsed wrongly, and the fallback bswap_64 does not parenthesise its argument. - PBKDF2: the block number is always byte-swapped. Swap only where the host byte order differs from the data, and enable the Streebog big-endian path. On big-endian hosts the message words, keys and blocks of SHA-2, BLAKE2s, Twofish and Kuznyechik are read and written byte-wise (new VcLoad*/VcStore* inline helpers in misc.h), so these paths also work on misaligned buffers on strict-alignment CPUs. On little-endian CPUs the code is unchanged: the object files of all touched sources are byte-identical before and after this change (checked on x86_64, aarch64 and mipsel). With it, all self-tests pass on mips (big-endian) under qemu. Signed-off-by: Ville Takio <ville+git@takio.fi> * Volume: avoid unaligned 64-bit header and test vector accesses The volume header (de)serialisation and TestXtsAES read and write 64-bit fields through casted pointers into byte buffers at offsets that are only 4-byte aligned (e.g. the header field at offset 12). CPUs that trap on misaligned access without kernel fix-up (SPARC, MIPS64 on some systems, qemu-user) then fail with SIGBUS in "veracrypt --test" and when creating or opening any volume. Use memcpy instead, and have DeserializeEntryAt check that the whole entry, not only its start, lies inside the header. The XTS code also accesses its local byte arrays (whitening values, data unit number) through uint64 pointers; declare them 8-byte aligned instead of relying on the compiler's stack layout. Signed-off-by: Ville Takio <ville+git@takio.fi> * Volume: test multi-block PBKDF2 output and the Streebog carry case The PBKDF2 self-tests only check the first 4 bytes of each derivation, so the block counter of the second and later output blocks is never checked. Also compare the complete output of a 192-byte derivation for every PRF, which covers the later blocks and how they are joined, and hash a message whose block sum hits the carry case of Streebog's add512(), which has to stay bit-compatible across CPUs. The message buffer is 8-byte aligned, as the portable Streebog code reads it as 64-bit words. The expected values are those of the existing little-endian code, and match independent implementations for all five PRFs (Python hashlib/hmac, OpenSSL for Whirlpool, gostcrypto for Streebog). Signed-off-by: Ville Takio <ville+git@takio.fi> --------- Signed-off-by: Ville Takio <ville+git@takio.fi>
This commit is contained in:
1 parent
ce72be65bb
commit
425cea6c9c
11 files changed
+353
-72
No files matched your search
+13
-5
@@ -22,6 +22,14 @@
|
||||
#include "Whirlpool.h"
|
||||
#include "cpu.h"
|
||||
#include "misc.h"
|
||||
#include "Endian.h"
|
||||
|
||||
/* PBKDF2 block numbers are big-endian: swap only on little-endian hosts. */
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define PKCS5_BE32(x) (x)
|
||||
#else
|
||||
#define PKCS5_BE32(x) (bswap_32(x))
|
||||
#endif
|
||||
#else
|
||||
#pragma optimize ("t", on)
|
||||
#include <string.h>
|
||||
@@ -180,7 +188,7 @@ static void derive_u_sha256 (const unsigned char *salt, int salt_len, uint32 ite
|
||||
memset (&k[salt_len], 0, 3);
|
||||
k[salt_len + 3] = (unsigned char) b;
|
||||
#else
|
||||
b = bswap_32 (b);
|
||||
b = PKCS5_BE32 (b);
|
||||
memcpy (&k[salt_len], &b, 4);
|
||||
#endif
|
||||
|
||||
@@ -433,7 +441,7 @@ static void derive_u_sha512 (const unsigned char *salt, int salt_len, uint32 ite
|
||||
/* iteration 1 */
|
||||
memcpy (k, salt, salt_len); /* salt */
|
||||
/* big-endian block number */
|
||||
b = bswap_32 (b);
|
||||
b = PKCS5_BE32 (b);
|
||||
memcpy (&k[salt_len], &b, 4);
|
||||
|
||||
hmac_sha512_internal (k, salt_len + 4, hmac);
|
||||
@@ -681,7 +689,7 @@ static void derive_u_blake2s (const unsigned char *salt, int salt_len, uint32 it
|
||||
memset (&k[salt_len], 0, 3);
|
||||
k[salt_len + 3] = (unsigned char) b;
|
||||
#else
|
||||
b = bswap_32 (b);
|
||||
b = PKCS5_BE32 (b);
|
||||
memcpy (&k[salt_len], &b, 4);
|
||||
#endif
|
||||
|
||||
@@ -911,7 +919,7 @@ static void derive_u_whirlpool (const unsigned char *salt, int salt_len, uint32
|
||||
/* iteration 1 */
|
||||
memcpy (k, salt, salt_len); /* salt */
|
||||
/* big-endian block number */
|
||||
b = bswap_32 (b);
|
||||
b = PKCS5_BE32 (b);
|
||||
memcpy (&k[salt_len], &b, 4);
|
||||
|
||||
hmac_whirlpool_internal (k, salt_len + 4, hmac);
|
||||
@@ -1114,7 +1122,7 @@ static void derive_u_streebog (const unsigned char *salt, int salt_len, uint32 i
|
||||
/* iteration 1 */
|
||||
memcpy (k, salt, salt_len); /* salt */
|
||||
/* big-endian block number */
|
||||
b = bswap_32 (b);
|
||||
b = PKCS5_BE32 (b);
|
||||
memcpy (&k[salt_len], &b, 4);
|
||||
|
||||
hmac_streebog_internal (k, salt_len + 4, hmac);
|
||||
|
||||
Reference in new issue
Block a user