text: /* $Id: digest-builtin.cpp $ */
  /** @file
   * IPRT - Crypto - Cryptographic Hash / Message Digest API, Built-in providers.
   */
  
  /*
   * Copyright (C) 2006-2015 Oracle Corporation
   *
   * This file is part of VirtualBox Open Source Edition (OSE), as
   * available from http://www.virtualbox.org. This file is free software;
   * you can redistribute it and/or modify it under the terms of the GNU
   * General Public License (GPL) as published by the Free Software
   * Foundation, in version 2 as it comes in the "COPYING" file of the
   * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
   * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
   *
   * The contents of this file may alternatively be used under the terms
   * of the Common Development and Distribution License Version 1.0
   * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
   * VirtualBox OSE distribution, in which case the provisions of the
   * CDDL are applicable instead of those of the GPL.
   *
   * You may elect to license modified versions of this file under the
   * terms and conditions of either the GPL or the CDDL or both.
   */
  
  
  /*******************************************************************************
  *   Header Files                                                               *
  *******************************************************************************/
  #include "internal/iprt.h"
  #include <iprt/crypto/digest.h>
  
  #include <iprt/err.h>
  #include <iprt/mem.h>
  #include <iprt/string.h>
  #include <iprt/md2.h>
  #include <iprt/md5.h>
  #include <iprt/sha.h>
  #include <iprt/crypto/pkix.h>
  
  #ifdef IPRT_WITH_OPENSSL
  # include "internal/iprt-openssl.h"
  # include <openssl/evp.h>
  #endif
  
  /*
   * MD2
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestMd2_Update(void *pvState, const void *pvData, size_t cbData)
  {
      RTMd2Update((PRTMD2CONTEXT)pvState, pvData, cbData);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestMd2_Final(void *pvState, uint8_t *pbHash)
  {
      RTMd2Final((PRTMD2CONTEXT)pvState, pbHash);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestMd2_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      AssertReturn(pvOpaque == NULL, VERR_INVALID_PARAMETER);
      RTMd2Init((PRTMD2CONTEXT)pvState);
      return VINF_SUCCESS;
  }
  
  /** MD2 alias ODIs. */
  static const char * const g_apszMd2Aliases[] =
  {
      RTCR_PKCS1_MD2_WITH_RSA_OID,
      "1.3.14.3.2.24" /* OIW md2WithRSASignature */,
      NULL
  };
  
  /** MD2 descriptor. */
  static RTCRDIGESTDESC const g_rtCrDigestMd2Desc =
  {
      "md2",
      "1.2.840.113549.2.2",
      g_apszMd2Aliases,
      RTDIGESTTYPE_MD2,
      RTMD2_HASH_SIZE,
      sizeof(RTMD2CONTEXT),
      0,
      rtCrDigestMd2_Update,
      rtCrDigestMd2_Final,
      rtCrDigestMd2_Init,
      NULL,
      NULL,
      NULL,
      NULL,
  };
  
  
  /*
   * MD5
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestMd5_Update(void *pvState, const void *pvData, size_t cbData)
  {
      RTMd5Update((PRTMD5CONTEXT)pvState, pvData, cbData);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestMd5_Final(void *pvState, uint8_t *pbHash)
  {
      RTMd5Final(pbHash, (PRTMD5CONTEXT)pvState);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestMd5_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      AssertReturn(pvOpaque == NULL, VERR_INVALID_PARAMETER);
      RTMd5Init((PRTMD5CONTEXT)pvState);
      return VINF_SUCCESS;
  }
  
  /** MD5 alias ODIs. */
  static const char * const g_apszMd5Aliases[] =
  {
      RTCR_PKCS1_MD5_WITH_RSA_OID,
      "1.3.14.3.2.25" /* OIW md5WithRSASignature */,
      NULL
  };
  
  /** MD5 descriptor. */
  static RTCRDIGESTDESC const g_rtCrDigestMd5Desc =
  {
      "md5",
      "1.2.840.113549.2.5",
      g_apszMd5Aliases,
      RTDIGESTTYPE_MD5,
      RTMD5_HASH_SIZE,
      sizeof(RTMD5CONTEXT),
      0,
      rtCrDigestMd5_Update,
      rtCrDigestMd5_Final,
      rtCrDigestMd5_Init,
      NULL,
      NULL,
      NULL,
      NULL,
  };
  
  
  /*
   * SHA-1
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestSha1_Update(void *pvState, const void *pvData, size_t cbData)
  {
      RTSha1Update((PRTSHA1CONTEXT)pvState, pvData, cbData);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestSha1_Final(void *pvState, uint8_t *pbHash)
  {
      RTSha1Final((PRTSHA1CONTEXT)pvState, pbHash);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestSha1_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      AssertReturn(pvOpaque == NULL, VERR_INVALID_PARAMETER);
      RTSha1Init((PRTSHA1CONTEXT)pvState);
      return VINF_SUCCESS;
  }
  
  /** SHA-1 alias ODIs. */
  static const char * const g_apszSha1Aliases[] =
  {
      RTCR_PKCS1_SHA1_WITH_RSA_OID,
      "1.3.14.3.2.29" /* OIW sha1WithRSASignature */,
      NULL
  };
  
  /** SHA-1 descriptor. */
  static RTCRDIGESTDESC const g_rtCrDigestSha1Desc =
  {
      "sha-1",
      "1.3.14.3.2.26",
      g_apszSha1Aliases,
      RTDIGESTTYPE_SHA1,
      RTSHA1_HASH_SIZE,
      sizeof(RTSHA1CONTEXT),
      0,
      rtCrDigestSha1_Update,
      rtCrDigestSha1_Final,
      rtCrDigestSha1_Init,
      NULL,
      NULL,
      NULL,
      NULL,
  };
  
  
  /*
   * SHA-256
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestSha256_Update(void *pvState, const void *pvData, size_t cbData)
  {
      RTSha256Update((PRTSHA256CONTEXT)pvState, pvData, cbData);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestSha256_Final(void *pvState, uint8_t *pbHash)
  {
      RTSha256Final((PRTSHA256CONTEXT)pvState, pbHash);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestSha256_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      AssertReturn(pvOpaque == NULL, VERR_INVALID_PARAMETER);
      RTSha256Init((PRTSHA256CONTEXT)pvState);
      return VINF_SUCCESS;
  }
  
  /** SHA-256 alias ODIs. */
  static const char * const g_apszSha256Aliases[] =
  {
      RTCR_PKCS1_SHA256_WITH_RSA_OID,
      NULL
  };
  
  /** SHA-256 descriptor. */
  static RTCRDIGESTDESC const g_rtCrDigestSha256Desc =
  {
      "sha-256",
      "2.16.840.1.101.3.4.2.1",
      g_apszSha256Aliases,
      RTDIGESTTYPE_SHA256,
      RTSHA256_HASH_SIZE,
      sizeof(RTSHA256CONTEXT),
      0,
      rtCrDigestSha256_Update,
      rtCrDigestSha256_Final,
      rtCrDigestSha256_Init,
      NULL,
      NULL,
      NULL,
      NULL,
  };
  
  
  /*
   * SHA-512
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestSha512_Update(void *pvState, const void *pvData, size_t cbData)
  {
      RTSha512Update((PRTSHA512CONTEXT)pvState, pvData, cbData);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestSha512_Final(void *pvState, uint8_t *pbHash)
  {
      RTSha512Final((PRTSHA512CONTEXT)pvState, pbHash);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestSha512_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      AssertReturn(pvOpaque == NULL, VERR_INVALID_PARAMETER);
      RTSha512Init((PRTSHA512CONTEXT)pvState);
      return VINF_SUCCESS;
  }
  
  /** SHA-512 alias ODIs. */
  static const char * const g_apszSha512Aliases[] =
  {
      RTCR_PKCS1_SHA512_WITH_RSA_OID,
      NULL
  };
  
  /** SHA-512 descriptor. */
  static RTCRDIGESTDESC const g_rtCrDigestSha512Desc =
  {
      "sha-512",
      "2.16.840.1.101.3.4.2.3",
      g_apszSha512Aliases,
      RTDIGESTTYPE_SHA512,
      RTSHA512_HASH_SIZE,
      sizeof(RTSHA512CONTEXT),
      0,
      rtCrDigestSha512_Update,
      rtCrDigestSha512_Final,
      rtCrDigestSha512_Init,
      NULL,
      NULL,
      NULL,
      NULL,
  };
  
  
  /*
   * SHA-224
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestSha224_Update(void *pvState, const void *pvData, size_t cbData)
  {
      RTSha224Update((PRTSHA224CONTEXT)pvState, pvData, cbData);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestSha224_Final(void *pvState, uint8_t *pbHash)
  {
      RTSha224Final((PRTSHA224CONTEXT)pvState, pbHash);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestSha224_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      AssertReturn(pvOpaque == NULL, VERR_INVALID_PARAMETER);
      RTSha224Init((PRTSHA224CONTEXT)pvState);
      return VINF_SUCCESS;
  }
  
  /** SHA-224 alias ODIs. */
  static const char * const g_apszSha224Aliases[] =
  {
      RTCR_PKCS1_SHA224_WITH_RSA_OID,
      NULL
  };
  
  /** SHA-224 descriptor. */
  static RTCRDIGESTDESC const g_rtCrDigestSha224Desc =
  {
      "sha-224",
      "2.16.840.1.101.3.4.2.4",
      g_apszSha224Aliases,
      RTDIGESTTYPE_SHA224,
      RTSHA224_HASH_SIZE,
      sizeof(RTSHA224CONTEXT),
      0,
      rtCrDigestSha224_Update,
      rtCrDigestSha224_Final,
      rtCrDigestSha224_Init,
      NULL,
      NULL,
      NULL,
      NULL,
  };
  
  
  /*
   * SHA-384
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestSha384_Update(void *pvState, const void *pvData, size_t cbData)
  {
      RTSha384Update((PRTSHA384CONTEXT)pvState, pvData, cbData);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestSha384_Final(void *pvState, uint8_t *pbHash)
  {
      RTSha384Final((PRTSHA384CONTEXT)pvState, pbHash);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestSha384_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      AssertReturn(pvOpaque == NULL, VERR_INVALID_PARAMETER);
      RTSha384Init((PRTSHA384CONTEXT)pvState);
      return VINF_SUCCESS;
  }
  
  /** SHA-384 alias ODIs. */
  static const char * const g_apszSha384Aliases[] =
  {
      RTCR_PKCS1_SHA384_WITH_RSA_OID,
      NULL
  };
  
  /** SHA-384 descriptor. */
  static RTCRDIGESTDESC const g_rtCrDigestSha384Desc =
  {
      "sha-384",
      "2.16.840.1.101.3.4.2.2",
      g_apszSha384Aliases,
      RTDIGESTTYPE_SHA384,
      RTSHA384_HASH_SIZE,
      sizeof(RTSHA384CONTEXT),
      0,
      rtCrDigestSha384_Update,
      rtCrDigestSha384_Final,
      rtCrDigestSha384_Init,
      NULL,
      NULL,
      NULL,
      NULL,
  };
  
  
  #ifndef IPRT_WITHOUT_SHA512T224
  /*
   * SHA-512/224
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestSha512t224_Update(void *pvState, const void *pvData, size_t cbData)
  {
      RTSha512t224Update((PRTSHA512T224CONTEXT)pvState, pvData, cbData);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestSha512t224_Final(void *pvState, uint8_t *pbHash)
  {
      RTSha512t224Final((PRTSHA512T224CONTEXT)pvState, pbHash);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestSha512t224_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      AssertReturn(pvOpaque == NULL, VERR_INVALID_PARAMETER);
      RTSha512t224Init((PRTSHA512T224CONTEXT)pvState);
      return VINF_SUCCESS;
  }
  
  /** SHA-512/224 alias ODIs. */
  static const char * const g_apszSha512t224Aliases[] =
  {
      NULL
  };
  
  /** SHA-512/224 descriptor. */
  static RTCRDIGESTDESC const g_rtCrDigestSha512t224Desc =
  {
      "sha-512/224",
      "2.16.840.1.101.3.4.2.5",
      g_apszSha512t224Aliases,
      RTDIGESTTYPE_SHA512T224,
      RTSHA512T224_HASH_SIZE,
      sizeof(RTSHA512T224CONTEXT),
      0,
      rtCrDigestSha512t224_Update,
      rtCrDigestSha512t224_Final,
      rtCrDigestSha512t224_Init,
      NULL,
      NULL,
      NULL,
      NULL,
  };
  #endif /* !IPRT_WITHOUT_SHA512T224 */
  
  
  #ifndef IPRT_WITHOUT_SHA512T256
  /*
   * SHA-512/256
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestSha512t256_Update(void *pvState, const void *pvData, size_t cbData)
  {
      RTSha512t256Update((PRTSHA512T256CONTEXT)pvState, pvData, cbData);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestSha512t256_Final(void *pvState, uint8_t *pbHash)
  {
      RTSha512t256Final((PRTSHA512T256CONTEXT)pvState, pbHash);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestSha512t256_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      AssertReturn(pvOpaque == NULL, VERR_INVALID_PARAMETER);
      RTSha512t256Init((PRTSHA512T256CONTEXT)pvState);
      return VINF_SUCCESS;
  }
  
  /** SHA-512/256 alias ODIs. */
  static const char * const g_apszSha512t256Aliases[] =
  {
      NULL
  };
  
  /** SHA-512/256 descriptor. */
  static RTCRDIGESTDESC const g_rtCrDigestSha512t256Desc =
  {
      "sha-512/256",
      "2.16.840.1.101.3.4.2.6",
      g_apszSha512t256Aliases,
      RTDIGESTTYPE_SHA512T256,
      RTSHA512T256_HASH_SIZE,
      sizeof(RTSHA512T256CONTEXT),
      0,
      rtCrDigestSha512t256_Update,
      rtCrDigestSha512t256_Final,
      rtCrDigestSha512t256_Init,
      NULL,
      NULL,
      NULL,
      NULL,
  };
  #endif /* !IPRT_WITHOUT_SHA512T256 */
  
  
  /**
   * Array of built in message digest vtables.
   */
  static PCRTCRDIGESTDESC const g_apDigestOps[] =
  {
      &g_rtCrDigestMd2Desc,
      &g_rtCrDigestMd5Desc,
      &g_rtCrDigestSha1Desc,
      &g_rtCrDigestSha256Desc,
      &g_rtCrDigestSha512Desc,
      &g_rtCrDigestSha224Desc,
      &g_rtCrDigestSha384Desc,
  #ifndef IPRT_WITHOUT_SHA512T224
      &g_rtCrDigestSha512t224Desc,
  #endif
  #ifndef IPRT_WITHOUT_SHA512T256
      &g_rtCrDigestSha512t256Desc,
  #endif
  };
  
  
  #ifdef IPRT_WITH_OPENSSL
  /*
   * OpenSSL EVP.
   */
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnUpdate} */
  static DECLCALLBACK(void) rtCrDigestOsslEvp_Update(void *pvState, const void *pvData, size_t cbData)
  {
      EVP_DigestUpdate((EVP_MD_CTX *)pvState, pvData, cbData);
  }
  
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnFinal} */
  static DECLCALLBACK(void) rtCrDigestOsslEvp_Final(void *pvState, uint8_t *pbHash)
  {
      unsigned int cbHash = EVP_MAX_MD_SIZE;
      EVP_DigestFinal((EVP_MD_CTX *)pvState, (unsigned char *)pbHash, &cbHash);
  }
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnInit} */
  static DECLCALLBACK(int) rtCrDigestOsslEvp_Init(void *pvState, void *pvOpaque, bool fReInit)
  {
      EVP_MD_CTX   *pThis    = (EVP_MD_CTX *)pvState;
      EVP_MD const *pEvpType = (EVP_MD const *)pvOpaque;
  
      if (fReInit)
      {
          pEvpType = EVP_MD_CTX_md(pThis);
          EVP_MD_CTX_cleanup(pThis);
      }
  
      AssertPtrReturn(pEvpType, VERR_INVALID_PARAMETER);
      Assert(pEvpType->md_size);
      if (EVP_DigestInit(pThis, pEvpType))
          return VINF_SUCCESS;
      return VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR;
  }
  
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfn} */
  static DECLCALLBACK(void) rtCrDigestOsslEvp_Delete(void *pvState)
  {
      EVP_MD_CTX *pThis = (EVP_MD_CTX *)pvState;
      EVP_MD_CTX_cleanup(pThis);
  }
  
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnClone} */
  static DECLCALLBACK(int) rtCrDigestOsslEvp_Clone(void *pvState, void const *pvSrcState)
  {
      EVP_MD_CTX        *pThis = (EVP_MD_CTX *)pvState;
      EVP_MD_CTX const  *pSrc  = (EVP_MD_CTX const *)pvSrcState;
  
      if (EVP_MD_CTX_copy(pThis, pSrc))
          return VINF_SUCCESS;
      return VERR_CR_DIGEST_OSSL_DIGEST_CTX_COPY_ERROR;
  }
  
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnGetHashSize} */
  static DECLCALLBACK(uint32_t) rtCrDigestOsslEvp_GetHashSize(void *pvState)
  {
      EVP_MD_CTX *pThis = (EVP_MD_CTX *)pvState;
      return EVP_MD_size(EVP_MD_CTX_md(pThis));
  }
  
  
  /** @impl_interface_method{RTCRDIGESTDESC::pfnGetHashSize} */
  static DECLCALLBACK(RTDIGESTTYPE) rtCrDigestOsslEvp_GetDigestType(void *pvState)
  {
      EVP_MD_CTX *pThis = (EVP_MD_CTX *)pvState;
      /** @todo figure which digest algorithm it is! */
      return RTDIGESTTYPE_UNKNOWN;
  }
  
  
  /** Descriptor for the OpenSSL EVP base message digest provider. */
  static RTCRDIGESTDESC const g_rtCrDigestOpenSslDesc =
  {
      "OpenSSL EVP",
      NULL,
      NULL,
      RTDIGESTTYPE_UNKNOWN,
      EVP_MAX_MD_SIZE,
      sizeof(EVP_MD_CTX),
      0,
      rtCrDigestOsslEvp_Update,
      rtCrDigestOsslEvp_Final,
      rtCrDigestOsslEvp_Init,
      rtCrDigestOsslEvp_Delete,
      rtCrDigestOsslEvp_Clone,
      rtCrDigestOsslEvp_GetHashSize,
      rtCrDigestOsslEvp_GetDigestType
  };
  
  #endif /* IPRT_WITH_OPENSSL */
  
  
  RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjIdString(const char *pszObjId, void **ppvOpaque)
  {
      if (ppvOpaque)
          *ppvOpaque = NULL;
  
      /*
       * Primary OIDs.
       */
      uint32_t i = RT_ELEMENTS(g_apDigestOps);
      while (i-- > 0)
          if (strcmp(g_apDigestOps[i]->pszObjId, pszObjId) == 0)
              return g_apDigestOps[i];
  
      /*
       * Alias OIDs.
       */
      i = RT_ELEMENTS(g_apDigestOps);
      while (i-- > 0)
      {
          const char * const *ppszAliases = g_apDigestOps[i]->papszObjIdAliases;
          if (ppszAliases)
              for (; *ppszAliases; ppszAliases++)
                  if (strcmp(*ppszAliases, pszObjId) == 0)
                      return g_apDigestOps[i];
      }
  
  #ifdef IPRT_WITH_OPENSSL
      /*
       * Try EVP and see if it knows the algorithm.
       */
      if (ppvOpaque)
      {
          rtCrOpenSslInit();
          int iAlgoNid = OBJ_txt2nid(pszObjId);
          if (iAlgoNid != NID_undef)
          {
              const char *pszAlogSn = OBJ_nid2sn(iAlgoNid);
              const EVP_MD *pEvpMdType = EVP_get_digestbyname(pszAlogSn);
              if (pEvpMdType)
              {
                  /*
                   * Return the OpenSSL provider descriptor and the EVP_MD address.
                   */
                  Assert(pEvpMdType->md_size);
                  *ppvOpaque = (void *)pEvpMdType;
                  return &g_rtCrDigestOpenSslDesc;
              }
          }
      }
  #endif
      return NULL;
  }
  
  
  RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByObjId(PCRTASN1OBJID pObjId, void **ppvOpaque)
  {
      return RTCrDigestFindByObjIdString(pObjId->szObjId, ppvOpaque);
  }
  
  
  RTDECL(int) RTCrDigestCreateByObjIdString(PRTCRDIGEST phDigest, const char *pszObjId)
  {
      void *pvOpaque;
      PCRTCRDIGESTDESC pDesc = RTCrDigestFindByObjIdString(pszObjId, &pvOpaque);
      if (pDesc)
          return RTCrDigestCreate(phDigest, pDesc, pvOpaque);
      return VERR_NOT_FOUND;
  }
  
  
  RTDECL(int) RTCrDigestCreateByObjId(PRTCRDIGEST phDigest, PCRTASN1OBJID pObjId)
  {
      void *pvOpaque;
      PCRTCRDIGESTDESC pDesc = RTCrDigestFindByObjId(pObjId, &pvOpaque);
      if (pDesc)
          return RTCrDigestCreate(phDigest, pDesc, pvOpaque);
      return VERR_NOT_FOUND;
  }
  
  
  RTDECL(PCRTCRDIGESTDESC) RTCrDigestFindByType(RTDIGESTTYPE enmDigestType)
  {
      AssertReturn(enmDigestType > RTDIGESTTYPE_INVALID && enmDigestType <= RTDIGESTTYPE_END, NULL);
  
      uint32_t i = RT_ELEMENTS(g_apDigestOps);
      while (i-- > 0)
          if (g_apDigestOps[i]->enmType == enmDigestType)
              return g_apDigestOps[i];
      return NULL;
  }
  
  
  RTDECL(int) RTCrDigestCreateByType(PRTCRDIGEST phDigest, RTDIGESTTYPE enmDigestType)
  {
      PCRTCRDIGESTDESC pDesc = RTCrDigestFindByType(enmDigestType);
      if (pDesc)
          return RTCrDigestCreate(phDigest, pDesc, NULL);
      return VERR_NOT_FOUND;
  }
  
  