source: lib/sha1.c @ 2906268

Last change on this file since 2906268 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
RevLine 
[34afea7]1#include "sha1.h"
[523fb23]2#include <string.h>
[e0a0a42]3#include <stdio.h>
[77bfd07]4
5
[34afea7]6void sha1_init(sha1_state_t *ctx)
[77bfd07]7{
[34afea7]8        *ctx = g_checksum_new(G_CHECKSUM_SHA1);
[77bfd07]9}
10
[34afea7]11void sha1_append(sha1_state_t *ctx, const guint8 * message_array, guint len)
[77bfd07]12{
[34afea7]13        g_checksum_update(*ctx, message_array, len);
[77bfd07]14}
15
[34afea7]16void sha1_finish(sha1_state_t *ctx, guint8 digest[SHA1_HASH_SIZE])
[77bfd07]17{
[34afea7]18        gsize digest_len = SHA1_HASH_SIZE;
[5ebff60]19
[34afea7]20        g_checksum_get_digest(*ctx, digest, &digest_len);
21        g_checksum_free(*ctx);
[77bfd07]22}
[523fb23]23
24#define HMAC_BLOCK_SIZE 64
25
[2906268]26void b_hmac(GChecksumType checksum_type, const char *key_, size_t key_len,
27            const char *payload, size_t payload_len, guint8 **digest)
[523fb23]28{
[2906268]29        GChecksum *checksum;
30        size_t hash_len;
31        guint8 *hash;
[5ebff60]32        guint8 key[HMAC_BLOCK_SIZE + 1];
[523fb23]33        int i;
[5ebff60]34
[2906268]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
[5ebff60]43        if (key_len == 0) {
44                key_len = strlen(key_);
45        }
46        if (payload_len == 0) {
47                payload_len = strlen(payload);
48        }
49
[523fb23]50        /* Create K. If our current key is >64 chars we have to hash it,
51           otherwise just pad. */
[5ebff60]52        memset(key, 0, HMAC_BLOCK_SIZE + 1);
53        if (key_len > HMAC_BLOCK_SIZE) {
[2906268]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);
[5ebff60]58        } else {
59                memcpy(key, key_, key_len);
[523fb23]60        }
[5ebff60]61
[523fb23]62        /* Inner part: H(K XOR 0x36, text) */
[2906268]63        checksum = g_checksum_new(checksum_type);
[5ebff60]64        for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
[523fb23]65                key[i] ^= 0x36;
[5ebff60]66        }
[2906268]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);
[5ebff60]71
[523fb23]72        /* Final result: H(K XOR 0x5C, inner stuff) */
[2906268]73        checksum = g_checksum_new(checksum_type);
[5ebff60]74        for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
[523fb23]75                key[i] ^= 0x36 ^ 0x5c;
[5ebff60]76        }
[2906268]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);
[523fb23]83}
[e0a0a42]84
[2906268]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
[e0a0a42]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.
[5ebff60]95
[e0a0a42]96   Returns a value that must be free()d. */
[5ebff60]97char *sha1_random_uuid(sha1_state_t * context)
[e0a0a42]98{
[34afea7]99        guint8 dig[SHA1_HASH_SIZE];
[5ebff60]100        char *ret = g_new0(char, 40);   /* 36 chars + \0 */
[e0a0a42]101        int i, p;
[5ebff60]102
[e0a0a42]103        sha1_finish(context, dig);
[5ebff60]104        for (p = i = 0; i < 16; i++) {
105                if (i == 4 || i == 6 || i == 8 || i == 10) {
[e0a0a42]106                        ret[p++] = '-';
[5ebff60]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]);
[e0a0a42]116                p += 2;
117        }
118        ret[p] = '\0';
[5ebff60]119
[e0a0a42]120        return ret;
121}
Note: See TracBrowser for help on using the repository browser.