aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2014-11-18 15:28:23 -0500
committerPaul Selkirk <paul@psgd.org>2014-11-18 15:28:23 -0500
commit283dea2f82bdfac2aeb0d026bc86c9d57b131915 (patch)
tree0a30b1ed97aa16be03f6863386ff9c3b02431c74
parent4817dd0cffa365bd58fc45e51f89157c36e0691f (diff)
do proper SHA* padding
-rw-r--r--src/sw/hash.c117
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;
}
}