/* ghmac.h - data hashing functions
*
* Copyright (C) 2011 Collabora Ltd.
* Copyright (C) 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gnutls/crypto.h>
#include "ghmac.h"
#include "glib/galloca.h"
#include "gatomic.h"
#include "gslice.h"
#include "gmem.h"
#include "gstrfuncs.h"
#include "gchecksumprivate.h"
#include "gtestutils.h"
#include "gtypes.h"
#include "glibintl.h"
struct _GHmac
{
int ref_count;
GChecksumType digest_type;
gnutls_hmac_hd_t hmac;
gchar *digest_str;
};
GHmac *
g_hmac_new (GChecksumType digest_type,
const guchar *key,
gsize key_len)
{
gnutls_mac_algorithm_t algo;
GHmac *hmac = g_slice_new0 (GHmac);
hmac->ref_count = 1;
hmac->digest_type = digest_type;
switch (digest_type)
{
case G_CHECKSUM_MD5:
algo = GNUTLS_MAC_MD5;
break;
case G_CHECKSUM_SHA1:
algo = GNUTLS_MAC_SHA1;
break;
case G_CHECKSUM_SHA256:
algo = GNUTLS_MAC_SHA256;
break;
case G_CHECKSUM_SHA384:
algo = GNUTLS_MAC_SHA384;
break;
case G_CHECKSUM_SHA512:
algo = GNUTLS_MAC_SHA512;
break;
default:
g_return_val_if_reached (NULL);
}
gnutls_hmac_init (&hmac->hmac, algo, key, key_len);
return hmac;
}
GHmac *
g_hmac_copy (const GHmac *hmac)
{
g_error ("g_hmac_copy is not available with GnuTLS-backend GHmac");
}
GHmac *
g_hmac_ref (GHmac *hmac)
{
g_return_val_if_fail (hmac != NULL, NULL);
g_atomic_int_inc (&hmac->ref_count);
return hmac;
}
void
g_hmac_unref (GHmac *hmac)
{
g_return_if_fail (hmac != NULL);
if (g_atomic_int_dec_and_test (&hmac->ref_count))
{
gnutls_hmac_deinit (hmac->hmac, NULL);
g_free (hmac->digest_str);
g_slice_free (GHmac, hmac);
}
}
void
g_hmac_update (GHmac *hmac,
const guchar *data,
gssize length)
{
g_return_if_fail (hmac != NULL);
g_return_if_fail (length == 0 || data != NULL);
gnutls_hmac (hmac->hmac, data, length);
}
const gchar *
g_hmac_get_string (GHmac *hmac)
{
guint8 *buffer;
gsize digest_len;
g_return_val_if_fail (hmac != NULL, NULL);
if (hmac->digest_str)
return hmac->digest_str;
digest_len = g_checksum_type_get_length (hmac->digest_type);
buffer = g_alloca (digest_len);
gnutls_hmac_output (hmac->hmac, buffer);
hmac->digest_str = gchecksum_digest_to_string (buffer, digest_len);
return hmac->digest_str;
}
void
g_hmac_get_digest (GHmac *hmac,
guint8 *buffer,
gsize *digest_len)
{
g_return_if_fail (hmac != NULL);
gnutls_hmac_output (hmac->hmac, buffer);
*digest_len = g_checksum_type_get_length (hmac->digest_type);
}