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