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;

}