00001
00010 #include "PKIFCNGCAPIRaw.h"
00011 #include "PKIFCAPICryptContext2.h"
00012 #include "PKIFCAPIHashContext.h"
00013 #include "CAPIUtils.h"
00014
00015 #include "PKIFCryptoException.h"
00016 #include "PKIFKeyMaterial.h"
00017 #include "PKIFCryptoErrors.h"
00018 #include "PKIFCAPIErrors.h"
00019 #include "CAPIRawCryptContext.h"
00020 #include "Buffer.h"
00021
00022 #include "AlgorithmIdentifier.h"
00023 #include "Certificate.h"
00024 #include "ToolkitUtils.h"
00025 #include "components.h"
00026 #include "PKIFException.h"
00027
00028 #include "SubjectPublicKeyInfo.h"
00029
00030 #include "ASN1Helper.h"
00031 #include "PKIX1Algorithms88.h"
00032
00033 #include <iostream>
00034 #include <sstream>
00035
00036 #include "PKIFCNGUtils.h"
00037 #include "PKIFBCryptPublicKey.h"
00038
00039 #include "dsa.h"
00040
00041 #include "boost/numeric/conversion/cast.hpp"
00042
00043 using boost::numeric_cast;
00044 using boost::bad_numeric_cast;
00045
00046 using namespace std;
00047
00048 #ifndef STATUS_NOT_SUPPORTED
00049 #define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
00050 #endif
00051 #ifndef STATUS_BUFFER_TOO_SMALL
00052 #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
00053 #endif
00054
00055
00056
00057 #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
00058 #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
00059
00061 struct CPKIFCNGCAPIRawImpl
00062 {
00063
00064 CPKIFCNGCAPIRaw* m_parent;
00072 CPKIFCNGCAPIRawImpl ()
00073 {
00074 m_parent = NULL;
00075 }
00083 CPKIFCNGCAPIRawImpl (CPKIFCNGCAPIRaw *p)
00084 {
00085 m_parent = p;
00086 }
00088 HCRYPTPROV m_hProv;
00090 HCRYPTKEY m_hPubPrivKey;
00091
00092 template<bool _CryptDirection>
00093 void AsymCrypt(const CPKIFKeyMaterial& key, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool pad = true);
00094
00095 template <bool _CryptDirection>
00096 void CryptFunc(IPKIFRawCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final);
00097
00098 };
00100
00109 CPKIFCNGCAPIRaw::CPKIFCNGCAPIRaw(void)
00110 :m_impl (new CPKIFCNGCAPIRawImpl)
00111 {
00112 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::CPKIFCNGCAPIRaw(void)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00113
00114 m_impl->m_parent = this;
00115 m_impl->m_hProv = NULL;
00116 m_impl->m_hPubPrivKey = NULL;
00117 }
00125 CPKIFCNGCAPIRaw::~CPKIFCNGCAPIRaw(void)
00126 {
00127 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::~CPKIFCNGCAPIRaw(void)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00128
00129 if(NULL != m_impl->m_hPubPrivKey)
00130 {
00131 BOOL succ = CryptDestroyKey(m_impl->m_hPubPrivKey);
00132 m_impl->m_hPubPrivKey = NULL;
00133 }
00134 if(NULL != m_impl->m_hProv)
00135 {
00136 BOOL succ = CryptReleaseContext(m_impl->m_hProv, 0);
00137 m_impl->m_hProv = NULL;
00138 }
00139 delete m_impl;
00140 m_impl = NULL;
00141 }
00149 void CPKIFCNGCAPIRaw::Initialize()
00150 {
00151 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::Initialize()", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00152 }
00153
00163 LPCWSTR GetCNGSymAlgorithm(
00165 const CPKIFKeyMaterial& key)
00166 {
00167 switch(key.GetSymmetricKeyAlgorithm())
00168 {
00169 case PKIFCRYPTO::DES:
00170 return BCRYPT_DES_ALGORITHM;
00171 case PKIFCRYPTO::TDES:
00172 return BCRYPT_3DES_ALGORITHM;
00173 case PKIFCRYPTO::AES:
00174 case PKIFCRYPTO::AES128:
00175 case PKIFCRYPTO::AES192:
00176 case PKIFCRYPTO::AES256:
00177 return BCRYPT_AES_ALGORITHM;
00178 default:
00179 RAISE_CRYPTO_EXCEPTION("", TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, NULL)
00180 }
00181 }
00182
00198 bool CPKIFCNGCAPIRaw::SupportsAlgorithm(
00200 const CPKIFKeyMaterial& key)
00201 {
00202 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::SupportsAlgorithm(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00203
00204 if(key.ContainsSymmetricKeyMaterial())
00205 {
00206 try
00207 {
00208 GetCNGSymAlgorithm(key);
00209 return true;
00210 }
00211 catch(CPKIFCryptoException& e)
00212 {
00213 if(CRYPTO_ALG_NOT_SUPPORTED == e.GetErrorCode())
00214 {
00215
00216
00217
00218 return false;
00219 } else {
00220 throw e;
00221 }
00222 }
00223 }
00224 else if(key.ContainsCertificate())
00225 {
00226 try
00227 {
00228 CPKIFCertificatePtr pkifCert(new CPKIFCertificate());
00229 pkifCert->Decode(key.GetCertificate(),key.GetCertificateLength());
00230 CPKIFSubjectPublicKeyInfoPtr spki = pkifCert->GetSubjectPublicKeyInfo();
00231
00232 if(!spki) return false;
00233 switch(GetAlgClass(spki->alg()))
00234 {
00235 case RSA_CLASS:
00236 case DSA_CLASS:
00237 case ECDSA_CLASS:
00238 return true;
00239 break;
00240 default:
00241 return false;
00242 break;
00243 }
00244 }
00245 catch(CPKIFException&)
00246 {
00247
00248
00249 return false;
00250 }
00251 } else {
00252 RAISE_CRYPTO_EXCEPTION("key parameter contents not recognized.", thisComponent, COMMON_INVALID_INPUT, this);
00253 }
00254 }
00265 void CPKIFCNGCAPIRaw::Sign(
00267 const CPKIFKeyMaterial& key,
00269 unsigned char* pHashData,
00271 int nHashDataLen,
00273 unsigned char* pSignature,
00275 int* nSignatureLen,
00277 PKIFCRYPTO::HASH_ALG hashAlg
00278 )
00279 {
00280 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::Sign(const CPKIFKeyMaterial& key,...)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00281
00282 RAISE_CRYPTO_EXCEPTION("Signing operations are not implemented for raw key material.", thisComponent, COMMON_NOT_IMPLEMENTED, this);
00283 }
00284
00306 template <bool _CryptDirection>
00307 void CPKIFCNGCAPIRawImpl::AsymCrypt(
00309 const CPKIFKeyMaterial& key,
00311 unsigned char* pData,
00313 int nDataLen,
00315 unsigned char* pResult,
00318 int* pnResultLen,
00322 bool pad)
00323 {
00324 LOG_STRING_DEBUG("CPKIFCNGCAPIRawImpl::AsymCrypt(const CPKIFKeyMaterial& key, ...)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00325
00326 CPKIFBCryptPublicKey capiKey;
00327 BCRYPT_KEY_HANDLE hKey = capiKey.Initialize(key);
00328 DWORD paddingFlags = 0;
00329 if(RSA_CLASS == GetAlgClass(capiKey.GetAlgId()))
00330 {
00331 paddingFlags = BCRYPT_PAD_PKCS1;
00332 }
00333
00334 int maxOut = *pnResultLen;
00335 *pnResultLen = nDataLen;
00336 int err = 0;
00337 memcpy(pResult, pData, nDataLen);
00338
00339 pkif_byte_array iv(0);
00340 int ivLen;
00341 key.GetIV(NULL,&ivLen);
00342
00343
00344 if(ivLen) {
00345 iv.reset(new unsigned char[ivLen]);
00346 key.GetIV(iv,&ivLen);
00347 }
00348
00349 NTSTATUS ntrv = 0L;
00350 if(_CryptDirection)
00351 {
00352 DWORD cbCipherText = 0;
00353 if(!NT_SUCCESS(ntrv = BCryptEncrypt(hKey,pData,nDataLen,NULL,iv,ivLen,
00354 NULL,0,&cbCipherText,paddingFlags)))
00355 {
00356 std::ostringstream os;
00357 os << "BCryptEncrypt failed: (" << GetLastError() << ")" << "NT status code " << ntrv;
00358 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
00359 }
00360
00361 pkif_byte_array pbCipherText(new unsigned char[cbCipherText]);
00362 DWORD cbCTOut = 0;
00363 if(!NT_SUCCESS(ntrv = BCryptEncrypt(hKey,pData,nDataLen,NULL,iv,ivLen,
00364 pbCipherText,cbCipherText,&cbCTOut,paddingFlags)))
00365 {
00366 std::ostringstream os;
00367 os << "BCryptEncrypt failed: (" << GetLastError() << ")" << "NT status code " << ntrv;
00368 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
00369 }
00370
00371 memcpy(pResult, pbCipherText.get(), cbCTOut);
00372 *pnResultLen = cbCTOut;
00373 }
00374 else
00375 {
00376 DWORD cbPlainText = 0;
00377 if(!NT_SUCCESS(ntrv = BCryptDecrypt(hKey,pData,nDataLen,NULL,iv,ivLen,
00378 NULL,0,&cbPlainText,paddingFlags)))
00379 {
00380 std::ostringstream os;
00381 os << "BCryptDecrypt failed: (" << GetLastError() << ")" << "NT status code " << ntrv;
00382 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
00383 }
00384
00385 pkif_byte_array pbPlainText(new unsigned char[cbPlainText]);
00386 DWORD cbPTOut = 0;
00387 if(!NT_SUCCESS(ntrv = BCryptEncrypt(hKey,pData,nDataLen,NULL,iv,ivLen,
00388 pbPlainText,cbPlainText,&cbPTOut,paddingFlags)))
00389 {
00390 std::ostringstream os;
00391 os << "BCryptDecrypt failed: (" << GetLastError() << ")" << "NT status code " << ntrv;
00392 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
00393 }
00394
00395 memcpy(pResult, pbPlainText.get(), cbPTOut);
00396 *pnResultLen = cbPTOut;
00397 }
00398
00399
00400 }
00408 void CPKIFCNGCAPIRaw::Decrypt(
00410 const CPKIFKeyMaterial& key,
00412 unsigned char* pData,
00414 int nDataLen,
00416 unsigned char* pResult,
00419 int* pnResultLen,
00422 bool pad)
00423 {
00424 if(key.ContainsSymmetricKeyMaterial()) {
00425
00426 std::auto_ptr<CPKIFCAPIRawCryptContext> ctx(
00427 static_cast<CPKIFCAPIRawCryptContext *>(this->CryptInit(key,pad))
00428 );
00429 Decrypt(ctx.get(),pData,nDataLen,pResult,pnResultLen,true);
00430 } else {
00431 m_impl->AsymCrypt<false>(key, pData, nDataLen, pResult, pnResultLen, pad);
00432 }
00433 }
00441 void CPKIFCNGCAPIRaw::Encrypt(
00443 const CPKIFKeyMaterial& key,
00445 unsigned char* pData,
00447 int nDataLen,
00449 unsigned char* pResult,
00452 int* pnResultLen,
00455 bool pad)
00456 {
00457 if(key.ContainsSymmetricKeyMaterial()) {
00458
00459 std::auto_ptr<CPKIFCAPIRawCryptContext> ctx(
00460 static_cast<CPKIFCAPIRawCryptContext *>(this->CryptInit(key,pad))
00461 );
00462 Encrypt(ctx.get(),pData,nDataLen,pResult,pnResultLen,true);
00463 } else {
00464 m_impl->AsymCrypt<true>(key, pData, nDataLen, pResult, pnResultLen, pad);
00465 }
00466 }
00467
00480 bool _CNGVerify(
00482 const CPKIFKeyMaterial& key,
00485 unsigned char* pHashData,
00487 int nHashDataLen,
00489 unsigned char* pSignature,
00491 int nSignatureLen,
00493 PKIFCRYPTO::HASH_ALG ha
00494 )
00495 {
00496 LOG_STRING_DEBUG("_CNGVerify(const CPKIFKeyMaterial& key, unsigned char* pHashData, int nHashDataLen, unsigned char* pSignature, int nSignatureLen)", TOOLKIT_CRYPTO_CAPIRAW, 0, NULL);
00497
00498 DWORD hashLen = 0;
00499 SECURITY_STATUS cngStatus = ERROR_SUCCESS;
00500 NTSTATUS ntrv = 0L;
00501 BCRYPT_PKCS1_PADDING_INFO PKCS1PaddingInfo= {0};
00502
00503
00504 CPKIFBCryptPublicKey bcKeyWrapper;
00505 BCRYPT_KEY_HANDLE bcKey = bcKeyWrapper.Initialize(key);
00506
00507
00508 switch(ha)
00509 {
00510 case PKIFCRYPTO::SHA1:
00511 PKCS1PaddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
00512 break;
00513 case PKIFCRYPTO::SHA256:
00514 PKCS1PaddingInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM;
00515 break;
00516 case PKIFCRYPTO::SHA384:
00517 PKCS1PaddingInfo.pszAlgId = BCRYPT_SHA384_ALGORITHM;
00518 break;
00519 case PKIFCRYPTO::SHA512:
00520 PKCS1PaddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM;
00521 break;
00522 default:
00523 std::ostringstream os;
00524 os << "Unsupported hash algorithm encountered: " << ha;
00525 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00526 }
00527
00528 BCRYPT_PKCS1_PADDING_INFO * pi = 0;
00529 DWORD pflags = 0;
00530 unsigned char * pSigToVerify = pSignature;
00531 DWORD nFinalSigLen = nSignatureLen;
00532
00533
00534
00535 DWORD algPropSize = 0;
00536 if(!NT_SUCCESS(ntrv = BCryptGetProperty(bcKey,BCRYPT_ALGORITHM_NAME,NULL,0,&algPropSize,0)))
00537 {
00538 std::ostringstream os;
00539 os << "Unable to obtain signature algorithm group for key material :("
00540 << GetLastError() << ")" << "(NTSTATUS code " << ntrv << ")" << endl;
00541 RAISE_CRYPTO_EXCEPTION(os.str().c_str(),TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00542 }
00543 pkif_byte_array algName(new unsigned char[algPropSize]);
00544 memset(algName,0x00,algPropSize);
00545 if(!NT_SUCCESS(ntrv = BCryptGetProperty(bcKey,BCRYPT_ALGORITHM_NAME,algName,algPropSize,&algPropSize,0)))
00546 {
00547 std::ostringstream os;
00548 os << "Unable to obtain signature algorithm group for key material :("
00549 << GetLastError() << ")" << "(NTSTATUS code " << ntrv << ")" << endl;
00550 RAISE_CRYPTO_EXCEPTION(os.str().c_str(),TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00551 }
00552 pkif_byte_array converted(0);
00553 if(0 == wcscmp(BCRYPT_RSA_ALGORITHM,(wchar_t *)algName.get()))
00554 {
00555 pi = &PKCS1PaddingInfo;
00556 pflags = BCRYPT_PAD_PKCS1;
00557 }
00558 else
00559 {
00560 DWORD dssSigLen,dssSigLenLen;
00561 if(FAILED(cngStatus = BCryptGetProperty(bcKey,
00562 BCRYPT_SIGNATURE_LENGTH,
00563 (unsigned char *)&dssSigLen,
00564 sizeof(DWORD),
00565 &dssSigLenLen,
00566 0)))
00567 {
00568 RAISE_CRYPTO_EXCEPTION("Unable to obtain signature length for key", TOOLKIT_CRYPTO, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00569 }
00570 size_t targetLen = dssSigLen;
00571 converted.reset(new unsigned char[targetLen]);
00572 try {
00573 targetLen = CryptoPP::DSAConvertSignatureFormat(converted,targetLen,CryptoPP::DSA_P1363,pSignature,nSignatureLen,CryptoPP::DSA_DER);
00574 }catch(CryptoPP::BERDecodeErr &){
00575
00576 converted.clear();
00577 }
00578 if(converted.get() != 0) {
00579 pSigToVerify = converted.get();
00580 nFinalSigLen = (DWORD)targetLen;
00581 }
00582
00583 }
00584
00585
00586 if(!NT_SUCCESS(ntrv = BCryptVerifySignature(bcKey,pi,pHashData,nHashDataLen,
00587 pSigToVerify,nFinalSigLen,pflags)))
00588 {
00589 return false;
00590 }
00591
00592
00593 return true;
00594 }
00603 bool CPKIFCNGCAPIRaw::VerifyCertificate(
00606 const CPKIFCertificate& issCert,
00609 const CPKIFCertificate& subCert)
00610 {
00611 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::VerifyCertificate(const CPKIFCertificate& issCert, const CPKIFCertificate& subCert)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00612
00613 CPKIFBufferPtr issBuf = issCert.Encoded();
00614 CPKIFBufferPtr subBuf = subCert.Encoded();
00615
00616 PCCERT_CONTEXT issCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
00617 issBuf->GetBuffer(), issBuf->GetLength());
00618
00619
00620
00621 int err = 0;
00622 BOOL b = CryptVerifyCertificateSignature(NULL,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
00623 subBuf->GetBuffer(), subBuf->GetLength(), &issCtx->pCertInfo->SubjectPublicKeyInfo);
00624 if(!b)
00625 {
00626 err = GetLastError();
00627 }
00628
00629 CertFreeCertificateContext(issCtx);
00630
00631
00632 return TRUE == b;
00633 }
00634
00635
00645 bool CPKIFCNGCAPIRaw::Verify(
00647 const CPKIFKeyMaterial& key,
00649 unsigned char* pHashData,
00651 int nHashDataLen,
00653 unsigned char* pSignature,
00655 int nSignatureLen,
00657 PKIFCRYPTO::HASH_ALG hashAlg
00658 )
00659 {
00660
00661 return _CNGVerify(key, pHashData, nHashDataLen, pSignature, nSignatureLen,hashAlg);
00662 }
00675 void CPKIFCNGCAPIRaw::GenRandom(
00677 unsigned char* buf,
00679 int len)
00680 {
00681 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::GenRandom(unsigned char* buf, int len)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00682
00683 BCRYPT_ALG_HANDLE_PKIF hRandomAlg(NULL);
00684 NTSTATUS ntrv = 0L;
00685
00686 if(!NT_SUCCESS(ntrv = BCryptOpenAlgorithmProvider(&hRandomAlg,BCRYPT_RNG_ALGORITHM,
00687 NULL,0)))
00688 {
00689 std::ostringstream os;
00690 os << "BCryptOpenAlgorithmProvider failed: (" << GetLastError() <<") NT Status: " << ntrv;
00691 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_ACQUIRE_CONTEXT_FAILED, NULL);
00692 }
00693
00694 if (!NT_SUCCESS(ntrv = BCryptGenRandom(hRandomAlg,buf,len,0)))
00695 {
00696 std::ostringstream os;
00697 os << "BCryptGenRandom failed: (" << GetLastError() <<") NT Status: " << ntrv;
00698 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, PKIFCAPI_GEN_RANDOM_FAILED, NULL);
00699
00700 }
00701 }
00716 IPKIFHashContext* CPKIFCNGCAPIRaw::HashInit(
00719 PKIFCRYPTO::HASH_ALG alg)
00720 {
00721 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::HashInit(HASH_ALG alg)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00722
00723
00724 wchar_t* hashAlg;
00725 switch(alg)
00726 {
00727 case PKIFCRYPTO::SHA1:
00728 hashAlg = BCRYPT_SHA1_ALGORITHM;
00729 break;
00730 case PKIFCRYPTO::SHA256:
00731 hashAlg = BCRYPT_SHA256_ALGORITHM;
00732 break;
00733 case PKIFCRYPTO::SHA384:
00734 hashAlg = BCRYPT_SHA384_ALGORITHM;
00735 break;
00736 case PKIFCRYPTO::SHA512:
00737 hashAlg = BCRYPT_SHA512_ALGORITHM;
00738 break;
00739 default:
00740 std::ostringstream os;
00741 os << "Unsupported hash algorithm encountered: " << alg;
00742 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, CRYPTO_ALG_NOT_SUPPORTED, NULL);
00743 }
00744
00745
00746
00747 CPKIFCAPIHashContext* hashCtx = new CPKIFCAPIHashContext();
00748 NTSTATUS status = STATUS_UNSUCCESSFUL;
00749 DWORD cbData = 0,
00750 cbHash = 0,
00751 cbHashObject = 0;
00752 PBYTE pbHash = NULL;
00753
00754
00755 if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
00756 &hashCtx->m_hHashAlg,
00757 GetCNGHashAlg((PKIFCRYPTO::HASH_ALG)alg),
00758 NULL,0)))
00759 {
00760
00761 std::ostringstream os;
00762 os << "CryptCreateHash failed: " << GetLastError();;
00763 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
00764 }
00765
00766
00767 if(!NT_SUCCESS(status = BCryptGetProperty(
00768 hashCtx->m_hHashAlg,
00769 BCRYPT_OBJECT_LENGTH,
00770 (PBYTE)&cbHashObject,
00771 sizeof(DWORD),
00772 &cbData,
00773 0)))
00774 {
00775 std::ostringstream os;
00776 os << "BCryptGetProperty failed: " << GetLastError();;
00777 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
00778 }
00779
00780
00781 hashCtx->m_pbHashObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHashObject);
00782 if(NULL == hashCtx->m_pbHashObject)
00783 {
00784 std::ostringstream os;
00785 os << "Memory allocation failed: " << GetLastError();;
00786 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
00787 }
00788
00789
00790 if(!NT_SUCCESS(status = BCryptGetProperty(
00791 hashCtx->m_hHashAlg,
00792 BCRYPT_HASH_LENGTH,
00793 (PBYTE)&cbHash,
00794 sizeof(DWORD),
00795 &cbData,
00796 0)))
00797 {
00798 std::ostringstream os;
00799 os << "BCryptGetProperty failed: " << GetLastError();;
00800 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
00801 }
00802
00803
00804 if(!NT_SUCCESS(status = BCryptCreateHash(
00805 hashCtx->m_hHashAlg,
00806 &hashCtx->m_cngHashHandle,
00807 hashCtx->m_pbHashObject,
00808 cbHashObject,
00809 NULL,
00810 0,
00811 0)))
00812 {
00813 std::ostringstream os;
00814 os << "BCryptCreateHash failed: " << GetLastError();;
00815 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
00816 }
00817
00818 return hashCtx;
00819 }
00834 void CPKIFCNGCAPIRaw::HashUpdate(
00836 IPKIFHashContext* hash,
00838 unsigned char* pData,
00840 int nDataLen)
00841 {
00842 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::HashUpdate(IPKIFHashContext* hash, unsigned char* pData, int nDataLen)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00843
00844 NTSTATUS status = STATUS_UNSUCCESSFUL;
00845
00846
00847
00848
00849
00850 if(NULL == hash || 0 > nDataLen)
00851 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HashUpdate.");
00852
00853
00854
00855 CPKIFCAPIHashContext* hashCtx = dynamic_cast<CPKIFCAPIHashContext*>(hash);
00856 if(NULL == hashCtx)
00857 throw CPKIFCryptoException(thisComponent, PKIFCAPI_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HashUpdate.");
00858
00859 if(NULL == hashCtx->m_cngHashHandle)
00860 throw CPKIFCryptoException(thisComponent, PKIFCAPI_EMPTY_HASH_CONTEXT, "Empty hash context passed to HashUpdate.");
00861
00862
00863 if(!NT_SUCCESS(status = BCryptHashData(
00864 hashCtx->m_cngHashHandle,
00865 (PBYTE)pData,
00866 nDataLen,
00867 0)))
00868 {
00869 std::ostringstream os;
00870 os << "BCryptHashData failed: " << GetLastError();;
00871 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
00872 }
00873 }
00889 void CPKIFCNGCAPIRaw::HashFinal(
00891 IPKIFHashContext* hash,
00893 unsigned char* pResult,
00896 int* pnResultLen)
00897 {
00898 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::HashFinal(IPKIFHashContext* hash, unsigned char* pResult, int* pnResultLen)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00899
00900 NTSTATUS status = STATUS_UNSUCCESSFUL;
00901
00902
00903
00904
00905
00906 if(NULL == hash || NULL == pResult || NULL == pnResultLen || 0 >= *pnResultLen)
00907 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HashFinal.");
00908
00909 CPKIFCAPIHashContext* hashCtx = dynamic_cast<CPKIFCAPIHashContext*>(hash);
00910 if(NULL == hashCtx)
00911 throw CPKIFCryptoException(thisComponent, PKIFCAPI_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HashFinal.");
00912
00913 if(NULL == hashCtx->m_cngHashHandle)
00914 throw CPKIFCryptoException(thisComponent, PKIFCAPI_EMPTY_HASH_CONTEXT, "Empty hash context passed to HashUpdate.");
00915
00916 DWORD digestLen = 0, maxOutLen = 0;
00917 try {
00918 maxOutLen = boost::numeric_cast<DWORD,int>(*pnResultLen);
00919 } catch(...) {
00920 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "Invalid output buffer length passed to HashFinal.");
00921 }
00922 unsigned long digestLenLen = 0;
00923 if(!NT_SUCCESS(status = BCryptGetProperty(
00924 hashCtx->m_cngHashHandle,
00925 BCRYPT_HASH_LENGTH,
00926 (PBYTE)&digestLen,
00927 sizeof(DWORD),
00928 &digestLenLen,
00929 0)))
00930 {
00931
00932
00933 digestLen = maxOutLen;
00934 }
00935
00936 if(digestLen > maxOutLen)
00937 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "Invalid output buffer passed to HashFinal.");
00938
00939
00940 if(!NT_SUCCESS(status = BCryptFinishHash(
00941 hashCtx->m_cngHashHandle,
00942 pResult,
00943 digestLen,
00944 0)))
00945 {
00946 std::ostringstream os;
00947 os << "BCryptFinishHash failed: " << GetLastError();;
00948 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_MISC_HASH_CALL_FAILED, NULL);
00949 }
00950 try {
00951 *pnResultLen = boost::numeric_cast<int,DWORD>(digestLen);
00952 } catch(...) {
00953 RAISE_CRYPTO_EXCEPTION("Internal error: Unable to cast digest length from DWORD to int.", TOOLKIT_CRYPTO, PKIFCAPI_MISC_HASH_CALL_FAILED, NULL);
00954 }
00955 }
00978 IPKIFRawCryptContext* CPKIFCNGCAPIRaw::CryptInit(
00981 const CPKIFKeyMaterial& key,
00983 bool pad)
00984 {
00985 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::CryptInit(const CPKIFKeyMaterial& key)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
00986
00987
00988 if(!key.ContainsSymmetricKeyMaterial())
00989 {
00990 throw CPKIFCryptoException(TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, "CryptInit() only makes sense for symmetric keys.");
00991 }
00992
00993
00994 std::auto_ptr<CPKIFCAPIRawCryptContext> cryptContext(new CPKIFCAPIRawCryptContext());
00995
00996 NTSTATUS status = STATUS_UNSUCCESSFUL;
00997
00998 cryptContext->m_bNeedsPad = pad;
00999
01000 LPCWSTR tmpAlgID = GetCNGSymAlgorithm(key);
01001 BCRYPT_ALG_HANDLE_PKIF hAlg(0);
01002
01003 if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAlg,tmpAlgID,NULL,0)))
01004 {
01005 std::ostringstream os;
01006 os << "BCryptOpenAlgorithmProvider failed: " << GetLastError();;
01007 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_OPEN_ALG_PROVIDER_FAILED, NULL);
01008 }
01009
01010
01011 DWORD cbData = 0;
01012 DWORD cbKeyObject = 0;
01013 if(!NT_SUCCESS(status = BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,(PBYTE)&cbKeyObject,
01014 sizeof(DWORD),&cbData,0)))
01015 {
01016 std::ostringstream os;
01017 os << "BCryptGetProperty failed: " << GetLastError();;
01018 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_GET_PROPERTY_FAILED, NULL);
01019 }
01020
01021 pkif_byte_array pbKeyObject(new unsigned char[cbKeyObject]);
01022
01023 LPCWSTR tmpMode = 0;
01024 switch(key.GetMode())
01025 {
01026 case PKIFCRYPTO::ECB:
01027 tmpMode = BCRYPT_CHAIN_MODE_ECB;
01028 break;
01029 case PKIFCRYPTO::CBC:
01030 tmpMode = BCRYPT_CHAIN_MODE_CBC;
01031 if(NULL == key.GetIV())
01032 throw CPKIFCryptoException(thisComponent, CRYPTO_MISSING_IV);
01033 break;
01034 default:
01035 throw CPKIFCryptoException(thisComponent, CRYPTO_MODE_NOT_SUPPORTED);
01036 }
01037
01038
01039 if(!NT_SUCCESS(status = BCryptGetProperty(hAlg,BCRYPT_BLOCK_LENGTH,
01040 (PBYTE)&cryptContext->m_blockLen,sizeof(DWORD),&cbData,0)))
01041 {
01042 std::ostringstream os;
01043 os << "BCryptGetProperty: " << GetLastError();;
01044 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_GET_PROPERTY_FAILED, NULL);
01045
01046 }
01047
01048 if(NULL != key.GetIV())
01049 {
01050 int ivLen = 0;
01051 key.GetIV(NULL, &ivLen);
01052 DWORD dwIVLen = 0;
01053 try {
01054 dwIVLen = boost::numeric_cast<DWORD,int>(ivLen);
01055 }catch(...){
01056 RAISE_CRYPTO_EXCEPTION("Invalid IV length.", TOOLKIT_CRYPTO, PKIFCAPING_GET_PROPERTY_FAILED, NULL);
01057 }
01058
01059
01060 if (cryptContext->m_blockLen > dwIVLen)
01061 {
01062 std::ostringstream os;
01063 os << "Block length is not equal to the supplied IV length: " << GetLastError();;
01064 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_GET_PROPERTY_FAILED, NULL);
01065
01066 }
01067
01068 CPKIFBufferPtr tmp(new CPKIFBuffer(key.GetIV(), ivLen));
01069 cryptContext->m_iv = tmp;
01070 }
01071
01072 if(pad)
01073 cryptContext->m_padbuf = new unsigned char[cryptContext->m_blockLen];
01074
01075
01076 ULONG modeLen = (ULONG) (wcslen(tmpMode)+1*sizeof(wchar_t));
01077 if(!NT_SUCCESS(status = BCryptSetProperty(hAlg,BCRYPT_CHAINING_MODE,(PBYTE)tmpMode,
01078 modeLen,0)))
01079 {
01080 std::ostringstream os;
01081 os << "Failed to set mode: " << GetLastError();
01082 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_SET_PROPERTY_FAILED, NULL);
01083 }
01084
01085 PKIFCRYPTO::SYMKEY_ALG symAlg = key.GetSymmetricKeyAlgorithm();
01086 int keyLen = 0;
01087 key.GetSymmetricKey(NULL, &keyLen, &symAlg);
01088
01089 if(!NT_SUCCESS(status = BCryptGenerateSymmetricKey(hAlg,&cryptContext->m_hKey,
01090 pbKeyObject,cbKeyObject,(PBYTE)key.GetSymmetricKey(),
01091 keyLen,0)))
01092 {
01093 std::ostringstream os;
01094 os << "BCryptGenerateSymmetricKey failed: " << GetLastError();;
01095 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_GENERATE_SYM_KEY_FAILED, NULL);
01096 }
01097
01098
01099 cryptContext->m_hBCAlg = hAlg.release();
01100 cryptContext->m_hKeyBuffer = pbKeyObject.release();
01101
01102
01103 return cryptContext.release();
01104 }
01113 void CPKIFCNGCAPIRaw::Decrypt(
01116 IPKIFRawCryptContext* cryptContext,
01118 unsigned char* pData,
01120 int nDataLen,
01122 unsigned char* pResult,
01125 int* pnResultLen,
01128 bool final)
01129 {
01130 m_impl->CryptFunc<false>(cryptContext, pData, nDataLen, pResult, pnResultLen, final);
01131 }
01140 void CPKIFCNGCAPIRaw::Encrypt(
01143 IPKIFRawCryptContext* cryptContext,
01145 unsigned char* pData,
01147 int nDataLen,
01149 unsigned char* pResult,
01152 int* pnResultLen,
01155 bool final)
01156 {
01157 m_impl->CryptFunc<true>(cryptContext, pData, nDataLen, pResult, pnResultLen, final);
01158 }
01159
01181 template <bool _CryptDirection>
01182 void CPKIFCNGCAPIRawImpl::CryptFunc(
01185 IPKIFRawCryptContext* cryptContext,
01187 unsigned char* pData,
01189 int nDataLen,
01191 unsigned char* pResult,
01193 int* pnResultLen,
01196 bool final)
01197 {
01198 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::CryptFunc(IPKIFRawCryptContext* cryptContext, unsigned char* pData, int nDataLen, unsigned char* pResult, int* pnResultLen, bool final)", TOOLKIT_CRYPTO_CAPIRAW, 0, this);
01199
01200 CPKIFCAPIRawCryptContext* icc = dynamic_cast<CPKIFCAPIRawCryptContext*>(cryptContext);
01201 const unsigned char* iv = NULL;
01202 ULONG ivLen = 0;
01203
01204 if(icc->m_iv != (CPKIFBuffer*)NULL)
01205 {
01206 iv = icc->m_iv->GetBuffer();
01207 ivLen = icc->m_iv->GetLength();
01208
01209 }
01210 NTSTATUS status = STATUS_UNSUCCESSFUL;
01211
01212 if(icc->m_bFromCert || !icc->m_bNeedsPad)
01213 {
01214 if(_CryptDirection)
01215 {
01216 DWORD cbCipherText = 0;
01217 if(!NT_SUCCESS(status = BCryptEncrypt(icc->m_hKey,pData,nDataLen,
01218 NULL,(PBYTE)iv,ivLen,NULL,0,&cbCipherText,0)))
01219 {
01220 std::ostringstream os;
01221 os << "BCryptEncrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01222 << ")" << endl;
01223 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01224 }
01225 pkif_byte_array pbCipherText(new unsigned char[cbCipherText]);
01226 DWORD cbData = 0;
01227 if(!NT_SUCCESS(status = BCryptEncrypt(icc->m_hKey,pData,nDataLen,
01228 NULL,(PBYTE)iv,ivLen,
01229 pbCipherText,cbCipherText,&cbData,0)))
01230 {
01231 std::ostringstream os;
01232 os << "BCryptEncrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01233 << ")" << endl;
01234 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01235 }
01236
01237 memcpy(pResult, pbCipherText.get(), cbData);
01238 *pnResultLen = cbData;
01239 }
01240 else
01241 {
01242 DWORD cbPlainText = 0;
01243
01244 if(!NT_SUCCESS(status = BCryptDecrypt( icc->m_hKey,pData,nDataLen,NULL,
01245 (PBYTE)iv,ivLen,NULL,0,&cbPlainText,0)))
01246 {
01247 std::ostringstream os;
01248 os << "BCryptDecrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01249 << ")" << endl;
01250 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
01251 }
01252 pkif_byte_array pbPlainText(new unsigned char[cbPlainText]);
01253 DWORD cbData = 0;
01254 if(!NT_SUCCESS(status = BCryptDecrypt(icc->m_hKey, pData, nDataLen,
01255 NULL,(PBYTE)iv,ivLen,
01256 pbPlainText,cbPlainText,&cbData,
01257 0)))
01258 {
01259 std::ostringstream os;
01260 os << "BCryptDecrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01261 << ")" << endl;
01262 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
01263 }
01264
01265 memcpy(pResult, pbPlainText.get(), cbData);
01266 try {
01267 *pnResultLen = cbData;
01268 }catch(...){
01269 RAISE_CRYPTO_EXCEPTION("BCryptDecrypt gave invalid length", TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
01270 }
01271 }
01272 return;
01273 }
01274
01275 int maxOut = *pnResultLen;
01276 int inLen = nDataLen;
01277 unsigned char * start = pData;
01278 unsigned char * outBuf = pResult;
01279
01280 DWORD updateLen = 0;
01281 DWORD padUpdateLen = 0;
01282 *pnResultLen = 0;
01283 unsigned int finalLen = 0;
01284
01285 *pnResultLen = 0;
01286 int err = 0;
01287
01288 DWORD dwMaxOut = 0;
01289 try {
01290 dwMaxOut = boost::numeric_cast<DWORD,int>(maxOut);
01291 } catch(...) {
01292 RAISE_CRYPTO_EXCEPTION("Invalid output length", TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, NULL);
01293 }
01294 if(_CryptDirection)
01295 {
01296 DWORD resLen = *pnResultLen;
01297 if(final)
01298 {
01299
01300 if(icc->m_padlen) {
01301 memcpy(outBuf,icc->m_padbuf,icc->m_padlen);
01302 }
01303 if(start && inLen) memcpy(outBuf + icc->m_padlen,start,inLen);
01304 updateLen = inLen + icc->m_padlen;
01305 DWORD cbCipherText = 0;
01306
01307
01308
01309
01310 if(!NT_SUCCESS(status = BCryptEncrypt(icc->m_hKey,outBuf,updateLen,
01311 NULL,(PBYTE)iv,ivLen,NULL,0,&cbCipherText,BCRYPT_BLOCK_PADDING)))
01312 {
01313 std::ostringstream os;
01314 os << "BCryptEncrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01315 << ")" << endl;
01316 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01317 }
01318 if(cbCipherText > dwMaxOut) {
01319 RAISE_CRYPTO_EXCEPTION("Output buffer is too small for ciphertext.", TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, NULL);
01320 }
01321 pkif_byte_array pbCipherText(new unsigned char[cbCipherText]);
01322 DWORD cbData = 0;
01323 if(!NT_SUCCESS(status = BCryptEncrypt(icc->m_hKey,outBuf,updateLen,
01324 NULL,(PBYTE)iv,ivLen,
01325 pbCipherText,cbCipherText,&cbData,BCRYPT_BLOCK_PADDING)))
01326 {
01327 std::ostringstream os;
01328 os << "BCryptEncrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01329 << ")" << endl;
01330 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01331 }
01332 memcpy(outBuf,pbCipherText.get(),cbData);
01333 try {
01334 *pnResultLen = boost::numeric_cast<int,DWORD>(cbData);
01335 }catch(...){
01336 RAISE_CRYPTO_EXCEPTION("BCryptEncrypt returned invalid length", TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01337 }
01338 return;
01339 }
01340
01341
01342 if(!start || !inLen) return;
01343 int leftInBlock = icc->m_blockLen - icc->m_padlen;
01344
01345
01346
01347 if(leftInBlock >= inLen) {
01348 memcpy(icc->m_padbuf,start,inLen);
01349 icc->m_padlen += inLen;
01350 *pnResultLen = 0;
01351 return;
01352 }
01353
01354
01355
01356 memcpy(outBuf,icc->m_padbuf,icc->m_padlen);
01357 updateLen = icc->m_padlen;
01358 icc->m_padlen = 0;
01359
01360
01361 int trailing = (inLen + updateLen) % icc->m_blockLen ?
01362 (inLen + updateLen) % icc->m_blockLen : icc->m_blockLen;
01363
01364
01365 int copied = inLen - trailing;
01366 memcpy(outBuf+updateLen,start,copied);
01367 start += copied;
01368 updateLen += copied;
01369
01370
01371 DWORD cbCipherText = 0;
01372 if(!NT_SUCCESS(status = BCryptEncrypt(icc->m_hKey,outBuf,updateLen,
01373 NULL,(PBYTE)iv,ivLen,NULL,0,&cbCipherText,0)))
01374 {
01375 std::ostringstream os;
01376 os << "BCryptEncrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01377 << ")" << endl;
01378 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01379 }
01380 if(cbCipherText > dwMaxOut) {
01381 RAISE_CRYPTO_EXCEPTION("Output buffer is too small for ciphertext.", TOOLKIT_CRYPTO, COMMON_INVALID_INPUT, NULL);
01382 }
01383 pkif_byte_array pbCipherText(new unsigned char[cbCipherText]);
01384 DWORD cbData = 0;
01385 if(!NT_SUCCESS(status = BCryptEncrypt(icc->m_hKey,outBuf,updateLen,
01386 NULL,(PBYTE)iv,ivLen,
01387 pbCipherText,cbCipherText,&cbData,0)))
01388 {
01389 std::ostringstream os;
01390 os << "BCryptEncrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01391 << ")" << endl;
01392 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01393 }
01394 memcpy(outBuf,pbCipherText.get(),cbData);
01395
01396
01397 memcpy(icc->m_padbuf,start,trailing);
01398 icc->m_padlen += trailing;
01399
01400 try {
01401 *pnResultLen = boost::numeric_cast<int,DWORD>(cbData);
01402 }catch(...){
01403 RAISE_CRYPTO_EXCEPTION("BCryptEncrypt returned invalid length", TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01404 }
01405 }
01406 else
01407 {
01408 if(final) {
01409 if(icc->m_padlen) {
01410 memcpy(outBuf,icc->m_padbuf,icc->m_padlen);
01411 }
01412 if(start && inLen) memcpy(outBuf + icc->m_padlen,start,inLen);
01413 updateLen = inLen + icc->m_padlen;
01414 icc->m_padlen = 0;
01415 DWORD cbPlainText = 0;
01416
01417 if(!NT_SUCCESS(status = BCryptDecrypt( icc->m_hKey,outBuf,updateLen,NULL,
01418 (PBYTE)iv,ivLen,NULL,0,&cbPlainText,BCRYPT_BLOCK_PADDING)))
01419 {
01420 std::ostringstream os;
01421 os << "BCryptDecrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01422 << ")" << endl;
01423 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
01424 }
01425 pkif_byte_array pbPlainText(new unsigned char[cbPlainText]);
01426 DWORD cbData = 0;
01427 if(!NT_SUCCESS(status = BCryptDecrypt(icc->m_hKey, outBuf, updateLen,
01428 NULL,(PBYTE)iv,ivLen,
01429 pbPlainText,cbPlainText,&cbData,
01430 BCRYPT_BLOCK_PADDING)))
01431 {
01432 std::ostringstream os;
01433 os << "BCryptDecrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01434 << ")" << endl;
01435 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
01436 }
01437
01438 if(dwMaxOut < cbData) {
01439 RAISE_CRYPTO_EXCEPTION("Decrypt() called with insufficient buffer available", m_parent->thisComponent, COMMON_INVALID_INPUT, NULL);
01440 }
01441
01442 memcpy(pResult, pbPlainText.get(), cbData);
01443 try {
01444 *pnResultLen = boost::numeric_cast<int,DWORD>(cbData);
01445 }catch(...){
01446 RAISE_CRYPTO_EXCEPTION("BCryptDecrypt returned invalid length", TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01447 }
01448 return;
01449 }
01450
01451
01452 if(!start || !inLen) return;
01453 int leftInBlock = icc->m_blockLen - icc->m_padlen;
01454
01455 if(leftInBlock >= inLen) {
01456 memcpy(icc->m_padbuf,start,inLen);
01457 icc->m_padlen += inLen;
01458 *pnResultLen = 0;
01459 return;
01460 }
01461
01462
01463
01464 memcpy(outBuf,icc->m_padbuf,icc->m_padlen);
01465 updateLen = icc->m_padlen;
01466 icc->m_padlen = 0;
01467
01468
01469 int trailing = (inLen + updateLen) % icc->m_blockLen ?
01470 (inLen + updateLen) % icc->m_blockLen : icc->m_blockLen;
01471
01472
01473 int copied = inLen - trailing;
01474 memcpy(outBuf+updateLen,start,copied);
01475 start += copied;
01476 updateLen += copied;
01477
01478
01479 DWORD cbPlainText = 0;
01480
01481 if(!NT_SUCCESS(status = BCryptDecrypt( icc->m_hKey,outBuf,updateLen,NULL,
01482 (PBYTE)iv,ivLen,NULL,0,&cbPlainText,0)))
01483 {
01484 std::ostringstream os;
01485 os << "BCryptDecrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01486 << ")" << endl;
01487 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
01488 }
01489
01490 if(dwMaxOut < cbPlainText) {
01491 RAISE_CRYPTO_EXCEPTION("Decrypt() called with insufficient buffer available", m_parent->thisComponent, COMMON_INVALID_INPUT, NULL);
01492 }
01493 pkif_byte_array pbPlainText(new unsigned char[cbPlainText]);
01494 DWORD cbData = 0;
01495 if(!NT_SUCCESS(status = BCryptDecrypt(icc->m_hKey, outBuf, updateLen,
01496 NULL,(PBYTE)iv,ivLen,
01497 pbPlainText,cbPlainText,&cbData,
01498 0)))
01499 {
01500 std::ostringstream os;
01501 os << "BCryptDecrypt failed :(" << GetLastError() << ")" << "(NTSTATUS code " << status
01502 << ")" << endl;
01503 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPING_DECRYPT_FAILED, NULL);
01504 }
01505
01506 memcpy(pResult, pbPlainText.get(), cbData);
01507
01508
01509 memcpy(icc->m_padbuf,start,trailing);
01510 icc->m_padlen += trailing;
01511 try {
01512 *pnResultLen = boost::numeric_cast<int,DWORD>(cbData);
01513 }catch(...){
01514 RAISE_CRYPTO_EXCEPTION("BCryptDecrypt returned invalid length", TOOLKIT_CRYPTO, PKIFCAPING_ENCRYPT_FAILED, NULL);
01515 }
01516 }
01517 }
01518
01519
01532 IPKIFRawCryptContext* CPKIFCNGCAPIRaw::HMACInit(const CPKIFKeyMaterial &key, PKIFCRYPTO::HASH_ALG ha)
01533 {
01534 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::HMACInit(const CPKIFKeyMaterial& key, HASH_ALG ha)", thisComponent, 0, this);
01535 return 0;
01536
01537 wchar_t* hashAlg;
01538 switch(ha)
01539 {
01540 case PKIFCRYPTO::SHA1:
01541 hashAlg = BCRYPT_SHA1_ALGORITHM;
01542 break;
01543 case PKIFCRYPTO::SHA256:
01544 hashAlg = BCRYPT_SHA256_ALGORITHM;
01545 break;
01546 case PKIFCRYPTO::SHA384:
01547 hashAlg = BCRYPT_SHA384_ALGORITHM;
01548 break;
01549 case PKIFCRYPTO::SHA512:
01550 hashAlg = BCRYPT_SHA512_ALGORITHM;
01551 break;
01552 default:
01553 std::ostringstream os;
01554 os << "Unsupported hash algorithm encountered: " << hashAlg;
01555 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), thisComponent, CRYPTO_ALG_NOT_SUPPORTED, NULL);
01556 }
01557
01558
01559
01560 CPKIFCAPIRawCryptContext* cryptCtx = new CPKIFCAPIRawCryptContext();
01561 NTSTATUS status = STATUS_UNSUCCESSFUL;
01562 BCRYPT_ALG_HANDLE hHashAlg = NULL;
01563 DWORD cbData = 0,
01564 cbHash = 0,
01565 cbHashObject = 0;
01566 PBYTE pbHashObject = NULL;
01567 PBYTE pbHash = NULL;
01568
01569
01570 if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
01571 &hHashAlg,
01572 hashAlg,
01573 NULL,
01574 BCRYPT_ALG_HANDLE_HMAC_FLAG)))
01575 {
01576
01577 std::ostringstream os;
01578 os << "CryptCreateHash failed: " << GetLastError();;
01579 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
01580 }
01581
01582
01583 if(!NT_SUCCESS(status = BCryptGetProperty(
01584 hHashAlg,
01585 BCRYPT_OBJECT_LENGTH,
01586 (PBYTE)&cbHashObject,
01587 sizeof(DWORD),
01588 &cbData,
01589 0)))
01590 {
01591 std::ostringstream os;
01592 os << "BCryptGetProperty failed: " << GetLastError();;
01593 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
01594 }
01595
01596
01597 pbHashObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHashObject);
01598 if(NULL == pbHashObject)
01599 {
01600 std::ostringstream os;
01601 os << "Memory allocation failed: " << GetLastError();;
01602 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
01603 }
01604
01605
01606 if(!NT_SUCCESS(status = BCryptGetProperty(
01607 hHashAlg,
01608 BCRYPT_HASH_LENGTH,
01609 (PBYTE)&cbHash,
01610 sizeof(DWORD),
01611 &cbData,
01612 0)))
01613 {
01614 std::ostringstream os;
01615 os << "BCryptGetProperty failed: " << GetLastError();;
01616 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
01617 }
01618
01619
01620 if(!NT_SUCCESS(status = BCryptCreateHash(
01621 hHashAlg,
01622 &cryptCtx->m_cngHashHandle,
01623 pbHashObject,
01624 cbHashObject,
01625 (PBYTE)const_cast<unsigned char *>(key.GetSymmetricKey()),
01626 key.GetSymmetricKeyLength(),
01627 0)))
01628 {
01629 std::ostringstream os;
01630 os << "BCryptCreateHash failed: " << GetLastError();;
01631 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
01632 }
01633
01634 return cryptCtx;
01635 }
01636
01648 void CPKIFCNGCAPIRaw::HMACUpdate(IPKIFRawCryptContext* ctx, unsigned char* pData, int nDataLen)
01649 {
01650 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::HMACUpdate(IPKIFRawCryptContext* ctx, unsigned char* pData, int nDataLen)", thisComponent, 0, this);
01651
01652 NTSTATUS status = STATUS_UNSUCCESSFUL;
01653
01654
01655
01656
01657
01658 if(NULL == ctx || 0 > nDataLen)
01659 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HMACUpdate.");
01660
01661
01662
01663 CPKIFCAPIRawCryptContext* cryptCtx = dynamic_cast<CPKIFCAPIRawCryptContext*>(ctx);
01664 if(NULL == cryptCtx)
01665 throw CPKIFCryptoException(thisComponent, PKIFCAPI_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HMACUpdate.");
01666
01667 if(NULL == cryptCtx->m_cngHashHandle)
01668 throw CPKIFCryptoException(thisComponent, PKIFCAPI_EMPTY_HASH_CONTEXT, "Empty hash context passed to HMACUpdate.");
01669
01670
01671 if(!NT_SUCCESS(status = BCryptHashData(
01672 cryptCtx->m_cngHashHandle,
01673 (PBYTE)pData,
01674 nDataLen,
01675 0)))
01676 {
01677 std::ostringstream os;
01678 os << "BCryptHashData failed: " << GetLastError();;
01679 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
01680 }
01681 }
01682
01694 void CPKIFCNGCAPIRaw::HMACFinal(IPKIFRawCryptContext* ctx, unsigned char* pResult, int* pnResultLen)
01695 {
01696 LOG_STRING_DEBUG("CPKIFCNGCAPIRaw::HMACFinal(IPKIFRawCryptContext* ctx, unsigned char* pResult, int* pnResultLen)", thisComponent, 0, this);
01697
01698 NTSTATUS status = STATUS_UNSUCCESSFUL;
01699
01700
01701
01702
01703
01704 if(NULL == ctx || NULL == pResult || NULL == pnResultLen || 0 >= *pnResultLen)
01705 throw CPKIFCryptoException(thisComponent, COMMON_INVALID_INPUT, "NULL input passed to HMACFinal.");
01706
01707 CPKIFCAPIRawCryptContext* cryptCtx = dynamic_cast<CPKIFCAPIRawCryptContext*>(ctx);
01708 if(NULL == cryptCtx)
01709 throw CPKIFCryptoException(thisComponent, PKIFCAPI_INCORRECT_HASH_CONTEXT, "Incorrect hash context passed to HMACFinal.");
01710
01711 if(NULL == cryptCtx->m_cngHashHandle)
01712 throw CPKIFCryptoException(thisComponent, PKIFCAPI_EMPTY_HASH_CONTEXT, "Empty hash context passed to HMACFinal.");
01713
01714
01715
01716 if(!NT_SUCCESS(status = BCryptFinishHash(
01717 cryptCtx->m_cngHashHandle,
01718 pResult,
01719 *((DWORD*)pnResultLen),
01720 0)))
01721 {
01722 std::ostringstream os;
01723 os << "BCryptFinishHash failed: " << GetLastError();;
01724 RAISE_CRYPTO_EXCEPTION(os.str().c_str(), TOOLKIT_CRYPTO, PKIFCAPI_CREATE_HASH_FAILED, NULL);
01725 }
01726 }