diff options
Diffstat (limited to 'src/sw')
-rw-r--r-- | src/sw/hash.c | 117 |
1 files changed, 72 insertions, 45 deletions
diff --git a/src/sw/hash.c b/src/sw/hash.c index 2314fe4..f9bb3b8 100644 --- a/src/sw/hash.c +++ b/src/sw/hash.c @@ -47,6 +47,7 @@ #include <sys/ioctl.h> #include <arpa/inet.h> #include <ctype.h> +#include <assert.h> char *usage = "Usage: %s [-d] [-v] [-q] [-i I2C_device] [-a I2C_addr] [algorithm [file]]\n" @@ -58,24 +59,24 @@ char *usage = int debug = 0; int verbose = 0; -/* block and digest lengths are number of 32-bit words */ -#define SHA1_BLOCK_LEN 16 -#define SHA1_DIGEST_LEN 5 -#define SHA256_BLOCK_LEN 16 -#define SHA256_DIGEST_LEN 8 -#define SHA512_BLOCK_LEN 32 -#define SHA512_224_DIGEST_LEN 7 -#define SHA512_256_DIGEST_LEN 8 -#define SHA384_DIGEST_LEN 12 -#define SHA512_DIGEST_LEN 16 +/* block and digest lengths are number of bytes */ +#define SHA1_BLOCK_LEN 512/8 +#define SHA1_DIGEST_LEN 160/8 +#define SHA256_BLOCK_LEN 512/8 +#define SHA256_DIGEST_LEN 256/8 +#define SHA512_BLOCK_LEN 1024/8 +#define SHA512_224_DIGEST_LEN 224/8 +#define SHA512_256_DIGEST_LEN 256/8 +#define SHA384_DIGEST_LEN 384/8 +#define SHA512_DIGEST_LEN 512/8 /* ---------------- algorithm lookup code ---------------- */ struct ctrl { char *name; - int i2c_addr; - int block_len; - int digest_len; + uint8_t i2c_addr; + uint8_t block_len; + uint8_t digest_len; } ctrl[] = { { "sha-1", 0x1e, SHA1_BLOCK_LEN, SHA1_DIGEST_LEN }, { "sha-256", 0x1f, SHA256_BLOCK_LEN, SHA256_DIGEST_LEN }, @@ -95,7 +96,7 @@ struct ctrl *find_algo(char *algo) if (strcmp(ctrl[i].name, algo) == 0) return &ctrl[i]; - fprintf(stderr, "algorithm \"%s\" not found\n", algo); + fprintf(stderr, "algorithm \"%s\" not found\n\n", algo); fprintf(stderr, usage, "hash"); return NULL; } @@ -131,10 +132,50 @@ void i2c_close(int ifd) /* ---------------- hash ---------------- */ +int transmit(uint8_t *block, uint8_t blen, int fd) +{ + int i; + + if (debug) { + printf("write ["); + for (i = 0; i < blen; ++i) + printf(" %02x", block[i]); + printf(" ]\n"); + } + + if (write(fd, block, blen) != blen) { + return 1; + } + + return 0; +} + +int pad_transmit(uint8_t *block, uint8_t flen, uint8_t blen, int fd, long long tlen) +{ + assert(flen < blen); + + block[flen++] = 0x80; + memset(block + flen, 0, blen - flen); + + if (blen - flen < ((blen == 64) ? 8 : 16)) { + if (transmit(block, blen, fd) != 0) + return 1; + memset(block, 0, blen); + } + + /* properly the length is 128 bits for sha-512, but we can't + * actually count above 64 bits + */ + ((uint32_t *)block)[blen/4 - 2] = htonl((tlen >> 32) & 0xffff); + ((uint32_t *)block)[blen/4 - 1] = htonl(tlen & 0xffff); + + return transmit(block, blen, fd); +} + /* return number of digest bytes read */ int hash(char *dev, char *algo, char *file, uint8_t *digest) { - uint8_t block[SHA512_BLOCK_LEN * 4]; + uint8_t block[SHA512_BLOCK_LEN]; struct ctrl *ctrl; int i2c_fd, in_fd = 0; int addr, blen, dlen; @@ -142,16 +183,12 @@ int hash(char *dev, char *algo, char *file, uint8_t *digest) int i, ret = -1; struct timeval start, stop, difftime; - if (debug) printf("hash(dev=%s, algo=%s, file=%s, digest=%p)\n", dev, algo, file, digest); - ctrl = find_algo(algo); if (ctrl == NULL) return -1; addr = ctrl->i2c_addr; - blen = ctrl->block_len * 4; - dlen = ctrl->digest_len * 4; - - if (debug) printf("algorithm %s, device addr %02x\n", ctrl->name, ctrl->i2c_addr); + blen = ctrl->block_len; + dlen = ctrl->digest_len; i2c_fd = i2c_open(dev, addr); if (i2c_fd < 0) @@ -174,32 +211,22 @@ int hash(char *dev, char *algo, char *file, uint8_t *digest) for (nblk = 0; ; ++nblk) { nread = read(in_fd, block, blen); - if (nread != blen) { - if (nread < 0) { - /* read error */ - perror("read"); - goto out; - } - else if (nread == 0) { - /* EOF */ - break; - } - else { - /* partial read - pad the block with 0 */ - while (nread < blen) { - block[nread++] = 0; - } - } + if (nread < 0) { + /* read error */ + perror("read"); + goto out; } - if (debug) { - printf("write ["); - for (i = 0; i < blen; ++i) - printf(" %02x", block[i]); - printf(" ]\n"); + else if (nread < blen) { + /* partial read = last block */ + if (pad_transmit(block, nread, blen, i2c_fd, + (nblk * blen + nread) * 8) != 0) + goto out; + break; } - if (write(i2c_fd, block, blen) != blen) { - perror("i2c write failed"); - goto out; + else { + /* full block read */ + if (transmit(block, blen, i2c_fd) != 0) + goto out; } } |