Function: gnutls-hash-digest

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

Signature

(gnutls-hash-digest DIGEST-METHOD INPUT)

Documentation

Digest INPUT with DIGEST-METHOD into a unibyte string.

Return nil on error.

The INPUT can be specified as a buffer or string or in other ways (see Info node (elisp)Format of GnuTLS Cryptography Inputs).

The alist of digest algorithms can be obtained with gnutls-digests. The DIGEST-METHOD may be a string or symbol matching a key in that alist, or a plist with the :digest-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);

  gnutls_digest_algorithm_t gda = GNUTLS_DIG_UNKNOWN;

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

  if (SYMBOLP (digest_method))
    {
      info = Fassq (digest_method, Fgnutls_digests ());
      if (!CONSP (info))
	xsignal2 (Qerror,
		  build_string ("GnuTLS digest-method is invalid or not found"),
		  digest_method);
      info = XCDR (info);
    }
  else if (TYPE_RANGED_FIXNUMP (gnutls_digest_algorithm_t, digest_method))
    gda = XFIXNUM (digest_method);
  else
    info = digest_method;

  if (!NILP (info) && CONSP (info))
    {
      Lisp_Object v = plist_get (info, QCdigest_algorithm_id);
      if (TYPE_RANGED_FIXNUMP (gnutls_digest_algorithm_t, v))
        gda = XFIXNUM (v);
    }

  ptrdiff_t digest_length = gnutls_hash_get_len (gda);
  if (digest_length == 0)
    xsignal2 (Qerror,
	      build_string ("GnuTLS digest-method is invalid or not found"),
	      digest_method);

  gnutls_hash_hd_t hash;
  int ret = gnutls_hash_init (&hash, gda);

  if (ret < GNUTLS_E_SUCCESS)
    error ("GnuTLS digest initialization failed: %s",
	   emacs_gnutls_strerror (ret));

  Lisp_Object digest = make_uninit_string (digest_length);

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

  ret = gnutls_hash (hash, idata + istart_byte, iend_byte - istart_byte);

  if (ret < GNUTLS_E_SUCCESS)
    {
      gnutls_hash_deinit (hash, NULL);
      error ("GnuTLS digest application failed: %s",
	     emacs_gnutls_strerror (ret));
    }

  gnutls_hash_output (hash, SSDATA (digest));
  gnutls_hash_deinit (hash, NULL);

  return digest;
}