source: lib/sha1.c @ b1b9453

Last change on this file since b1b9453 was 2906268, checked in by dequis <dx@…>, at 2016-10-16T06:58:19Z

lib/sha1: Refactor sha1_hmac into a generic b_hmac function

  • Property mode set to 100644
File size: 3.0 KB
Line 
1#include "sha1.h"
2#include <string.h>
3#include <stdio.h>
4
5
6void sha1_init(sha1_state_t *ctx)
7{
8        *ctx = g_checksum_new(G_CHECKSUM_SHA1);
9}
10
11void sha1_append(sha1_state_t *ctx, const guint8 * message_array, guint len)
12{
13        g_checksum_update(*ctx, message_array, len);
14}
15
16void sha1_finish(sha1_state_t *ctx, guint8 digest[SHA1_HASH_SIZE])
17{
18        gsize digest_len = SHA1_HASH_SIZE;
19
20        g_checksum_get_digest(*ctx, digest, &digest_len);
21        g_checksum_free(*ctx);
22}
23
24#define HMAC_BLOCK_SIZE 64
25
26void b_hmac(GChecksumType checksum_type, const char *key_, size_t key_len,
27            const char *payload, size_t payload_len, guint8 **digest)
28{
29        GChecksum *checksum;
30        size_t hash_len;
31        guint8 *hash;
32        guint8 key[HMAC_BLOCK_SIZE + 1];
33        int i;
34
35        hash_len = g_checksum_type_get_length(checksum_type);
36
37        if (hash_len == (size_t) -1) {
38                return;
39        }
40
41        hash = g_malloc(hash_len);
42
43        if (key_len == 0) {
44                key_len = strlen(key_);
45        }
46        if (payload_len == 0) {
47                payload_len = strlen(payload);
48        }
49
50        /* Create K. If our current key is >64 chars we have to hash it,
51           otherwise just pad. */
52        memset(key, 0, HMAC_BLOCK_SIZE + 1);
53        if (key_len > HMAC_BLOCK_SIZE) {
54                checksum = g_checksum_new(checksum_type);
55                g_checksum_update(checksum, (guint8 *) key_, key_len);
56                g_checksum_get_digest(checksum, key, &hash_len);
57                g_checksum_free(checksum);
58        } else {
59                memcpy(key, key_, key_len);
60        }
61
62        /* Inner part: H(K XOR 0x36, text) */
63        checksum = g_checksum_new(checksum_type);
64        for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
65                key[i] ^= 0x36;
66        }
67        g_checksum_update(checksum, key, HMAC_BLOCK_SIZE);
68        g_checksum_update(checksum, (const guint8 *) payload, payload_len);
69        g_checksum_get_digest(checksum, hash, &hash_len);
70        g_checksum_free(checksum);
71
72        /* Final result: H(K XOR 0x5C, inner stuff) */
73        checksum = g_checksum_new(checksum_type);
74        for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
75                key[i] ^= 0x36 ^ 0x5c;
76        }
77        g_checksum_update(checksum, key, HMAC_BLOCK_SIZE);
78        g_checksum_update(checksum, hash, hash_len);
79        g_checksum_get_digest(checksum, *digest, &hash_len);
80        g_checksum_free(checksum);
81
82        g_free(hash);
83}
84
85void sha1_hmac(const char *key_, size_t key_len, const char *payload, size_t payload_len, guint8 digest[SHA1_HASH_SIZE])
86{
87        b_hmac(G_CHECKSUM_SHA1, key_, key_len, payload, payload_len, &digest);
88}
89
90
91/* I think this follows the scheme described on:
92   http://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29
93   My random data comes from a SHA1 generator but hey, it's random enough for
94   me, and RFC 4122 looks way more complicated than I need this to be.
95
96   Returns a value that must be free()d. */
97char *sha1_random_uuid(sha1_state_t * context)
98{
99        guint8 dig[SHA1_HASH_SIZE];
100        char *ret = g_new0(char, 40);   /* 36 chars + \0 */
101        int i, p;
102
103        sha1_finish(context, dig);
104        for (p = i = 0; i < 16; i++) {
105                if (i == 4 || i == 6 || i == 8 || i == 10) {
106                        ret[p++] = '-';
107                }
108                if (i == 6) {
109                        dig[i] = (dig[i] & 0x0f) | 0x40;
110                }
111                if (i == 8) {
112                        dig[i] = (dig[i] & 0x30) | 0x80;
113                }
114
115                sprintf(ret + p, "%02x", dig[i]);
116                p += 2;
117        }
118        ret[p] = '\0';
119
120        return ret;
121}
Note: See TracBrowser for help on using the repository browser.