Branch data Line data Source code
1 : : /* ghmac.h - data hashing functions
2 : : *
3 : : * Copyright (C) 2011 Collabora Ltd.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General Public License
18 : : * along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Author: Stef Walter <stefw@collabora.co.uk>
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include <string.h>
26 : :
27 : : #include "ghmac.h"
28 : :
29 : : #include "glib/galloca.h"
30 : : #include "gatomic.h"
31 : : #include "gslice.h"
32 : : #include "gmem.h"
33 : : #include "gstrfuncs.h"
34 : : #include "gtestutils.h"
35 : : #include "gtypes.h"
36 : : #include "glibintl.h"
37 : :
38 : :
39 : : /**
40 : : * GHmac:
41 : : *
42 : : * HMACs should be used when producing a cookie or hash based on data
43 : : * and a key. Simple mechanisms for using SHA1 and other algorithms to
44 : : * digest a key and data together are vulnerable to various security
45 : : * issues.
46 : : * [HMAC](http://en.wikipedia.org/wiki/HMAC)
47 : : * uses algorithms like SHA1 in a secure way to produce a digest of a
48 : : * key and data.
49 : : *
50 : : * Both the key and data are arbitrary byte arrays of bytes or characters.
51 : : *
52 : : * Support for HMAC Digests has been added in GLib 2.30, and support for SHA-512
53 : : * in GLib 2.42. Support for SHA-384 was added in GLib 2.52.
54 : : *
55 : : * To create a new `GHmac`, use [ctor@GLib.Hmac.new]. To free a `GHmac`, use
56 : : * [method@GLib.Hmac.unref].
57 : : *
58 : : * Since: 2.30
59 : : */
60 : :
61 : : struct _GHmac
62 : : {
63 : : int ref_count;
64 : : GChecksumType digest_type;
65 : : GChecksum *digesti;
66 : : GChecksum *digesto;
67 : : };
68 : :
69 : : /**
70 : : * g_hmac_new: (constructor)
71 : : * @digest_type: the desired type of digest
72 : : * @key: (array length=key_len): the key for the HMAC
73 : : * @key_len: the length of the keys
74 : : *
75 : : * Creates a new #GHmac, using the digest algorithm @digest_type.
76 : : * If the @digest_type is not known, %NULL is returned.
77 : : * A #GHmac can be used to compute the HMAC of a key and an
78 : : * arbitrary binary blob, using different hashing algorithms.
79 : : *
80 : : * A #GHmac works by feeding a binary blob through g_hmac_update()
81 : : * until the data is complete; the digest can then be extracted
82 : : * using g_hmac_get_string(), which will return the checksum as a
83 : : * hexadecimal string; or g_hmac_get_digest(), which will return a
84 : : * array of raw bytes. Once either g_hmac_get_string() or
85 : : * g_hmac_get_digest() have been called on a #GHmac, the HMAC
86 : : * will be closed and it won't be possible to call g_hmac_update()
87 : : * on it anymore.
88 : : *
89 : : * Support for digests of type %G_CHECKSUM_SHA512 has been added in GLib 2.42.
90 : : * Support for %G_CHECKSUM_SHA384 was added in GLib 2.52.
91 : : *
92 : : * Returns: (nullable) (transfer full): the newly created #GHmac, or %NULL.
93 : : * Use g_hmac_unref() to free the memory allocated by it.
94 : : *
95 : : * Since: 2.30
96 : : */
97 : : GHmac *
98 : 41 : g_hmac_new (GChecksumType digest_type,
99 : : const guchar *key,
100 : : gsize key_len)
101 : : {
102 : : GChecksum *checksum;
103 : : GHmac *hmac;
104 : : guchar *buffer;
105 : : guchar *pad;
106 : : gsize i, len;
107 : : gsize block_size;
108 : : gssize block_size_signed, key_len_signed;
109 : :
110 : 41 : g_return_val_if_fail (key_len <= G_MAXSSIZE, NULL);
111 : :
112 : 41 : checksum = g_checksum_new (digest_type);
113 : 41 : g_return_val_if_fail (checksum != NULL, NULL);
114 : :
115 [ + + + - ]: 41 : switch (digest_type)
116 : : {
117 : 21 : case G_CHECKSUM_MD5:
118 : : case G_CHECKSUM_SHA1:
119 : 21 : block_size = 64; /* RFC 2104 */
120 : 21 : break;
121 : 8 : case G_CHECKSUM_SHA256:
122 : 8 : block_size = 64; /* RFC 4868 */
123 : 8 : break;
124 : 12 : case G_CHECKSUM_SHA384:
125 : : case G_CHECKSUM_SHA512:
126 : 12 : block_size = 128; /* RFC 4868 */
127 : 12 : break;
128 : 0 : default:
129 : : g_return_val_if_reached (NULL);
130 : : }
131 : :
132 : 41 : hmac = g_slice_new0 (GHmac);
133 : 41 : hmac->ref_count = 1;
134 : 41 : hmac->digest_type = digest_type;
135 : 41 : hmac->digesti = checksum;
136 : 41 : hmac->digesto = g_checksum_new (digest_type);
137 : :
138 [ + - ]: 41 : buffer = g_alloca0 (block_size);
139 : 41 : pad = g_alloca (block_size);
140 : :
141 : : /* If the key is too long, hash it */
142 [ + + ]: 41 : if (key_len > block_size)
143 : : {
144 : 10 : len = block_size;
145 : 10 : g_assert (key_len <= G_MAXSSIZE);
146 : 10 : key_len_signed = key_len;
147 : 10 : g_checksum_update (hmac->digesti, key, key_len_signed);
148 : 10 : g_checksum_get_digest (hmac->digesti, buffer, &len);
149 : 10 : g_checksum_reset (hmac->digesti);
150 : : }
151 : :
152 : : /* Otherwise pad it with zeros */
153 : : else
154 : : {
155 : 31 : memcpy (buffer, key, key_len);
156 : : }
157 : :
158 : : /* g_checksum_update() accepts a signed length, so build and check that. */
159 : 41 : g_assert (block_size <= G_MAXSSIZE);
160 : 41 : block_size_signed = block_size;
161 : :
162 : : /* First pad */
163 [ + + ]: 3433 : for (i = 0; i < block_size; i++)
164 : 3392 : pad[i] = 0x36 ^ buffer[i]; /* ipad value */
165 : 41 : g_checksum_update (hmac->digesti, pad, block_size_signed);
166 : :
167 : : /* Second pad */
168 [ + + ]: 3433 : for (i = 0; i < block_size; i++)
169 : 3392 : pad[i] = 0x5c ^ buffer[i]; /* opad value */
170 : 41 : g_checksum_update (hmac->digesto, pad, block_size_signed);
171 : :
172 : 41 : return hmac;
173 : : }
174 : :
175 : : /**
176 : : * g_hmac_copy:
177 : : * @hmac: the #GHmac to copy
178 : : *
179 : : * Copies a #GHmac. If @hmac has been closed, by calling
180 : : * g_hmac_get_string() or g_hmac_get_digest(), the copied
181 : : * HMAC will be closed as well.
182 : : *
183 : : * Returns: (transfer full): the copy of the passed #GHmac. Use g_hmac_unref()
184 : : * when finished using it.
185 : : *
186 : : * Since: 2.30
187 : : */
188 : : GHmac *
189 : 1 : g_hmac_copy (const GHmac *hmac)
190 : : {
191 : : GHmac *copy;
192 : :
193 : 1 : g_return_val_if_fail (hmac != NULL, NULL);
194 : :
195 : 1 : copy = g_slice_new (GHmac);
196 : 1 : copy->ref_count = 1;
197 : 1 : copy->digest_type = hmac->digest_type;
198 : 1 : copy->digesti = g_checksum_copy (hmac->digesti);
199 : 1 : copy->digesto = g_checksum_copy (hmac->digesto);
200 : :
201 : 1 : return copy;
202 : : }
203 : :
204 : : /**
205 : : * g_hmac_ref:
206 : : * @hmac: a valid #GHmac
207 : : *
208 : : * Atomically increments the reference count of @hmac by one.
209 : : *
210 : : * This function is MT-safe and may be called from any thread.
211 : : *
212 : : * Returns: (transfer full): the passed in #GHmac.
213 : : *
214 : : * Since: 2.30
215 : : **/
216 : : GHmac *
217 : 1 : g_hmac_ref (GHmac *hmac)
218 : : {
219 : 1 : g_return_val_if_fail (hmac != NULL, NULL);
220 : :
221 : 1 : g_atomic_int_inc (&hmac->ref_count);
222 : :
223 : 1 : return hmac;
224 : : }
225 : :
226 : : /**
227 : : * g_hmac_unref:
228 : : * @hmac: (transfer full): a #GHmac
229 : : *
230 : : * Atomically decrements the reference count of @hmac by one.
231 : : *
232 : : * If the reference count drops to 0, all keys and values will be
233 : : * destroyed, and all memory allocated by the hash table is released.
234 : : * This function is MT-safe and may be called from any thread.
235 : : * Frees the memory allocated for @hmac.
236 : : *
237 : : * Since: 2.30
238 : : */
239 : : void
240 : 43 : g_hmac_unref (GHmac *hmac)
241 : : {
242 : 43 : g_return_if_fail (hmac != NULL);
243 : :
244 [ + + ]: 43 : if (g_atomic_int_dec_and_test (&hmac->ref_count))
245 : : {
246 : 42 : g_checksum_free (hmac->digesti);
247 : 42 : g_checksum_free (hmac->digesto);
248 : 42 : g_slice_free (GHmac, hmac);
249 : : }
250 : : }
251 : :
252 : : /**
253 : : * g_hmac_update:
254 : : * @hmac: a #GHmac
255 : : * @data: (array length=length): buffer used to compute the checksum
256 : : * @length: size of the buffer, or -1 if it is a nul-terminated string
257 : : *
258 : : * Feeds @data into an existing #GHmac.
259 : : *
260 : : * The HMAC must still be open, that is g_hmac_get_string() or
261 : : * g_hmac_get_digest() must not have been called on @hmac.
262 : : *
263 : : * Since: 2.30
264 : : */
265 : : void
266 : 38 : g_hmac_update (GHmac *hmac,
267 : : const guchar *data,
268 : : gssize length)
269 : : {
270 : 38 : g_return_if_fail (hmac != NULL);
271 : 38 : g_return_if_fail (length == 0 || data != NULL);
272 : :
273 : 38 : g_checksum_update (hmac->digesti, data, length);
274 : : }
275 : :
276 : : /**
277 : : * g_hmac_get_string:
278 : : * @hmac: a #GHmac
279 : : *
280 : : * Gets the HMAC as a hexadecimal string.
281 : : *
282 : : * Once this function has been called the #GHmac can no longer be
283 : : * updated with g_hmac_update().
284 : : *
285 : : * The hexadecimal characters will be lower case.
286 : : *
287 : : * Returns: the hexadecimal representation of the HMAC. The
288 : : * returned string is owned by the HMAC and should not be modified
289 : : * or freed.
290 : : *
291 : : * Since: 2.30
292 : : */
293 : : const gchar *
294 : 8 : g_hmac_get_string (GHmac *hmac)
295 : : {
296 : : guint8 *buffer;
297 : : gssize digest_len_signed;
298 : : gsize digest_len;
299 : :
300 : 8 : g_return_val_if_fail (hmac != NULL, NULL);
301 : :
302 : : /* It shouldn’t be possible for @digest_len_signed to be negative, as
303 : : * `hmac->digest_type` has already been validated as being supported. */
304 : 8 : digest_len_signed = g_checksum_type_get_length (hmac->digest_type);
305 : 8 : g_assert (digest_len_signed >= 0);
306 : 8 : digest_len = digest_len_signed;
307 : :
308 : 8 : buffer = g_alloca (digest_len);
309 : :
310 : : /* This is only called for its side-effect of updating hmac->digesto... */
311 : 8 : g_hmac_get_digest (hmac, buffer, &digest_len);
312 : : /* ... because we get the string from the checksum rather than
313 : : * stringifying buffer ourselves
314 : : */
315 : 8 : return g_checksum_get_string (hmac->digesto);
316 : : }
317 : :
318 : : /**
319 : : * g_hmac_get_digest:
320 : : * @hmac: a #GHmac
321 : : * @buffer: (array length=digest_len): output buffer
322 : : * @digest_len: (inout): an inout parameter. The caller initializes it to the
323 : : * size of @buffer. After the call it contains the length of the digest
324 : : *
325 : : * Gets the digest from @checksum as a raw binary array and places it
326 : : * into @buffer. The size of the digest depends on the type of checksum.
327 : : *
328 : : * Once this function has been called, the #GHmac is closed and can
329 : : * no longer be updated with g_checksum_update().
330 : : *
331 : : * Since: 2.30
332 : : */
333 : : void
334 : 40 : g_hmac_get_digest (GHmac *hmac,
335 : : guint8 *buffer,
336 : : gsize *digest_len)
337 : : {
338 : : gsize len;
339 : : gssize len_signed;
340 : :
341 : 40 : g_return_if_fail (hmac != NULL);
342 : :
343 : : /* It shouldn’t be possible for @len_signed to be negative, as
344 : : * `hmac->digest_type` has already been validated as being supported. */
345 : 40 : len_signed = g_checksum_type_get_length (hmac->digest_type);
346 : 40 : g_assert (len_signed >= 0);
347 : 40 : len = len_signed;
348 : :
349 : : /* @buffer must be long enough for the digest */
350 : 40 : g_return_if_fail (*digest_len >= len);
351 : :
352 : : /* Use the same buffer, because we can :) */
353 : 40 : g_checksum_get_digest (hmac->digesti, buffer, &len);
354 : 40 : g_assert (len <= G_MAXSSIZE);
355 : 40 : len_signed = len;
356 : 40 : g_checksum_update (hmac->digesto, buffer, len_signed);
357 : 40 : g_checksum_get_digest (hmac->digesto, buffer, digest_len);
358 : : }
359 : :
360 : : /**
361 : : * g_compute_hmac_for_data:
362 : : * @digest_type: a #GChecksumType to use for the HMAC
363 : : * @key: (array length=key_len): the key to use in the HMAC
364 : : * @key_len: the length of the key
365 : : * @data: (array length=length): binary blob to compute the HMAC of
366 : : * @length: length of @data
367 : : *
368 : : * Computes the HMAC for a binary @data of @length. This is a
369 : : * convenience wrapper for g_hmac_new(), g_hmac_get_string()
370 : : * and g_hmac_unref().
371 : : *
372 : : * The hexadecimal string returned will be in lower case.
373 : : *
374 : : * Returns: the HMAC of the binary data as a string in hexadecimal.
375 : : * The returned string should be freed with g_free() when done using it.
376 : : *
377 : : * Since: 2.30
378 : : */
379 : : gchar *
380 : 3 : g_compute_hmac_for_data (GChecksumType digest_type,
381 : : const guchar *key,
382 : : gsize key_len,
383 : : const guchar *data,
384 : : gsize length)
385 : : {
386 : : GHmac *hmac;
387 : : gchar *retval;
388 : :
389 : 3 : g_return_val_if_fail (length == 0 || data != NULL, NULL);
390 : :
391 : 3 : hmac = g_hmac_new (digest_type, key, key_len);
392 [ - + ]: 3 : if (!hmac)
393 : 0 : return NULL;
394 : :
395 : 3 : g_hmac_update (hmac, data, length);
396 : 3 : retval = g_strdup (g_hmac_get_string (hmac));
397 : 3 : g_hmac_unref (hmac);
398 : :
399 : 3 : return retval;
400 : : }
401 : :
402 : : /**
403 : : * g_compute_hmac_for_bytes:
404 : : * @digest_type: a #GChecksumType to use for the HMAC
405 : : * @key: the key to use in the HMAC
406 : : * @data: binary blob to compute the HMAC of
407 : : *
408 : : * Computes the HMAC for a binary @data. This is a
409 : : * convenience wrapper for g_hmac_new(), g_hmac_get_string()
410 : : * and g_hmac_unref().
411 : : *
412 : : * The hexadecimal string returned will be in lower case.
413 : : *
414 : : * Returns: the HMAC of the binary data as a string in hexadecimal.
415 : : * The returned string should be freed with g_free() when done using it.
416 : : *
417 : : * Since: 2.50
418 : : */
419 : : gchar *
420 : 1 : g_compute_hmac_for_bytes (GChecksumType digest_type,
421 : : GBytes *key,
422 : : GBytes *data)
423 : : {
424 : : gconstpointer byte_data;
425 : : gsize length;
426 : : gconstpointer key_data;
427 : : gsize key_len;
428 : :
429 : 1 : g_return_val_if_fail (data != NULL, NULL);
430 : 1 : g_return_val_if_fail (key != NULL, NULL);
431 : :
432 : 1 : byte_data = g_bytes_get_data (data, &length);
433 : 1 : key_data = g_bytes_get_data (key, &key_len);
434 : 1 : return g_compute_hmac_for_data (digest_type, key_data, key_len, byte_data, length);
435 : : }
436 : :
437 : :
438 : : /**
439 : : * g_compute_hmac_for_string:
440 : : * @digest_type: a #GChecksumType to use for the HMAC
441 : : * @key: (array length=key_len): the key to use in the HMAC
442 : : * @key_len: the length of the key
443 : : * @str: the string to compute the HMAC for
444 : : * @length: the length of the string, or -1 if the string is nul-terminated
445 : : *
446 : : * Computes the HMAC for a string.
447 : : *
448 : : * The hexadecimal string returned will be in lower case.
449 : : *
450 : : * Returns: the HMAC as a hexadecimal string.
451 : : * The returned string should be freed with g_free()
452 : : * when done using it.
453 : : *
454 : : * Since: 2.30
455 : : */
456 : : gchar *
457 : 1 : g_compute_hmac_for_string (GChecksumType digest_type,
458 : : const guchar *key,
459 : : gsize key_len,
460 : : const gchar *str,
461 : : gssize length)
462 : : {
463 : 1 : g_return_val_if_fail (length == 0 || str != NULL, NULL);
464 : :
465 [ + - ]: 1 : if (length < 0)
466 : 1 : length = strlen (str);
467 : :
468 : 1 : return g_compute_hmac_for_data (digest_type, key, key_len,
469 : : (const guchar *) str, length);
470 : : }
|