Skip to content

Instantly share code, notes, and snippets.

@dpogorzelski
Last active December 16, 2020 00:22
Show Gist options
  • Save dpogorzelski/fb28b6ac7d92a7c667af to your computer and use it in GitHub Desktop.
Save dpogorzelski/fb28b6ac7d92a7c667af to your computer and use it in GitHub Desktop.
sha256
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#define TYP_INIT 0
#define TYP_SMLE 1
#define TYP_BIGE 2
static uint32_t hash[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
static uint32_t w[64] = { 0 };
static const uint32_t k[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6,
0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3,
0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138,
0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e,
0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814,
0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
uint8_t buffer[64] = { 0 };
static const uint8_t pad = 0x80;
void sha256();
uint64_t swap_uint64(uint64_t src);
int main(int argc, char** argv)
{
size_t ceof;
uint64_t count = 0;
uint32_t i;
while ((ceof = fread(buffer, 1, 64, stdin)) > 0) {
count += ceof * 8;
if (ceof < 56) {
count = swap_uint64(count);
memcpy(buffer + ceof, &pad, 1);
memcpy(buffer + 56, &count, 8);
sha256();
} else if (ceof <= 63) {
count = swap_uint64(count);
memcpy(buffer + ceof, &pad, 1);
sha256();
memset(buffer, 0, 64);
memcpy(buffer + 56, &count, 8);
sha256();
} else {
sha256();
memset(buffer, 0, 64);
}
}
for (i = 0; i < 8; i++)
printf("%08x", hash[i]);
printf("\n");
return 0;
}
void sha256()
{
static uint32_t ch, maj, s0, s1, S0, S1, t1, t2;
static uint32_t a, b, c, d, e, f, g, h;
uint8_t i;
a = hash[0];
b = hash[1];
c = hash[2];
d = hash[3];
e = hash[4];
f = hash[5];
g = hash[6];
h = hash[7];
for (i = 0; i < 16; i++) {
memcpy(w + i, buffer + i * 4, 4);
w[i] = htonl(w[i]);
}
for (i = 16; i <= 63; i++) {
s0 = ((w[i - 15] >> 7) | (w[i - 15] << (32 - 7)))
^ ((w[i - 15] >> 18) | (w[i - 15] << (32 - 18)))
^ (w[i - 15] >> 3);
s1 = ((w[i - 2] >> 17) | (w[i - 2] << (32 - 17)))
^ ((w[i - 2] >> 19) | (w[i - 2] << (32 - 19)))
^ (w[i - 2] >> 10);
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
}
for (i = 0; i <= 63; i++) {
ch = (e & f) ^ (~e & g);
maj = (a & b) ^ (a & c) ^ (c & b);
S0 = ((a >> 2) | (a << (32 - 2)))
^ ((a >> 13) | (a << (32 - 13)))
^ ((a >> 22) | (a << (32 - 22)));
S1 = ((e >> 6) | (e << (32 - 6)))
^ ((e >> 11) | (e << (32 - 11)))
^ ((e >> 25) | (e << (32 - 25)));
t1 = h + S1 + ch + k[i] + w[i];
t2 = S0 + maj;
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
hash[0] += a;
hash[1] += b;
hash[2] += c;
hash[3] += d;
hash[4] += e;
hash[5] += f;
hash[6] += g;
hash[7] += h;
}
uint64_t swap_uint64(uint64_t src)
{
static int typ = TYP_INIT;
unsigned char c;
union {
unsigned long long ull;
unsigned char c[8];
} x;
if (typ == TYP_INIT) {
x.ull = 0x01;
typ = (x.c[7] == 0x01ULL) ? TYP_BIGE : TYP_SMLE;
}
if (typ == TYP_BIGE)
return src;
x.ull = src;
c = x.c[0];
x.c[0] = x.c[7];
x.c[7] = c;
c = x.c[1];
x.c[1] = x.c[6];
x.c[6] = c;
c = x.c[2];
x.c[2] = x.c[5];
x.c[5] = c;
c = x.c[3];
x.c[3] = x.c[4];
x.c[4] = c;
return x.ull;
}
@jac18281828
Copy link

Although it compiles on gcc, the output does not match openssl dgst -sha256

@dpogorzelski
Copy link
Author

dpogorzelski commented Dec 15, 2020

hey @jac18281828, just did a quick test with random data:

~ ❯ echo "asdfdsf" | ./a.out                                                                                                                                              
c3474612eaed297c0a8b7bcc09e89f0f7beb05dd9ead5b3ff03940fb7c43f900
~ ❯ echo "asdfdsf" | openssl dgst -sha256
c3474612eaed297c0a8b7bcc09e89f0f7beb05dd9ead5b3ff03940fb7c43f900

would you be able to provide a sample input that didn't match?

edit:
testing on random binary files also seems to match:

~ ❯ cat Downloads/terraform | ./a.out
922b234c6c013183cf350ecd7fc3d840f3c9b28d6ec60c9c636fe2159bfa3638
~ ❯ cat Downloads/terraform | openssl dgst -sha256
922b234c6c013183cf350ecd7fc3d840f3c9b28d6ec60c9c636fe2159bfa3638

@jac18281828
Copy link

It appears to have to do with binary data. In my initial test I used the generated binary itself.

Here is a Dockerfile for gcc on Debian 10. The same issue occurred on my Mac running Big Sur and clang 11.

https://gist.github.com/jac18281828/eaf5fd59f649178bdafa932a7ed639d1

@jac18281828
Copy link

I see that it works if you remove the optimization '-O2'. You have some unsafe code that fails with safe optimizations turned on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment