Created
May 3, 2018 02:50
-
-
Save RealTrisT/f09dfb86948c7c9b0726261999d29eba to your computer and use it in GitHub Desktop.
just a shitty implementation of sha256
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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