/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/mscng/digests.c
554 строки
18 KB
lsh123
(xmlsec-core) Added xmlSecMemEqual to compare two buffers in constant time and upgraded the code to use it (#1191)
30 май 2026, 05:26
Не верифицирован
30 май 2026, 05:26
0fb64f6
Код
Авторство
О чём код?
/** * XML Security Library (http://www.aleksey.com/xmlsec). * * This is free software; see the Copyright file in the source distribution for precise wording. * * Copyright (C) 2018-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved. * Copyright (C) 2018 Miklos Vajna. All Rights Reserved. */ /** * @addtogroup xmlsec_mscng_crypto * @brief Digests transforms implementation for MSCng. */ #include "globals.h" #include <string.h> #include <xmlsec/xmlsec.h> #include <xmlsec/buffer.h> #include <xmlsec/keys.h> #include <xmlsec/transforms.h> #include <xmlsec/errors.h> #include <xmlsec/strings.h> #include <xmlsec/mscng/crypto.h> #include "../cast_helpers.h" typedef struct _xmlSecMSCngDigestCtx xmlSecMSCngDigestCtx, *xmlSecMSCngDigestCtxPtr; struct _xmlSecMSCngDigestCtx { LPCWSTR pszAlgId; DWORD cbHash; PBYTE pbHash; BCRYPT_ALG_HANDLE hAlg; PBYTE pbHashObject; BCRYPT_HASH_HANDLE hHash; }; /****************************************************************************** * * MSCng Digest transforms * *****************************************************************************/ XMLSEC_TRANSFORM_DECLARE(MSCngDigest, xmlSecMSCngDigestCtx) #define xmlSecMSCngDigestSize XMLSEC_TRANSFORM_SIZE(MSCngDigest) static int xmlSecMSCngDigestInitialize (xmlSecTransformPtr transform); static void xmlSecMSCngDigestFinalize (xmlSecTransformPtr transform); static int xmlSecMSCngDigestVerify (xmlSecTransformPtr transform, const xmlSecByte* data, xmlSecSize dataSize, xmlSecTransformCtxPtr transformCtx); static int xmlSecMSCngDigestExecute (xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx); static int xmlSecMSCngDigestCheckId (xmlSecTransformPtr transform); #define XMLSEC_MSCNG_DIGEST_KLASS_EX(name) \ static xmlSecTransformKlass xmlSecMSCng ## name ## Klass = { \ sizeof(xmlSecTransformKlass), /* size_t klassSize */ \ xmlSecMSCngDigestSize, /* size_t objSize */ \ \ xmlSecName ## name, /* const xmlChar* name; */ \ xmlSecHref ## name, /* const xmlChar* href; */ \ xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ \ xmlSecMSCngDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ \ xmlSecMSCngDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ \ NULL, /* xmlSecTransformNodeReadMethod readNode; */ \ NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ \ NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ \ NULL, /* xmlSecTransformSetKeyMethod setKey; */ \ xmlSecMSCngDigestVerify, /* xmlSecTransformVerifyMethod verify; */ \ xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ \ xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ \ xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ \ NULL, /* xmlSecTransformPushXmlMethod pushXml; */ \ NULL, /* xmlSecTransformPopXmlMethod popXml; */ \ xmlSecMSCngDigestExecute, /* xmlSecTransformExecuteMethod execute; */ \ NULL, /* void* reserved0; */ \ NULL, /* void* reserved1; */ \ }; static int xmlSecMSCngDigestCheckId(xmlSecTransformPtr transform) { #ifndef XMLSEC_NO_MD5 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformMd5Id)) { return(1); } else #endif /* XMLSEC_NO_MD5 */ #ifndef XMLSEC_NO_SHA1 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha1Id)) { return(1); } else #endif /* XMLSEC_NO_SHA1 */ #ifndef XMLSEC_NO_SHA256 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha256Id)) { return(1); } else #endif /* XMLSEC_NO_SHA256 */ #ifndef XMLSEC_NO_SHA384 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha384Id)) { return(1); } else #endif /* XMLSEC_NO_SHA384 */ #ifndef XMLSEC_NO_SHA512 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha512Id)) { return(1); } else #endif /* XMLSEC_NO_SHA512 */ #ifndef XMLSEC_NO_SHA3 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha3_256Id)) { return(1); } else if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha3_384Id)) { return(1); } else if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha3_512Id)) { return(1); } else #endif /* XMLSEC_NO_SHA3 */ return(0); } static int xmlSecMSCngDigestInitialize(xmlSecTransformPtr transform) { xmlSecMSCngDigestCtxPtr ctx; xmlSecAssert2(xmlSecMSCngDigestCheckId(transform), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCngDigestSize), -1); ctx = xmlSecMSCngDigestGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); /* initialize context */ memset(ctx, 0, sizeof(xmlSecMSCngDigestCtx)); #ifndef XMLSEC_NO_MD5 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformMd5Id)) { ctx->pszAlgId = BCRYPT_MD5_ALGORITHM; } else #endif /* XMLSEC_NO_MD5 */ #ifndef XMLSEC_NO_SHA1 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha1Id)) { ctx->pszAlgId = BCRYPT_SHA1_ALGORITHM; } else #endif /* XMLSEC_NO_SHA1 */ #ifndef XMLSEC_NO_SHA256 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha256Id)) { ctx->pszAlgId = BCRYPT_SHA256_ALGORITHM; } else #endif /* XMLSEC_NO_SHA256 */ #ifndef XMLSEC_NO_SHA384 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha384Id)) { ctx->pszAlgId = BCRYPT_SHA384_ALGORITHM; } else #endif /* XMLSEC_NO_SHA384 */ #ifndef XMLSEC_NO_SHA512 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha512Id)) { ctx->pszAlgId = BCRYPT_SHA512_ALGORITHM; } else #endif /* XMLSEC_NO_SHA512 */ #ifndef XMLSEC_NO_SHA3 if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha3_256Id)) { ctx->pszAlgId = BCRYPT_SHA3_256_ALGORITHM; } else if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha3_384Id)) { ctx->pszAlgId = BCRYPT_SHA3_384_ALGORITHM; } else if(xmlSecTransformCheckId(transform, xmlSecMSCngTransformSha3_512Id)) { ctx->pszAlgId = BCRYPT_SHA3_512_ALGORITHM; } else #endif /* XMLSEC_NO_SHA3 */ { xmlSecInvalidTransfromError(transform); return(-1); } return(0); } static void xmlSecMSCngDigestFinalize(xmlSecTransformPtr transform) { xmlSecMSCngDigestCtxPtr ctx; xmlSecAssert(xmlSecMSCngDigestCheckId(transform)); xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCngDigestSize)); ctx = xmlSecMSCngDigestGetCtx(transform); xmlSecAssert(ctx != NULL); if(ctx->hAlg != 0) { BCryptCloseAlgorithmProvider(ctx->hAlg, 0); } if(ctx->hHash != 0) { BCryptDestroyHash(ctx->hHash); } if(ctx->pbHashObject != NULL) { xmlFree(ctx->pbHashObject); } if(ctx->pbHash != NULL) { xmlFree(ctx->pbHash); } memset(ctx, 0, sizeof(xmlSecMSCngDigestCtx)); } static int xmlSecMSCngDigestVerify(xmlSecTransformPtr transform, const xmlSecByte* data, xmlSecSize dataSize, xmlSecTransformCtxPtr transformCtx) { xmlSecMSCngDigestCtxPtr ctx; xmlSecSize hashSize; int ret; xmlSecAssert2(xmlSecMSCngDigestCheckId(transform), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCngDigestSize), -1); xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); xmlSecAssert2(data != NULL, -1); xmlSecAssert2(transformCtx != NULL, -1); ctx = xmlSecMSCngDigestGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->cbHash > 0, -1); XMLSEC_SAFE_CAST_ULONG_TO_SIZE(ctx->cbHash, hashSize, return(-1), xmlSecTransformGetName(transform)); if(dataSize != hashSize) { xmlSecInvalidSizeError("Digest", dataSize, hashSize, xmlSecTransformGetName(transform)); transform->status = xmlSecTransformStatusFail; return(0); } ret = xmlSecMemEqual(ctx->pbHash, data, hashSize); if(ret < 0) { xmlSecInternalError("xmlSecMemEqual", xmlSecTransformGetName(transform)); return(-1); } if(ret == 0) { xmlSecInvalidDataError("data and digest do not match", xmlSecTransformGetName(transform)); transform->status = xmlSecTransformStatusFail; return(0); } transform->status = xmlSecTransformStatusOk; return(0); } static int xmlSecMSCngDigestExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { xmlSecMSCngDigestCtxPtr ctx; xmlSecBufferPtr in, out; NTSTATUS status; int ret; DWORD cbData = 0; DWORD cbHashObject = 0; xmlSecAssert2(xmlSecMSCngDigestCheckId(transform), -1); xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCngDigestSize), -1); xmlSecAssert2(transformCtx != NULL, -1); in = &(transform->inBuf); xmlSecAssert2(in != NULL, -1); out = &(transform->outBuf); xmlSecAssert2(out != NULL, -1); ctx = xmlSecMSCngDigestGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); if(transform->status == xmlSecTransformStatusNone) { /* open an algorithm handle */ status = BCryptOpenAlgorithmProvider( &ctx->hAlg, ctx->pszAlgId, NULL, 0); if(status != STATUS_SUCCESS) { xmlSecMSCngNtError("BCryptOpenAlgorithmProvider", xmlSecTransformGetName(transform), status); return(-1); } /* calculate the size of the buffer to hold the hash object */ status = BCryptGetProperty( ctx->hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0); if(status != STATUS_SUCCESS) { xmlSecMSCngNtError("BCryptGetProperty", xmlSecTransformGetName(transform), status); return(-1); } /* allocate the hash object on the heap */ ctx->pbHashObject = (PBYTE)xmlMalloc(cbHashObject); if(ctx->pbHashObject == NULL) { xmlSecMallocError(cbHashObject, NULL); return(-1); } /* calculate the length of the hash */ status = BCryptGetProperty( ctx->hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&ctx->cbHash, sizeof(DWORD), &cbData, 0); if(status != STATUS_SUCCESS) { xmlSecMSCngNtError("BCryptGetProperty", xmlSecTransformGetName(transform), status); return(-1); } /* allocate the hash buffer on the heap */ ctx->pbHash = (PBYTE)xmlMalloc(ctx->cbHash); if(ctx->pbHash == NULL) { xmlSecMallocError(ctx->cbHash, NULL); return(-1); } /* create the hash */ status = BCryptCreateHash( ctx->hAlg, &ctx->hHash, ctx->pbHashObject, cbHashObject, NULL, 0, 0); if(status != STATUS_SUCCESS) { xmlSecMSCngNtError("BCryptCreateHash", xmlSecTransformGetName(transform), status); return(-1); } transform->status = xmlSecTransformStatusWorking; } if(transform->status == xmlSecTransformStatusWorking) { xmlSecSize inSize; inSize = xmlSecBufferGetSize(in); if(inSize > 0) { DWORD dwInSize; /* hash some data */ XMLSEC_SAFE_CAST_SIZE_TO_ULONG(inSize, dwInSize, return(-1), xmlSecTransformGetName(transform)); status = BCryptHashData( ctx->hHash, (PBYTE)xmlSecBufferGetData(in), dwInSize, 0); if(status != STATUS_SUCCESS) { xmlSecMSCngNtError("BCryptHashData", xmlSecTransformGetName(transform), status); return(-1); } ret = xmlSecBufferRemoveHead(in, inSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferRemoveHead", xmlSecTransformGetName(transform)); return(-1); } } if(last) { /* close the hash */ status = BCryptFinishHash( ctx->hHash, ctx->pbHash, ctx->cbHash, 0); if(status != STATUS_SUCCESS) { xmlSecMSCngNtError("BCryptFinishHash", xmlSecTransformGetName(transform), status); return(-1); } xmlSecAssert2(ctx->cbHash > 0, -1); /* copy result to output */ if(transform->operation == xmlSecTransformOperationSign) { ret = xmlSecBufferAppend(out, ctx->pbHash, ctx->cbHash); if(ret < 0) { xmlSecInternalError("xmlSecBufferAppend", xmlSecTransformGetName(transform)); return(-1); } } transform->status = xmlSecTransformStatusFinished; } } else if(transform->status == xmlSecTransformStatusFinished) { xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); } else { xmlSecInvalidTransfromStatusError(transform); return(-1); } return(0); } #ifndef XMLSEC_NO_MD5 /****************************************************************************** * * MD5 * *****************************************************************************/ XMLSEC_MSCNG_DIGEST_KLASS_EX(Md5) /** * @brief MD-5 digest transform klass. * @return pointer to MD-5 digest transform klass. */ xmlSecTransformId xmlSecMSCngTransformMd5GetKlass(void) { return(&xmlSecMSCngMd5Klass); } #endif /* XMLSEC_NO_MD5 */ #ifndef XMLSEC_NO_SHA1 /****************************************************************************** * * SHA1 * *****************************************************************************/ XMLSEC_MSCNG_DIGEST_KLASS_EX(Sha1) /** * @brief SHA-1 digest transform klass. * @return pointer to SHA-1 digest transform klass. */ xmlSecTransformId xmlSecMSCngTransformSha1GetKlass(void) { return(&xmlSecMSCngSha1Klass); } #endif /* XMLSEC_NO_SHA1 */ #ifndef XMLSEC_NO_SHA256 /****************************************************************************** * * SHA256 * *****************************************************************************/ XMLSEC_MSCNG_DIGEST_KLASS_EX(Sha256) /** * @brief SHA-256 digest transform klass. * @return pointer to SHA-256 digest transform klass. */ xmlSecTransformId xmlSecMSCngTransformSha256GetKlass(void) { return(&xmlSecMSCngSha256Klass); } #endif /* XMLSEC_NO_SHA256 */ #ifndef XMLSEC_NO_SHA384 /****************************************************************************** * * SHA384 * *****************************************************************************/ XMLSEC_MSCNG_DIGEST_KLASS_EX(Sha384) /** * @brief SHA-384 digest transform klass. * @return pointer to SHA-256 digest transform klass. */ xmlSecTransformId xmlSecMSCngTransformSha384GetKlass(void) { return(&xmlSecMSCngSha384Klass); } #endif /* XMLSEC_NO_SHA384 */ #ifndef XMLSEC_NO_SHA512 /****************************************************************************** * * SHA512 * *****************************************************************************/ XMLSEC_MSCNG_DIGEST_KLASS_EX(Sha512) /** * @brief SHA-512 digest transform klass. * @return pointer to SHA-512 digest transform klass. */ xmlSecTransformId xmlSecMSCngTransformSha512GetKlass(void) { return(&xmlSecMSCngSha512Klass); } #endif /* XMLSEC_NO_SHA512 */ #ifndef XMLSEC_NO_SHA3 /****************************************************************************** * * SHA3-256 * *****************************************************************************/ XMLSEC_MSCNG_DIGEST_KLASS_EX(Sha3_256) /** * @brief SHA3-256 digest transform klass. * @return pointer to SHA3-256 digest transform klass. */ xmlSecTransformId xmlSecMSCngTransformSha3_256GetKlass(void) { return(&xmlSecMSCngSha3_256Klass); } /****************************************************************************** * * SHA3-384 * *****************************************************************************/ XMLSEC_MSCNG_DIGEST_KLASS_EX(Sha3_384) /** * @brief SHA3-384 digest transform klass. * @return pointer to SHA3-384 digest transform klass. */ xmlSecTransformId xmlSecMSCngTransformSha3_384GetKlass(void) { return(&xmlSecMSCngSha3_384Klass); } /****************************************************************************** * * SHA3-512 * *****************************************************************************/ XMLSEC_MSCNG_DIGEST_KLASS_EX(Sha3_512) /** * @brief SHA3-512 digest transform klass. * @return pointer to SHA3-512 digest transform klass. */ xmlSecTransformId xmlSecMSCngTransformSha3_512GetKlass(void) { return(&xmlSecMSCngSha3_512Klass); } #endif /* XMLSEC_NO_SHA3 */