The driver program is at the bottom. ### sha256.h ```c #ifndef __SHA256_H__ #define __SHA256_H__ #include #include #define sha256_block_size_bytes (512 / 8) // Later look up how to do opaque structs typedef struct _sha256 { uint32_t H[8]; uint8_t buf[sha256_block_size_bytes]; size_t n_bytes_read; } sha256; // create and init sha256* sha256_create(); void sha256_destroy(sha256* sha); // data is a block of blocsize void sha256_update(sha256* sha, uint8_t* data, size_t len); void sha256_finalize(sha256* sha, uint8_t* data, size_t len); // digests uint8_t* sha256_digest(sha256* sha, uint8_t* buf); char* sha256_hexdigest(sha256* sha, char* buf); #endif ``` ### sha256.c ```c #include "sha256.h" #include "sha256_consts.h" #include #include #include #include static inline uint32_t rotr(uint32_t x, int n) { return ((x >> n) | (x << (32-n))); } sha256* sha256_create() { sha256* sha = (sha256*)malloc(sizeof(sha256)); if( sha ) { memcpy(&(sha->H),I,sizeof(I)); sha->n_bytes_read = 0; } else { fprintf(stderr,"Failed to allocate sha256\n"); } return sha; } void sha256_destroy(sha256* sha) { free(sha); } static void process_block(sha256* sha, uint8_t* buf) { uint32_t *H = sha->H; uint32_t w[64]; uint32_t *data_words_le = (uint32_t*)buf; size_t i; for(i=0; i<16; i++) { // this is for little endian machines w[i] = __builtin_bswap32(data_words_le[i]); // for big endian machines do // w[i] = data_words_le[i]; } for(i=16; i<64; i++) { uint32_t s0 = rotr( w[i-15], 7 ) ^ rotr( w[i-15], 18 ) ^ (w[i-15] >> 3); uint32_t s1 = rotr( w[i-2], 17 ) ^ rotr( w[i-2], 19 ) ^ (w[i-2] >> 10); w[i] = (w[i-16] + s0 + w[i-7] + s1); } uint32_t a = H[0], b = H[1], c = H[2], d = H[3]; uint32_t e = H[4], f = H[5], g = H[6], h = H[7]; for(i=0; i<64; i++) { uint32_t s1 = rotr(e,6) ^ rotr(e,11) ^ rotr(e,25); uint32_t ch = (e & f) ^ ((~e) & g); uint32_t t1 = (h + s1 + ch + K[i] + w[i]); uint32_t s0 = rotr(a,2) ^ rotr(a,13) ^ rotr(a,22); uint32_t maj = (a & b) ^ (b & c) ^ (a & c); uint32_t t2 = s0 + maj; h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; } H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; H[5] += f; H[6] += g; H[7] += h; } // update void sha256_update(sha256* sha, uint8_t* data, size_t len) { //printf("Update %lld\n",len); // copy bytes from data to sha->buf, then call process_block as needed. // we could, later, remove the redundant copy by having process_block // take a parameter, and pointing it to the data when it contains // complete blocks, and only using the buffer for extraneous bytes size_t curl = sha->n_bytes_read; size_t curoff = curl % sha256_block_size_bytes; // equal to number of bytes in buffer size_t currem = sha256_block_size_bytes - curoff; // number of bytes remaining in block size_t newl = curl + len; // length after data is added if( len > currem ) { memcpy(sha->buf + curoff, data, currem); data += currem; len -= currem; process_block(sha,sha->buf); } // now we are starting on a block boundary while(len >= sha256_block_size_bytes) { // memcpy(sha->buf, data, sha256_block_size_bytes); // strangely this is _slower_ without the memcpy // presumably since sha->buf is nicely aligned. process_block(sha,data); data += sha256_block_size_bytes; len -= sha256_block_size_bytes; } // now we have the remainder if( len > 0 ) { memcpy(sha->buf, data, len); } sha->n_bytes_read = newl; } // data is a block of blocsize void sha256_finalize(sha256* sha, uint8_t* data, size_t len) { //printf("Finalise %lld\n",len); sha256_update(sha,data,len); // add padding and process_block as required size_t curl = sha->n_bytes_read; size_t curoff = curl % sha256_block_size_bytes; // equal to number of bytes in buffer size_t currem = sha256_block_size_bytes - curoff; // number of bytes remaining in block uint64_t len_bswap = __builtin_bswap64(curl*8); // total number of bits as big endian 64bit integer //printf("curl %lld, curoff %lld, currem %lld\n",curl,curoff,currem); if( currem == 0 ) { //printf("Padding empty block\n"); // add empty block and process sha->buf[0] = 0x80; memset(sha->buf+1,0,sha256_block_size_bytes-9); memcpy(sha->buf+sha256_block_size_bytes-8,(uint8_t*)&len_bswap,sizeof(len_bswap)); process_block(sha,sha->buf); } else if( currem < 9 ) { //printf("Adding extra block\n"); // start padding, process block, finish padding, process block sha->buf[curoff] = 0x80; memset(sha->buf+curoff+1,0,sha256_block_size_bytes-curoff-1); process_block(sha,sha->buf); memset(sha->buf,0,sha256_block_size_bytes-8); memcpy(sha->buf+sha256_block_size_bytes-8,(uint8_t*)&len_bswap,sizeof(len_bswap)); process_block(sha,sha->buf); } else { //printf("Padding current block\n"); // add padding, process block sha->buf[curoff] = 0x80; memset(sha->buf+curoff+1,0,sha256_block_size_bytes-curoff-9); memcpy(sha->buf+sha256_block_size_bytes-8,(uint8_t*)&len_bswap,sizeof(len_bswap)); process_block(sha,sha->buf); } } uint8_t* sha256_digest(sha256* sha, uint8_t* buf) { size_t i; for( i=0; i<8; i++) { uint32_t x = __builtin_bswap32(sha->H[i]); memcpy(buf + 4*i,&x,sizeof(uint32_t)); } return buf; } char* sha256_hexdigest(sha256* sha, char* buf) { size_t i; for( i=0; i<8; i++ ) { snprintf(buf+8*i,9,"%08x",sha->H[i]); } return buf; } ``` ### sha256_consts.h ```c const uint32_t I[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; 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 }; ``` ### summer.c A simple implementation of [GNU](/aw/os/gnu) coreutils' `sha256sum`. ```c #include #include #include #include #include #include #include #include #include "sha256.h" // #define BUF_SIZE 4096 // funny size to test buffering #define BUF_SIZE 367 void sum_file(const char* filename); void sum_fd(int fd, const char* filename); void sum_file(const char* filename) { int fd; fd = open(filename,O_RDONLY); if( fd == -1 ) { fprintf(stderr, "[ERROR filename='%s' errno=%d -- %s]\n",filename,errno,strerror(errno)); return; } else { sum_fd(fd,filename); close(fd); } } void sum_fd(int fd, const char* filename) { sha256* sha = sha256_create(); ssize_t s; uint8_t buf[BUF_SIZE]; char hexbuf[65]; while( ( s = read(fd, buf, BUF_SIZE) ) ) { sha256_update(sha,buf,s); } sha256_finalize(sha,NULL,0); sha256_hexdigest(sha,hexbuf); sha256_destroy(sha); printf("%s *%s\n",hexbuf,filename); } int main(int argc, char* argv[]) { int i; if( argc == 1) { sum_fd(0,"-"); } else { for(i=1; i