Function: gnutls-hash-mac

gnutls-hash-mac is a function defined in gnutls.c.

Signature

(gnutls-hash-mac HASH-METHOD KEY INPUT)

Documentation

Hash INPUT with HASH-METHOD and KEY into a unibyte string.

Return nil on error.

The KEY can be specified as a buffer or string or in other ways (see Info node (elisp)Format of GnuTLS Cryptography Inputs). The KEY will be wiped after use if it's a string.

The INPUT can also be specified as a buffer or string or in other ways.

The alist of MAC algorithms can be obtained with gnutls-macs. The HASH-METHOD may be a string or symbol matching a key in that alist, or a plist with the :mac-algorithm-id numeric property, or the number itself.

Probably introduced at or before Emacs version 26.1.

Source Code

// Defined in /usr/src/emacs/src/gnutls.c
{
  if (BUFFERP (input) || STRINGP (input))
    input = list1 (input);

  CHECK_CONS (input);

  if (BUFFERP (key) || STRINGP (key))
    key = list1 (key);

  CHECK_CONS (key);

  gnutls_mac_algorithm_t gma = GNUTLS_MAC_UNKNOWN;

  Lisp_Object info = Qnil;
  if (STRINGP (hash_method))
    hash_method = intern (SSDATA (hash_method));

  if (SYMBOLP (hash_method))
    {
      info = Fassq (hash_method, Fgnutls_macs ());
      if (!CONSP (info))
	xsignal2 (Qerror,
		  build_string ("GnuTLS MAC-method is invalid or not found"),
		  hash_method);
      info = XCDR (info);
    }
  else if (TYPE_RANGED_FIXNUMP (gnutls_mac_algorithm_t, hash_method))
    gma = XFIXNUM (hash_method);
  else
    info = hash_method;

  if (!NILP (info) && CONSP (info))
    {
      Lisp_Object v = plist_get (info, QCmac_algorithm_id);
      if (TYPE_RANGED_FIXNUMP (gnutls_mac_algorithm_t, v))
        gma = XFIXNUM (v);
    }

  ptrdiff_t digest_length = gnutls_hmac_get_len (gma);
  if (digest_length == 0)
    xsignal2 (Qerror,
	      build_string ("GnuTLS MAC-method is invalid or not found"),
	      hash_method);

  ptrdiff_t kstart_byte, kend_byte;
  const char *kdata = extract_data_from_object (key, &kstart_byte, &kend_byte);
  if (kdata == NULL)
    error ("GnuTLS MAC key extraction failed");

  gnutls_hmac_hd_t hmac;
  int ret = gnutls_hmac_init (&hmac, gma,
			      kdata + kstart_byte, kend_byte - kstart_byte);
  if (ret < GNUTLS_E_SUCCESS)
    error ("GnuTLS MAC %s initialization failed: %s",
	   gnutls_mac_get_name (gma), emacs_gnutls_strerror (ret));

  ptrdiff_t istart_byte, iend_byte;
  const char *idata
    = extract_data_from_object (input, &istart_byte, &iend_byte);
  if (idata == NULL)
    error ("GnuTLS MAC input extraction failed");

  Lisp_Object digest = make_uninit_string (digest_length);

  ret = gnutls_hmac (hmac, idata + istart_byte, iend_byte - istart_byte);

  if (STRINGP (XCAR (key)))
    Fclear_string (XCAR (key));

  if (ret < GNUTLS_E_SUCCESS)
    {
      gnutls_hmac_deinit (hmac, NULL);
      error ("GnuTLS MAC %s application failed: %s",
	     gnutls_mac_get_name (gma), emacs_gnutls_strerror (ret));
    }

  gnutls_hmac_output (hmac, SSDATA (digest));
  gnutls_hmac_deinit (hmac, NULL);

  return digest;
}