summaryrefslogtreecommitdiff
path: root/util.c
blob: f0d1fdafcc04b6578b78c6ff4c02af7b1dea128f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <assert.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#include "util.h"

static inline signed char hexchr2int(char c) {
    /* No, nobody uses EBCDIC anymore. */
    return (c >= '0' && c <= '9') ? (c - '0') :
           (c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
           (c >= 'A' && c <= 'F') ? (c - 'A' + 10) :
           -1;
}

/**
 * Decode hex.
 *
 * \param dest where to store the decoded data
 * \param size the maximum number of bytes to decode
 * \param src the hex-encoded data
 *
 * \return 0 if an error occurred, otherwise the number of bytes written to
 * dest
 */
size_t hex2mem(unsigned char *dest, size_t size, const char *src) {
#ifdef DEBUG
    fprintf(stderr, "hex decoding %zu bytes\n", size);
#endif
    size_t i;
    for (i = 0; i < size; i++) {
        int n1 = hexchr2int(src[2*i]);
        if (n1 < 0) return 0;
        int n2 = hexchr2int(src[2*i+1]);
        if (n2 < 0) return 0;
        dest[i] = (unsigned char)(n1 << 4 | n2);
    }
    return i;
}

static const char *HEX_CHARS = "0123456789abcdef";

/** Encode hex.
 *
 * \param dest where to store the encoded data (must have at least size*2+1 bytes)
 * \param src the data to encode
 * \param size the number of bytes to encode
 */
void mem2hex(char *dest, const void *src, size_t size) {
    for (size_t i = 0; i < size; i++) {
        unsigned char c = *((const unsigned char *)src + i);
        dest[2*i] = HEX_CHARS[c >> 4];
        dest[2*i+1] = HEX_CHARS[c & 0xf];
    }
    dest[size*2] = '\0';
}

void hash(const unsigned char salt[static SALT_LEN], unsigned char *out, const void *in, size_t size) {
    assert(size < INT_MAX - SALT_LEN - 100);
#ifdef DEBUG
    fprintf(stderr, "hashing %zu bytes starting with 0x%x ending with 0x%x\n", size, (int)((unsigned char*)in)[0], (int)((unsigned char*)in)[size-1]);
#endif
    sha256_ctx ctx;
    sha256_init(&ctx);
    sha256_update(&ctx, salt, SALT_LEN);
    sha256_update(&ctx, in, (unsigned int)size);
    sha256_final(&ctx, out);
}

void print_hash(const unsigned char digest[static HASH_LEN]) {
#ifdef DEBUG
    char hash[HASH_LEN*2+1];
    mem2hex(hash, digest, HASH_LEN);
    fprintf(stderr, "hash: %s\n", hash);
#else
    (void)digest;
#endif
}

bool hash_match(const unsigned char digest[static HASH_LEN], const char *arg) {
    unsigned char theirdigest[HASH_LEN];
    if (hex2mem(theirdigest, sizeof(theirdigest), arg) == 0) {
        fputs("error decoding hex hash\n", stderr);
        exit(1);
    }
#ifdef DEBUG
    fprintf(stderr, "comparing hash, theirs: %s = 0x%02x..0x%02x, ours: 0x%02x..0x%02x\n", arg, (int)theirdigest[0], (int)theirdigest[HASH_LEN-1], (int)digest[0], (int)theirdigest[HASH_LEN-1]);
    fputs("  our ", stderr);
    print_hash(digest);
    fputs("their ", stderr);
    print_hash(theirdigest);
#endif
    return !memcmp(digest, theirdigest, HASH_LEN);
}