[Cryptech-Commits] [staging/core/platform/novena] 03/08: Add a generic file hashing utility, and some test files.

git at cryptech.is git at cryptech.is
Tue Mar 17 13:17:41 UTC 2015


This is an automated email from the git hooks/post-receive script.

paul at psgd.org pushed a commit to branch master
in repository staging/core/platform/novena.

commit b2bba47aff69e773d1f82707e7be9596a74fe5e2
Author: Paul Selkirk <paul at psgd.org>
Date:   Thu Sep 25 22:14:35 2014 -0400

    Add a generic file hashing utility, and some test files.
---
 src/sw/00-index.txt         |  12 +
 src/sw/1000_block.bin       | Bin 0 -> 64000 bytes
 src/sw/hash.c               | 586 ++++++++++++++++++++++++++++++++++++++++++++
 src/sw/nist_1024_double.bin | Bin 0 -> 256 bytes
 src/sw/nist_1024_single.bin | Bin 0 -> 128 bytes
 src/sw/nist_512_double.bin  | Bin 0 -> 128 bytes
 src/sw/nist_512_single.bin  | Bin 0 -> 64 bytes
 7 files changed, 598 insertions(+)

diff --git a/src/sw/00-index.txt b/src/sw/00-index.txt
new file mode 100644
index 0000000..c704834
--- /dev/null
+++ b/src/sw/00-index.txt
@@ -0,0 +1,12 @@
+configure.sh - Configure a bitstream file onto the FPGA
+
+hash_tester.c - Test the hash cores
+hash_tester.py - Same thing, only in Python
+
+hash.c - Hash an arbitrary file
+
+nist_512_single.bin - One-block test file for SHA-1 and SHA-256
+nist_512_double.bin - Two-block test file for SHA-1 and SHA-256
+nist_1024_single.bin - One-block test file for SHA-512
+nist_1024_double.bin - Two-block test file for SHA-512
+1000_block.bin - A large file for speed testing
diff --git a/src/sw/1000_block.bin b/src/sw/1000_block.bin
new file mode 100644
index 0000000..7e2b02b
Binary files /dev/null and b/src/sw/1000_block.bin differ
diff --git a/src/sw/hash.c b/src/sw/hash.c
new file mode 100644
index 0000000..f67a863
--- /dev/null
+++ b/src/sw/hash.c
@@ -0,0 +1,586 @@
+/* 
+ * hash.c
+ * ------
+ * This program uses the coretest_hashes subsystem to produce a
+ * cryptographic hash of a file or input stream. It is a generalization
+ * of the hash_tester.c test program.
+ * 
+ * Authors: Joachim Strömbergson, Paul Selkirk
+ * Copyright (c) 2014, SUNET
+ * 
+ * Redistribution and use in source and binary forms, with or 
+ * without modification, are permitted provided that the following 
+ * conditions are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in 
+ *    the documentation and/or other materials provided with the 
+ *    distribution. 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <linux/i2c-dev.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+char *usage = 
+"Usage: %s [-d] [-v] [-q] [-i I2C_device] [-a I2C_addr] [algorithm [file]]\n"
+"algorithms: sha-1, sha-256, sha-512/224, sha-512/256, sha-384, sha-512\n";
+
+/* I2C configuration */
+#define I2C_dev  "/dev/i2c-2"
+#define I2C_addr 0x0f
+
+/* command codes */
+#define SOC       0x55
+#define EOC       0xaa
+#define READ_CMD  0x10
+#define WRITE_CMD 0x11
+#define RESET_CMD 0x01
+
+/* response codes */
+#define SOR       0xaa
+#define EOR       0x55
+#define READ_OK   0x7f
+#define WRITE_OK  0x7e
+#define RESET_OK  0x7d
+#define UNKNOWN   0xfe
+#define ERROR     0xfd
+
+/* addresses and codes common to all hash cores */
+#define ADDR_NAME0              0x00
+#define ADDR_NAME1              0x01
+#define ADDR_VERSION            0x02
+#define ADDR_CTRL               0x08
+#define CTRL_INIT_CMD           1
+#define CTRL_NEXT_CMD           2
+#define ADDR_STATUS             0x09
+#define STATUS_READY_BIT        0
+#define STATUS_VALID_BIT        1
+
+/* addresses and codes for the specific hash cores */
+/* block and digest lengths are number of 32-bit words */
+#define SHA1_ADDR_PREFIX        0x10
+#define SHA1_ADDR_BLOCK         0x10
+#define SHA1_BLOCK_LEN          16
+#define SHA1_ADDR_DIGEST        0x20
+#define SHA1_DIGEST_LEN         5
+
+#define SHA256_ADDR_PREFIX      0x20
+#define SHA256_ADDR_BLOCK       0x10
+#define SHA256_BLOCK_LEN        16
+#define SHA256_ADDR_DIGEST      0x20
+#define SHA256_DIGEST_LEN       8
+
+#define SHA512_ADDR_PREFIX      0x30
+#define SHA512_CTRL_MODE_LOW    2
+#define SHA512_CTRL_MODE_HIGH   3
+#define SHA512_ADDR_BLOCK       0x10
+#define SHA512_BLOCK_LEN        32
+#define SHA512_ADDR_DIGEST      0x40
+#define SHA512_DIGEST_LEN       16
+#define MODE_SHA_512_224        0
+#define MODE_SHA_512_256        1
+#define MODE_SHA_384            2
+#define MODE_SHA_512            3
+
+int i2cfd;
+int debug = 0;
+int verbose = 0;
+
+/* ---------------- algorithm lookup code ---------------- */
+
+struct ctrl {
+    char *name;
+    uint8_t addr_prefix;
+    uint8_t addr_block;
+    uint8_t block_len;
+    uint8_t addr_digest;
+    uint8_t digest_len;
+    uint8_t mode;
+} ctrl[] = {
+    { "sha-1",       SHA1_ADDR_PREFIX, SHA1_ADDR_BLOCK, SHA1_BLOCK_LEN,
+                     SHA1_ADDR_DIGEST, SHA1_DIGEST_LEN, 0 },
+    { "sha-256",     SHA256_ADDR_PREFIX, SHA256_ADDR_BLOCK, SHA256_BLOCK_LEN,
+                     SHA256_ADDR_DIGEST, SHA256_DIGEST_LEN, 0 },
+    { "sha-512/224", SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
+                     SHA512_ADDR_DIGEST, 7, MODE_SHA_512_224 },
+    { "sha-512/256", SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
+                     SHA512_ADDR_DIGEST, 8, MODE_SHA_512_256 },
+    { "sha-384",     SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
+                     SHA512_ADDR_DIGEST, 12, MODE_SHA_384 },
+    { "sha-512",     SHA512_ADDR_PREFIX, SHA512_ADDR_BLOCK, SHA512_BLOCK_LEN,
+                     SHA512_ADDR_DIGEST, 16, MODE_SHA_512 },
+    { NULL, 0, 0, 0 }
+};
+
+/* return the control structure for the given algorithm */
+struct ctrl *find_algo(char *algo)
+{
+    int i;
+
+    for (i = 0; ctrl[i].name != NULL; ++i)
+        if (strcmp(ctrl[i].name, algo) == 0)
+            return &ctrl[i];
+
+    fprintf(stderr, "algorithm \"%s\" not found\n\n", algo);
+    fprintf(stderr, usage, "hash");
+    return NULL;
+}
+
+/* ---------------- I2C low-level code ---------------- */
+
+int i2c_open(char *dev, int addr)
+{
+    if (debug) printf("i2c_open(%s, %d)\n", dev, addr);
+
+    i2cfd = open(dev, O_RDWR);
+    if (i2cfd < 0) {
+        fprintf(stderr, "Unable to open %s: ", dev);
+        perror("");
+        i2cfd = 0;
+        return 1;
+    }
+
+    if (ioctl(i2cfd, I2C_SLAVE, addr) < 0) {
+        fprintf(stderr, "Unable to set I2C slave device 0x%02x: ", addr);
+        perror("");
+        return 1;
+    }
+
+    return 0;
+}
+
+void i2c_close(void)
+{
+    close(i2cfd);
+}
+
+int i2c_write(uint8_t *buf, int len)
+{
+    if (debug) {
+        int i;
+        printf("write [");
+        for (i = 0; i < len; ++i)
+            printf(" %02x", buf[i]);
+        printf(" ]\n");
+    }
+
+    if (write(i2cfd, buf, len) != len) {
+        perror("i2c write failed");
+        return 1;
+    }
+
+    return 0;
+}
+
+int i2c_read(uint8_t *b)
+{
+    /* read() on the i2c device only returns one byte at a time,
+     * and tc_get_resp() needs to parse the response one byte at a time
+     */
+    if (read(i2cfd, b, 1) != 1) {
+        perror("i2c read failed");
+        return 1;
+    }
+
+    return 0;
+}
+
+/* ---------------- test-case low-level code ---------------- */
+
+int tc_send_write_cmd(uint8_t addr0, uint8_t addr1, uint8_t *data)
+{
+    uint8_t buf[9] = { SOC, WRITE_CMD, addr0, addr1,
+                       data[0], data[1], data[2], data[3], EOC };
+
+    return i2c_write(buf, sizeof(buf));
+}
+
+int tc_send_read_cmd(uint8_t addr0, uint8_t addr1)
+{
+    uint8_t buf[5] = { SOC, READ_CMD, addr0, addr1, EOC };
+
+    return i2c_write(buf, sizeof(buf));
+}
+
+int tc_get_resp(uint8_t *buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; ++i) {
+        if (i2c_read(&buf[i]) != 0)
+            return 1;
+        if ((i == 0) && (buf[i] != SOR)) {
+            /* we've gotten out of sync, and there's probably nothing we can do */
+            fprintf(stderr, "response byte 0: expected 0x%02x (SOR), got 0x%02x\n",
+                    SOR, buf[0]);
+            return 1;
+        }
+        else if (i == 1) {      /* response code */
+            switch (buf[i]) {
+            case READ_OK:
+                len = 9;
+                break;
+            case WRITE_OK:
+                len = 5;
+                break;
+            case RESET_OK:
+                len = 3;
+                break;
+            case ERROR:
+            case UNKNOWN:
+                len = 4;
+                break;
+            default:
+                /* we've gotten out of sync, and there's probably nothing we can do */
+                fprintf(stderr, "unknown response code 0x%02x\n", buf[i]);
+                return 1;
+            }
+        }
+    }
+
+    if (debug) {
+        printf("read  [");
+        for (i = 0; i < len; ++i)
+            printf(" %02x", buf[i]);
+        printf(" ]\n");
+    }
+
+    return 0;
+}
+
+int tc_compare(uint8_t *buf, uint8_t *expected, int len)
+{
+    int i;
+
+    /* start at byte 1 because SOR has already been tested */
+    for (i = 1; i < len; ++i) {
+        if (buf[i] != expected[i]) {
+            fprintf(stderr, "response byte %d: expected 0x%02x, got 0x%02x\n",
+                    i, expected[i], buf[i]);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+int tc_get_write_resp(uint8_t addr0, uint8_t addr1)
+{
+    uint8_t buf[5];
+    uint8_t expected[5] = { SOR, WRITE_OK, addr0, addr1, EOR };
+
+    return
+        tc_get_resp(buf, sizeof(buf)) ||
+        tc_compare(buf, expected, sizeof(expected));
+}
+
+int tc_get_read_resp(uint8_t addr0, uint8_t addr1, uint8_t *data)
+{
+    uint8_t buf[9];
+    uint8_t expected[4] = { SOR, READ_OK, addr0, addr1 };
+
+    if ((tc_get_resp(buf, sizeof(buf)) != 0) ||
+        (tc_compare(buf, expected, 4) != 0) || buf[8] != EOR)
+        return 1;
+
+    data[0] = buf[4];
+    data[1] = buf[5];
+    data[2] = buf[6];
+    data[3] = buf[7];
+
+    return 0;
+}
+
+int tc_write(uint8_t addr0, uint8_t addr1, uint8_t *data)
+{
+    return (tc_send_write_cmd(addr0, addr1, data) ||
+            tc_get_write_resp(addr0, addr1));
+}
+
+int tc_read(uint8_t addr0, uint8_t addr1, uint8_t *data)
+{
+    return (tc_send_read_cmd(addr0, addr1) ||
+            tc_get_read_resp(addr0, addr1, data));
+}
+
+int tc_init(uint8_t addr0, uint8_t mode)
+{
+    uint8_t buf[4] = { 0, 0, 0, CTRL_INIT_CMD };
+
+    if (addr0 == SHA512_ADDR_PREFIX)
+        buf[3] += (mode << SHA512_CTRL_MODE_LOW);
+
+    return tc_write(addr0, ADDR_CTRL, buf);
+}
+
+int tc_next(uint8_t addr0, uint8_t mode)
+{
+    uint8_t buf[4] = { 0, 0, 0, CTRL_NEXT_CMD };
+
+    if (addr0 == SHA512_ADDR_PREFIX)
+        buf[3] += (mode << SHA512_CTRL_MODE_LOW);
+
+    return tc_write(addr0, ADDR_CTRL, buf);
+}
+
+int tc_wait(uint8_t addr0, uint8_t status)
+{
+    uint8_t buf[4];
+
+    do {
+        if (tc_read(addr0, ADDR_STATUS, &buf[0]) != 0)
+            return 1;
+    } while ((buf[3] & status) != status);
+
+    return 0;
+}
+
+int tc_wait_ready(uint8_t addr0)
+{
+    return tc_wait(addr0, STATUS_READY_BIT);
+}
+
+int tc_wait_valid(uint8_t addr0)
+{
+    return tc_wait(addr0, STATUS_VALID_BIT);
+}
+
+int tc_write_block(uint8_t addr0, uint8_t addr1, uint8_t *buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; ++i) {
+        if (tc_write(addr0, addr1 + i, &buf[i*4]) != 0)
+            return 1;
+    }
+
+    return 0;
+}
+
+int tc_read_digest(uint8_t addr0, uint8_t addr1, uint8_t *buf, int len)
+{
+    int i;
+
+    for (i = 0; i < len; ++i) {
+        if (tc_read(addr0, addr1 + i, &buf[i*4]) != 0)
+            return 1;
+    }
+
+    return 0;
+}
+
+/* ---------------- hash ---------------- */
+
+/* return number of digest bytes read */
+int hash(char *algo, char *file, uint8_t *digest)
+{
+    uint8_t block[SHA512_BLOCK_LEN * 4];
+    struct ctrl *ctrl;
+    int in_fd = 0;      /* stdin */
+    uint8_t addr0, baddr, blen, daddr, dlen, mode;
+    int nblk, nread, first;
+    int i, ret = -1;
+    struct timeval start, stop, difftime;
+
+    if (debug) printf("hash(algo=%s, file=%s, digest=%p)\n", algo, file, digest);
+
+    ctrl = find_algo(algo);
+    if (ctrl == NULL)
+        return -1;
+    addr0 = ctrl->addr_prefix;
+    baddr = ctrl->addr_block;
+    blen = ctrl->block_len;
+    daddr = ctrl->addr_digest;
+    dlen = ctrl->digest_len;
+    mode = ctrl->mode;
+
+    if (strcmp(file, "-") != 0) {
+        in_fd = open(file, O_RDONLY);
+        if (in_fd < 0) {
+            perror("open");
+            return -1;
+        }
+    }
+
+    if (verbose) {
+        if (gettimeofday(&start, NULL) < 0) {
+            perror("gettimeofday");
+            goto out;
+        }
+    }
+
+    for (nblk = 0, first = 1; ; ++nblk) {
+        nread = read(in_fd, block, blen * 4);
+        if (nread != blen * 4) {
+            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 * 4) {
+                    block[nread++] = 0;
+                }
+            }
+        }
+        if (debug) {
+            printf("write [");
+            for (i = 0; i < blen * 4; ++i)
+                printf(" %02x", block[i]);
+            printf(" ]\n");
+        }
+        if (tc_write_block(addr0, baddr, block, blen) != 0) {
+            goto out;
+        }
+        if (first) {
+            first = 0;
+            if (tc_init(addr0, mode) != 0)
+                goto out;
+        }
+        else {
+            if (tc_next(addr0, mode) != 0)
+                goto out;
+        }
+        if (tc_wait_ready(addr0) != 0)
+            goto out;
+    }
+
+    if (tc_wait_valid(addr0) != 0)
+	goto out;
+    if (tc_read_digest(addr0, daddr, digest, dlen) != 0) {
+        perror("i2c read failed");
+        goto out;
+    }
+
+    if (verbose) {
+        if (gettimeofday(&stop, NULL) < 0) {
+            perror("gettimeofday");
+            goto out;
+        }
+        timersub(&stop, &start, &difftime);
+        printf("%d blocks written in %d.%03d sec (%.3f blocks/sec)\n",
+               nblk, (int)difftime.tv_sec, (int)difftime.tv_usec/1000,
+               (float)nblk / ((float)difftime.tv_sec + ((float)difftime.tv_usec)/1000000));
+    }
+
+    ret = dlen * 4;
+out:
+    if (in_fd != 0)
+        close(in_fd);
+    return ret;
+}
+
+/* ---------------- main ---------------- */
+
+int main(int argc, char *argv[])
+{
+    char *dev = I2C_dev;
+    int addr = I2C_addr;
+    int i, opt, quiet = 0;
+    char *algo = "sha-1";
+    char *file = "-";
+    uint8_t digest[512/8];
+    int dlen;
+
+    while ((opt = getopt(argc, argv, "h?dvqi:a:")) != -1) {
+        switch (opt) {
+        case 'h':
+        case '?':
+            printf(usage, argv[0]);
+            return 0;
+        case 'd':
+            debug = 1;
+            break;
+        case 'v':
+            verbose = 1;
+            break;
+        case 'q':
+            quiet = 1;
+            break;
+        case 'i':
+            dev = optarg;
+            break;
+        case 'a':
+            addr = (int)strtol(optarg, NULL, 0);
+            if ((addr < 0x03) || (addr > 0x77)) {
+                fprintf(stderr, "addr must be between 0x03 and 0x77\n");
+                return 1;
+            }
+            break;
+        default:
+            fprintf(stderr, usage, argv[0]);
+            return 1;
+        }
+    }
+
+    if (optind < argc) {
+        algo = argv[optind];
+        ++optind;
+    }
+    else {
+        if (!quiet)
+            printf("defaulting to algorithm \"%s\"\n", algo);
+    }
+
+    if (optind < argc) {
+        file = argv[optind];
+        ++optind;
+    }
+    else {
+        if (!quiet)
+            printf("reading from stdin\n");
+    }
+
+    if (i2c_open(dev, addr) != 0)
+        return -1;
+
+    dlen = hash(algo, file, digest);
+    if (dlen < 0)
+        return 1;
+
+    for (i = 0; i < dlen; ++i) {
+        printf("%02x", digest[i]);
+        if (i % 16 == 15)
+            printf("\n");
+        else if (i % 4 == 3)
+            printf(" ");
+    }
+    if (dlen % 16 != 0)
+        printf("\n");
+
+    i2c_close();
+
+    return 0;
+}
diff --git a/src/sw/nist_1024_double.bin b/src/sw/nist_1024_double.bin
new file mode 100644
index 0000000..543b415
Binary files /dev/null and b/src/sw/nist_1024_double.bin differ
diff --git a/src/sw/nist_1024_single.bin b/src/sw/nist_1024_single.bin
new file mode 100644
index 0000000..100111a
Binary files /dev/null and b/src/sw/nist_1024_single.bin differ
diff --git a/src/sw/nist_512_double.bin b/src/sw/nist_512_double.bin
new file mode 100644
index 0000000..ac8d755
Binary files /dev/null and b/src/sw/nist_512_double.bin differ
diff --git a/src/sw/nist_512_single.bin b/src/sw/nist_512_single.bin
new file mode 100644
index 0000000..1f3a5ce
Binary files /dev/null and b/src/sw/nist_512_single.bin differ



More information about the Commits mailing list