Skip to content

Commit

Permalink
sha1sum.c, sha256.c: make code work with -fstrict-aliasing
Browse files Browse the repository at this point in the history
-fstrict-aliasing is enabled by default when using optimization levels
higher than 1, including -Os. With that option, compiler may assume
that object of one type never resides at the same address as object of
a different type. Both sha1_final() and sha256_final() used to write
message length by casting a pointer to buffer into a pointer to u64,
while surrounding code operated on the buffer directly.

The problem manifests in GCC 11 and later versions.

The commit fixes this issue and another UB caused by unaligned access
at the beginning of transformation step by using memcpy() in both cases.

Signed-off-by: Krystian Hebel <[email protected]>
Signed-off-by: Sergii Dmytruk <[email protected]>
  • Loading branch information
krystian-hebel committed Apr 17, 2024
1 parent 87833a0 commit c00c554
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 39 deletions.
57 changes: 29 additions & 28 deletions sha1sum.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,18 @@ static inline u32 rol( u32 x, int n)

typedef struct {
u32 count;
union {
struct {
u32 h0, h1, h2, h3, h4;
};
u32 h[5];
};
unsigned char buf[64];
u32 h[5];
u8 buf[64];
} SHA1_CONTEXT;

static void sha1_init( SHA1_CONTEXT *hd )
{
*hd = (SHA1_CONTEXT){
.h0 = 0x67452301,
.h1 = 0xefcdab89,
.h2 = 0x98badcfe,
.h3 = 0x10325476,
.h4 = 0xc3d2e1f0,
.h[0] = 0x67452301,
.h[1] = 0xefcdab89,
.h[2] = 0x98badcfe,
.h[3] = 0x10325476,
.h[4] = 0xc3d2e1f0,
};
}

Expand All @@ -70,20 +65,24 @@ static u32 sha1_blend(u32 *x, unsigned int i)
*/
static void sha1_transform(SHA1_CONTEXT *hd, const void *_data)
{
const u32 *data = _data;
const u8 *data = _data;
u32 a,b,c,d,e;
u32 x[16];
int i;

/* get values from the chaining vars */
a = hd->h0;
b = hd->h1;
c = hd->h2;
d = hd->h3;
e = hd->h4;
a = hd->h[0];
b = hd->h[1];
c = hd->h[2];
d = hd->h[3];
e = hd->h[4];

for ( i = 0; i < 16; ++i )
x[i] = cpu_to_be32(data[i]);
{
u32 tmp;
memcpy(&tmp, &data[i*sizeof(u32)], sizeof(u32));
x[i] = be32_to_cpu(tmp);
}


#define K1 0x5A827999L
Expand Down Expand Up @@ -147,11 +146,11 @@ static void sha1_transform(SHA1_CONTEXT *hd, const void *_data)
}

/* Update chaining vars */
hd->h0 += a;
hd->h1 += b;
hd->h2 += c;
hd->h3 += d;
hd->h4 += e;
hd->h[0] += a;
hd->h[1] += b;
hd->h[2] += c;
hd->h[3] += d;
hd->h[4] += e;
}


Expand All @@ -176,6 +175,7 @@ static void
sha1_final(SHA1_CONTEXT *hd, u8 hash[SHA1_DIGEST_SIZE])
{
unsigned int partial = hd->count & 0x3f;
u64 ml = cpu_to_be64((u64)hd->count << 3);

/* Start padding */
hd->buf[partial++] = 0x80;
Expand All @@ -191,13 +191,14 @@ sha1_final(SHA1_CONTEXT *hd, u8 hash[SHA1_DIGEST_SIZE])
memset(hd->buf + partial, 0, 56 - partial);

/* append the 64 bit count */
u64 *count = (void *)&hd->buf[56];
*count = cpu_to_be64((u64)hd->count << 3);
memcpy(hd->buf + 56, &ml, sizeof(ml));
sha1_transform(hd, hd->buf);

u32 *p = (void *)hash;
for ( int i = 0; i < 5; ++i )
p[i] = be32_to_cpu(hd->h[i]);
{
u32 be = cpu_to_be32(hd->h[i]);
memcpy(&hash[i*sizeof(u32)], &be, sizeof(u32));
}
}

void sha1sum(u8 hash[static SHA1_DIGEST_SIZE], const void *ptr, u32 len)
Expand Down
26 changes: 15 additions & 11 deletions sha256.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@
#include <sha256.h>
#include <string.h>

#define SHA256_BLOCK_SIZE 64

struct sha256_state {
u32 state[SHA256_DIGEST_SIZE / 4];
u32 count;
u8 buf[SHA256_BLOCK_SIZE];
u8 buf[64];
};

static inline u32 ror32(u32 word, unsigned int shift)
Expand Down Expand Up @@ -78,14 +76,18 @@ static const u32 K[] = {

static void sha256_transform(u32 *state, const void *_input)
{
const u32 *input = _input;
const u8 *input = _input;
u32 a, b, c, d, e, f, g, h, t1, t2;
u32 W[16];
int i;

/* load the input */
for ( i = 0; i < 16; i++ )
W[i] = be32_to_cpu(input[i]);
{
u32 tmp;
memcpy(&tmp, &input[i*sizeof(u32)], sizeof(u32));
W[i] = be32_to_cpu(tmp);
}

/* load the state into our registers */
a = state[0]; b = state[1]; c = state[2]; d = state[3];
Expand Down Expand Up @@ -163,31 +165,33 @@ static void sha256_once(struct sha256_state *sctx, const void *data, u32 len)

static void sha256_final(struct sha256_state *sctx, void *_dst)
{
u32 *dst = _dst;
u64 *count;
u8 *dst = _dst;
unsigned int i, partial = sctx->count & 0x3f;
u64 ml = cpu_to_be64((u64)sctx->count << 3);

/* Start padding */
sctx->buf[partial++] = 0x80;

if ( partial > 56 )
{
/* Need one extra block - pad to 64 */
memset(sctx->buf + partial, 0, 64 - partial);
memset(sctx->buf + partial, 0, sizeof(sctx->buf) - partial);
sha256_transform(sctx->state, sctx->buf);
partial = 0;
}
/* Pad to 56 */
memset(sctx->buf + partial, 0, 56 - partial);

/* Append the 64 bit count */
count = (void *)&sctx->buf[56];
*count = cpu_to_be64((u64)sctx->count << 3);
memcpy(sctx->buf + 56, &ml, sizeof(ml));
sha256_transform(sctx->state, sctx->buf);

/* Store state in digest */
for ( i = 0; i < 8; i++ )
dst[i] = cpu_to_be32(sctx->state[i]);
{
u32 be = cpu_to_be32(sctx->state[i]);
memcpy(&dst[i*sizeof(u32)], &be, sizeof(u32));
}
}

void sha256sum(u8 hash[static SHA256_DIGEST_SIZE], const void *data, u32 len)
Expand Down

0 comments on commit c00c554

Please sign in to comment.