Skip to content

Instantly share code, notes, and snippets.

@kulp
Created August 17, 2015 17:33
Show Gist options
  • Save kulp/c7feb6109e770cebb74a to your computer and use it in GitHub Desktop.
Save kulp/c7feb6109e770cebb74a to your computer and use it in GitHub Desktop.

Revisions

  1. kulp created this gist Aug 17, 2015.
    101 changes: 101 additions & 0 deletions sha1.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,101 @@
    #include <stdint.h>
    #include <stdio.h>
    #include <limits.h>

    static inline uint32_t rol(uint32_t x, unsigned char y)
    {
    return (x << y) | ((x >> (32 - y)) & ~(-1 << y));
    }

    static void chunk(uint32_t h[5], unsigned char *ptr)
    {
    uint32_t w[80];

    for (int i = 0; i < 16; i++)
    w[i] = (ptr[i * 4 + 0] << 24)
    | (ptr[i * 4 + 1] << 16)
    | (ptr[i * 4 + 2] << 8)
    | (ptr[i * 4 + 3] << 0);

    for (int i = 16; i < 80; i++)
    w[i] = rol(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);

    uint32_t a = h[0],
    b = h[1],
    c = h[2],
    d = h[3],
    e = h[4];

    static const uint32_t k[] =
    { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };

    for (int i = 0; i < 80; i++) {
    uint32_t f = (i < 20) ? (b & c) | (~b & d) :
    (i < 40) ? b ^ c ^ d :
    (i < 60) ? (b & c) | (b & d) | (c & d) :
    b ^ c ^ d;

    uint32_t temp = rol(a, 5) + f + e + k[i / 20] + w[i];
    e = d;
    d = c;
    c = rol(b, 30);
    b = a;
    a = temp;
    }

    h[0] += a;
    h[1] += b;
    h[2] += c;
    h[3] += d;
    h[4] += e;
    }

    void process_stream(FILE *in, const char *fname)
    {
    uint32_t h[] =
    { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };

    const int chunkbytes = 512 / CHAR_BIT;
    unsigned char buf[chunkbytes * 2];
    size_t end = 0, pos = 0;
    while (!feof(in) && !ferror(in)) {
    end += fread(buf, 1, chunkbytes, in);

    if (end - pos >= chunkbytes) {
    chunk(h, buf);
    pos += chunkbytes;
    }
    }

    if (ferror(in)) {
    perror("sha1");
    return;
    }

    // handle last chunk which is necessarily < 512 bits long
    uint64_t ml = end * CHAR_BIT;
    buf[end++ - pos] = 1 << (CHAR_BIT - 1);
    while ((end - pos) % 64 != 56)
    buf[end++ - pos] = 0x00;

    size_t idx = end - pos;
    for (int i = 0; i < 64 / CHAR_BIT; i++)
    buf[idx + i] = (ml >> ((7 - i) * CHAR_BIT)) & 0xff;

    for (size_t off = 0; off < idx; off += 64)
    chunk(h, &buf[off]);

    printf("%08x%08x%08x%08x%08x %s\n", h[0], h[1], h[2], h[3], h[4], fname);
    }

    int main(int argc, char *argv[])
    {
    if (argc <= 1) {
    process_stream(stdin, "-");
    } else for (int i = 1; i < argc; i++) {
    FILE *in = fopen(argv[i], "rb");
    process_stream(in, argv[i]);
    fclose(in);
    }
    }