crypto/crypto/ SHA256InC
The driver program is at the bottom.
sha256.h
#ifndef __SHA256_H__
#define __SHA256_H__
#include <stddef.h>
#include <stdint.h>
#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
#include "sha256.h"
#include "sha256_consts.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
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
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 coreutils' sha256sum
.
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#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<argc; i++) {
if( strcmp("-",argv[i]) == 0) {
sum_fd(0,"-");
} else {
sum_file(argv[i]);
}
}
}
return 0;
}