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