Skip to content

Instantly share code, notes, and snippets.

@RealTrisT
Created May 3, 2018 02:50
Show Gist options
  • Save RealTrisT/f09dfb86948c7c9b0726261999d29eba to your computer and use it in GitHub Desktop.
Save RealTrisT/f09dfb86948c7c9b0726261999d29eba to your computer and use it in GitHub Desktop.
just a shitty implementation of sha256
#ifndef H_SHA256
#define H_SHA256
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned int uint;
typedef unsigned long long uint64;
#define h_A 0
#define h_B 1
#define h_C 2
#define h_D 3
#define h_E 4
#define h_F 5
#define h_G 6
#define h_H 7
const uint h_Constants[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
const uint h_Ks[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
};
#define align_512bit(x) (x & (~63))
#define ROTLEFT (a,b) (((a) << (b)) | ((a) >> (32-(b))))
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define SIG0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) //uppercase sigma
#define SIG1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) //uppercase sigma
#define sig0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) //lowercase sigma
#define sig1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) //lowercase sigma
uint64 LittleEndian_ByteSwap_64(uint64 x){
#ifdef __GNUC__ //if it's gcc
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ //and compiling for lil endy
return __builtin_bswap64(x); //do dis
#endif
#else //Just assume it's windows, sorry, but not gonna compiler-macro-hunt
return _byteswap_uint64(x); //windows is always little endian
#endif
return x; //if it's none of the above it's most likely big endian
}
uint LittleEndian_ByteSwap_32(uint x){
#ifdef __GNUC__ //if it's gcc
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ //and compiling for lil endy
return __builtin_bswap32(x); //do dis
#endif
#else //Just assume it's windows, sorry, but not gonna compiler-macro-hunt
return _byteswap_uint32(x); //windows is always little endian
#endif
return x; //if it's none of the above it's most likely big endian
}
#define lebs32 LittleEndian_ByteSwap_32 //just a shorter name
//len - length of the message in bytes
//return - cubo de gelo aka ice cube
uint64 h_CalcPadSize(uint64 len){
uint64 CalculatedSize = 8 + 1 + len;//64-bit integer + end bit byte + message
if(CalculatedSize&63) //if it's not already aligned to 512-bits
CalculatedSize = align_512bit(CalculatedSize+64); //align it to the next smallest possible block that'll fit it
return CalculatedSize;
}
//buffer - pointer to a zero-filled buffer that'll contain the padded message
//buffersize - size of said buffer in bytes
//to_hash - thing that needs hashing
//len - length, in bytes, of thing that needs hashing
//return - how many 512-bit blocks there are in the message
uint h_Pad(unsigned char* buffer, uint64 buffersize, unsigned char* to_hash, uint64 len){
memcpy(buffer, to_hash, len);
buffer[len] = 0x80; //put that last bit in the end (h 80 = b 1000 0000)
//put the total length in bits in the end of all that --> HAS TO BE BIG ENDIAN <--
*(uint64*)(buffer + buffersize - sizeof(uint64)) = LittleEndian_ByteSwap_64((uint64)(len*8));
return buffersize/64;
}
//buffer - 64 32-bit words (256 bytes = 2048 bits)
//paddedMessage - exactly that
//index - index of the 512-bit block to get the first 16 32-bit words from
//return - pointer to buffer, for utility purposes
//512 bits = 64 bytes
unsigned char* h_MessageSchedule(unsigned char* buffer, unsigned char* paddedMessage, uint index){
uint* w32 = (uint*)buffer;
memcpy(buffer, paddedMessage + index*64, 64);
//first convert message to little endian
//we do this, because in a little endian machine, reading an int from memory is done "upside down"
//so basically 0x11223344 in memory will become 0x44332211 when read and interpreted as an "int"
//because of this, we'll save *everything* as little endian, so when the system reads it, it
//becomes it's big endian variant, basically doing the convertion for us
for (int i = 0; i < 16; ++i) w32[i] = lebs32(w32[i]);
//now let's do the math
for (int i = 16; i < 64; ++i){
w32[i] = w32[i - 16] + sig0(w32[i - 15]) + w32[i - 7] + sig1(w32[i - 2]);
}
//we'll keep it all as little endian, cuz it'll be useful for the HashSchedule
//function, so we don't have to keep changing endiannesses
return buffer;
}
//hashval - 8x 32bit words array to sum the output to
//MessageSchedule - pointer to exactly that, the 256 byte buffer (64 32-bit words)
void h_HashSchedule(uint* hashval, unsigned char* MessageSchedule){
uint* MS32 = (uint*)MessageSchedule;
uint a, b, c, d, e, f, g, h, t1, t2;
a = hashval[h_A]; b = hashval[h_B]; c = hashval[h_C]; d = hashval[h_D];
e = hashval[h_E]; f = hashval[h_F]; g = hashval[h_G]; h = hashval[h_H];
for (int i = 0; i < 64; ++i){
t1 = h + SIG1(e) + CH(e, f, g) + h_Ks[i] + MS32[i];
t2 = SIG0(a) + MAJ(a, b, c);
h = g; g = f; f = e;
e = d + t1;
d = c; c = b; b = a;
a = t1 + t2;
}
hashval[h_A] += a; hashval[h_B] += b; hashval[h_C] += c; hashval[h_D] += d;
hashval[h_E] += e; hashval[h_F] += f; hashval[h_G] += g; hashval[h_H] += h;
}
//buffer - digest buffer, output
//message and messagelen - pretty fucking self-explanatory
void h_sha256(unsigned char* buffer, unsigned char* Message, uint64 MessageLen){
uint blocks = 0;
uint64 paddedMessageSize = 0;
unsigned char* paddedMessage = 0;
unsigned char* tempSchedule = 0;
memcpy(buffer, h_Constants, 8*sizeof(uint)); //start the digest buffer as the constants
paddedMessageSize = h_CalcPadSize(MessageLen);
paddedMessage = (unsigned char*)calloc(paddedMessageSize, 1);
blocks = h_Pad(paddedMessage, paddedMessageSize, Message, MessageLen);
tempSchedule = malloc(256);
for (int i = 0; i < blocks; ++i){
h_MessageSchedule(tempSchedule, paddedMessage, i);
h_HashSchedule((uint*)buffer, tempSchedule);
}
free(tempSchedule);
free(paddedMessage);
//the numbers in the digest (the eight 32-bit words) will be little endian, change that
for (int i = 0; i < 8; ++i)((uint*)buffer)[i] = lebs32(((uint*)buffer)[i]);
return; //REEEEEEEEEEEEEEEEEEEEEEEEEEEEEEturn like a big boi
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment