Remove Stig from first copyright line.
[radsecproxy.git] / fticks_hashmac.c
1 /* Copyright (c) 2006-2010, UNINETT AS.
2  * Copyright (c) 2010, UNINETT AS, NORDUnet A/S.
3  * Copyright (c) 2010-2012, NORDUnet A/S. */
4 /* See LICENSE for licensing information. */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <ctype.h>
11 #include <nettle/sha.h>
12 #include <nettle/hmac.h>
13 #include "fticks_hashmac.h"
14
15 static void
16 _format_hash(const uint8_t *hash, size_t out_len, uint8_t *out)
17 {
18     int ir, iw;
19
20     for (ir = 0, iw = 0; iw <= out_len - 3; ir++, iw += 2)
21         sprintf((char *) out + iw, "%02x", hash[ir % SHA256_DIGEST_SIZE]);
22 }
23
24 static void
25 _hash(const uint8_t *in,
26       const uint8_t *key,
27       size_t out_len,
28       uint8_t *out)
29 {
30     if (key == NULL) {
31         struct sha256_ctx ctx;
32         uint8_t hash[SHA256_DIGEST_SIZE];
33
34         sha256_init(&ctx);
35         sha256_update(&ctx, strlen((char *) in), in);
36         sha256_digest(&ctx, sizeof(hash), hash);
37         _format_hash(hash, out_len, out);
38     }
39     else {
40         struct hmac_sha256_ctx ctx;
41         uint8_t hash[SHA256_DIGEST_SIZE];
42
43         hmac_sha256_set_key(&ctx, strlen((char *) key), key);
44         hmac_sha256_update(&ctx, strlen((char *) in), in);
45         hmac_sha256_digest(&ctx, sizeof(hash), hash);
46         _format_hash(hash, out_len, out);
47     }
48 }
49
50 /** Hash the Ethernet MAC address in \a IN, keying a HMAC with \a KEY
51     unless \a KEY is NULL.  If \a KEY is null \a IN is hashed with an
52     ordinary cryptographic hash function such as SHA-2.
53
54     \a IN and \a KEY are NULL terminated strings.
55
56     \a IN is supposed to be an Ethernet MAC address and is sanitised
57     by lowercasing it, removing all but [0-9a-f] and truncating it at
58     the first ';' found.  The truncation is done because RADIUS
59     supposedly has a praxis of tacking on SSID to the MAC address in
60     Calling-Station-Id.
61
62     \return 0 on success, -ENOMEM on out of memory.
63 */
64 int
65 fticks_hashmac(const uint8_t *in,
66                const uint8_t *key,
67                size_t out_len,
68                uint8_t *out)
69 {
70     uint8_t *in_copy = NULL;
71     uint8_t *p = NULL;
72     int i;
73
74     in_copy = calloc(1, strlen((const char *) in) + 1);
75     if (in_copy == NULL)
76         return -ENOMEM;
77
78     /* Sanitise and lowercase 'in' into 'in_copy'.  */
79     for (i = 0, p = in_copy; in[i] != '\0'; i++) {
80         if (in[i] == ';') {
81             *p++ = '\0';
82             break;
83         }
84         if (in[i] >= '0' && in[i] <= '9') {
85             *p++ = in[i];
86         }
87         else if (tolower(in[i]) >= 'a' && tolower(in[i]) <= 'f') {
88             *p++ = tolower(in[i]);
89         }
90     }
91
92     _hash(in_copy, key, out_len, out);
93     free(in_copy);
94     return 0;
95 }