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