void _libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx) { BCryptDestroyKey(ctx->hKey); if (ctx->pbKeyObject) { free(ctx->pbKeyObject); ctx->pbKeyObject = NULL; } memset(ctx, 0, sizeof(_libssh2_cipher_ctx)); }
void _libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa) { if (!rsa) return; BCryptDestroyKey(rsa->hKey); if (rsa->pbKeyObject) free(rsa->pbKeyObject); memset(rsa, 0, sizeof(libssh2_rsa_ctx)); free(rsa); }
static int aes_ctr_release(archive_crypto_ctx *ctx) { if (ctx->hAlg != NULL) { BCryptCloseAlgorithmProvider(ctx->hAlg, 0); ctx->hAlg = NULL; BCryptDestroyKey(ctx->hKey); ctx->hKey = NULL; HeapFree(GetProcessHeap(), 0, ctx->keyObj); ctx->keyObj = NULL; } memset(ctx, 0, sizeof(*ctx)); return 0; }
int aes_transformkey(m0_kdbx_header_entry_t *hdr, uint8_t *tkey, size_t tkeylen) { BCRYPT_ALG_HANDLE aes = NULL; BCRYPT_KEY_HANDLE key = NULL; NTSTATUS status = 0; DWORD len_ciphertext = 0, tmp_len = 0, key_objectlen = 0; PBYTE key_object = NULL; uint64_t rounds = 0; // Open an algorithm handle. status = BCryptOpenAlgorithmProvider( &aes, BCRYPT_AES_ALGORITHM, NULL, 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); goto cleanup; } // Calculate the size of the buffer to hold the KeyObject. status = BCryptGetProperty( aes, BCRYPT_OBJECT_LENGTH, (PBYTE)&key_objectlen, sizeof(DWORD), &tmp_len, 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptGetProperty\n", status); goto cleanup; } // Allocate the key object on the heap. key_object = (PBYTE)HeapAlloc(GetProcessHeap(), 0, key_objectlen); if(NULL == key_object) { printf("[!] memory allocation failed\n"); goto cleanup; } status = BCryptSetProperty( aes, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptSetProperty\n", status); goto cleanup; } // Generate the key from supplied input key bytes. status = BCryptGenerateSymmetricKey( aes, &key, key_object, key_objectlen, hdr[TRANSFORMSEED].data, hdr[TRANSFORMSEED].len, 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptGenerateSymmetricKey\n", status); goto cleanup; } status = BCryptEncrypt( key, tkey, tkeylen, NULL, NULL, 0, NULL, 0, &len_ciphertext, 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptEncrypt (calculate)\n", status); goto cleanup; } for(rounds = 0; rounds < hdr[TRANSFORMROUNDS].qw; rounds++) { status = BCryptEncrypt( key, tkey, tkeylen, NULL, NULL, 0, tkey, tkeylen, &tmp_len, 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptEncrypt (encrypt)\n", status); goto cleanup; } } cleanup: if(aes) { BCryptCloseAlgorithmProvider(aes,0); } if (key) { BCryptDestroyKey(key); } if(key_object) { HeapFree(GetProcessHeap(), 0, key_object); } return status; }
bool aes_decrypt_check(m0_kdbx_header_entry_t *hdr, uint8_t *masterkey, m0_kdbx_payload_t *payload) { bool res = false; BCRYPT_ALG_HANDLE aes = NULL; BCRYPT_KEY_HANDLE ctx = NULL; NTSTATUS status = 0; DWORD len_ciphertext = 0, tmp_len = 0, key_objectlen = 0; PBYTE key_object = NULL; uint8_t plaintext[32] = {0}; uint8_t iv[256] = {0}; uint8_t ivlen = hdr[ENCRYPTIONIV].len & 0xFF; // we need to create a local copy of IV, as it is modified during decryption. memcpy(&iv, hdr[ENCRYPTIONIV].data, ivlen); // Open an algorithm handle. status = BCryptOpenAlgorithmProvider( &aes, BCRYPT_AES_ALGORITHM, NULL, 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); goto cleanup; } // Calculate the size of the buffer to hold the Key Object. status = BCryptGetProperty( aes, BCRYPT_OBJECT_LENGTH, (PBYTE)&key_objectlen, sizeof(DWORD), &tmp_len, 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptGetProperty\n", status); goto cleanup; } // We should use preallocated memory for better performance... key_object = (PBYTE)HeapAlloc(GetProcessHeap(), 0, key_objectlen); if(NULL == key_object) { printf("[!] memory allocation failed\n"); goto cleanup; } status = BCryptSetProperty( aes, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptSetProperty\n", status); goto cleanup; } // Generate the key from supplied input key bytes. status = BCryptGenerateSymmetricKey( aes, &ctx, key_object, key_objectlen, masterkey, 32, 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptGenerateSymmetricKey\n", status); goto cleanup; } status = BCryptDecrypt( ctx, payload->encrypted, hdr[STREAMSTARTBYTES].len, NULL, iv, ivlen, plaintext, sizeof(plaintext), &tmp_len, 0); if(!NT_SUCCESS(status)) { printf("[!] Error 0x%x returned by BCryptDecrypt\n", status); goto cleanup; } // success! if (0 == memcmp(plaintext, hdr[STREAMSTARTBYTES].data, hdr[STREAMSTARTBYTES].len)) { res = true; payload->decrypted = malloc(hdr[STREAMSTARTBYTES].len); memcpy(payload->decrypted, plaintext, hdr[STREAMSTARTBYTES].len); } cleanup: if(aes) { BCryptCloseAlgorithmProvider(aes,0); } if (ctx) { BCryptDestroyKey(ctx); } if(key_object) { HeapFree(GetProcessHeap(), 0, key_object); } return res; }
int main(int argc, char **argv) { // Handles for RSA BCRYPT_ALG_HANDLE hAlgo = NULL; BCRYPT_KEY_HANDLE hKey = NULL; FILE_CRYPTO_INFO cryptoInfo; PBYTE psPlainText = NULL; DWORD dwBytesWritten = 0; DWORD dwBytesRead = 0; CCRYPT_STATUS status; // TEST DATA // PBYTE pbData1 = "Hello world!\n"; PBYTE pbData2 = "Hello person!\n"; PBYTE pbData3 = "This is cool!\n"; if (argc != 2) { printf("USAGE: %s <encrypt|decrypt>\n\n", argv[0]); return -1; } // -------------------------------------------------------------------------- // // Testing encrypting/writing to file // // -------------------------------------------------------------------------- if (strcmp(argv[1], "encrypt") == 0) { if (CCRYPT_STATUS_SUCCESS != (status = CCryptCreateFile(&cryptoInfo, TEXT("test.log"), CCRYPT_FILE_WRITE))) { printf("CCryptCreateFile error: %x\n", status); return -1; } // Write data to file if (!CCryptWriteFile(&cryptoInfo, pbData1, strlen(pbData1), &dwBytesWritten)) { printf("CCryptWriteFile error: %x\n", GetLastError()); return -1; } if (!CCryptWriteFile(&cryptoInfo, pbData2, strlen(pbData2), &dwBytesWritten)) { printf("CCryptWriteFile error: %x\n", GetLastError()); return -1; } if (!CCryptWriteFile(&cryptoInfo, pbData3, strlen(pbData3), &dwBytesWritten)) { printf("CCryptWriteFile error: %x\n", GetLastError()); return -1; } // Import our RSA public key to encrypt AES key if (CCRYPT_STATUS_SUCCESS != (status = RSAImportKey(&hAlgo, &hKey, TEXT("public.key"), BCRYPT_RSAPUBLIC_BLOB))) { printf("RSAImportKey error (public): %x\n", status); return -1; } // Finalize the file write if (!CCryptFinalizeFile(&cryptoInfo, hKey)) { printf("CCryptFinalizeFile error: %d\n", GetLastError()); return -1; } CCryptCloseHandle(&cryptoInfo); BCryptDestroyKey(hKey); BCryptCloseAlgorithmProvider(hAlgo, 0); } // -------------------------------------------------------------------------- // // Testing reading/decrypting from file // // -------------------------------------------------------------------------- else { if (CCRYPT_STATUS_SUCCESS != (status = CCryptCreateFile(&cryptoInfo, TEXT("test.log"), CCRYPT_FILE_READ))) { printf("CCryptCreateFile error: %x\n", status); return -1; } // Import our RSA private key to decrypt AES key if (CCRYPT_STATUS_SUCCESS != (status = RSAImportKey(&hAlgo, &hKey, TEXT("private.key"), BCRYPT_RSAPRIVATE_BLOB))) { printf("RSAImportKey error (private): %x\n", status); return -1; } if (!CCryptReadFile(&cryptoInfo, hKey, &psPlainText, &dwBytesRead)) { printf("CCryptReadFile error: %x\n", GetLastError()); return -1; } printf("Plain text: %s\n\n", psPlainText); if (psPlainText != NULL) { HeapFree(GetProcessHeap(), 0, psPlainText); } CCryptCloseHandle(&cryptoInfo); BCryptDestroyKey(hKey); BCryptCloseAlgorithmProvider(hAlgo, 0); } return 0; }
int _libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, LIBSSH2_SESSION *session, const char *filename, const unsigned char *passphrase) { #ifdef HAVE_LIBCRYPT32 BCRYPT_KEY_HANDLE hKey; unsigned char *pbEncoded, *pbStructInfo; unsigned long cbEncoded, cbStructInfo; int ret; (void)session; ret = _libssh2_wincng_load_private(session, filename, (const char *)passphrase, &pbEncoded, &cbEncoded); if (ret) { return -1; } ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, PKCS_RSA_PRIVATE_KEY, &pbStructInfo, &cbStructInfo); free(pbEncoded); if (ret) { return -1; } ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, LEGACY_RSAPRIVATE_BLOB, &hKey, pbStructInfo, cbStructInfo, 0); if (!BCRYPT_SUCCESS(ret)) { free(pbStructInfo); return -1; } *rsa = malloc(sizeof(libssh2_rsa_ctx)); if (!(*rsa)) { BCryptDestroyKey(hKey); free(pbStructInfo); return -1; } (*rsa)->hKey = hKey; (*rsa)->pbKeyObject = pbStructInfo; (*rsa)->cbKeyObject = cbStructInfo; return 0; #else (void)rsa; (void)filename; (void)passphrase; return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to load RSA key from private key file: " "Method unsupported in Windows CNG backend"); #endif /* HAVE_LIBCRYPT32 */ }
int _libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, const unsigned char *edata, unsigned long elen, const unsigned char *ndata, unsigned long nlen, const unsigned char *ddata, unsigned long dlen, const unsigned char *pdata, unsigned long plen, const unsigned char *qdata, unsigned long qlen, const unsigned char *e1data, unsigned long e1len, const unsigned char *e2data, unsigned long e2len, const unsigned char *coeffdata, unsigned long coefflen) { BCRYPT_KEY_HANDLE hKey; BCRYPT_RSAKEY_BLOB *rsakey; LPCWSTR lpszBlobType; unsigned char *key; unsigned long keylen, offset, mlen, p1len = 0, p2len = 0; int ret; mlen = max(_libssh2_wincng_bn_size(ndata, nlen), _libssh2_wincng_bn_size(ddata, dlen)); offset = sizeof(BCRYPT_RSAKEY_BLOB); keylen = offset + elen + mlen; if (ddata && dlen > 0) { p1len = max(_libssh2_wincng_bn_size(pdata, plen), _libssh2_wincng_bn_size(e1data, e1len)); p2len = max(_libssh2_wincng_bn_size(qdata, qlen), _libssh2_wincng_bn_size(e2data, e2len)); keylen += p1len * 3 + p2len * 2 + mlen; } key = malloc(keylen); if (!key) { return -1; } memset(key, 0, keylen); /* http://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ rsakey = (BCRYPT_RSAKEY_BLOB *)key; rsakey->BitLength = mlen * 8; rsakey->cbPublicExp = elen; rsakey->cbModulus = mlen; memcpy(key + offset, edata, elen); offset += elen; if (nlen < mlen) memcpy(key + offset + mlen - nlen, ndata, nlen); else memcpy(key + offset, ndata + nlen - mlen, mlen); if (ddata && dlen > 0) { offset += mlen; if (plen < p1len) memcpy(key + offset + p1len - plen, pdata, plen); else memcpy(key + offset, pdata + plen - p1len, p1len); offset += p1len; if (qlen < p2len) memcpy(key + offset + p2len - qlen, qdata, qlen); else memcpy(key + offset, qdata + qlen - p2len, p2len); offset += p2len; if (e1len < p1len) memcpy(key + offset + p1len - e1len, e1data, e1len); else memcpy(key + offset, e1data + e1len - p1len, p1len); offset += p1len; if (e2len < p2len) memcpy(key + offset + p2len - e2len, e2data, e2len); else memcpy(key + offset, e2data + e2len - p2len, p2len); offset += p2len; if (coefflen < p1len) memcpy(key + offset + p1len - coefflen, coeffdata, coefflen); else memcpy(key + offset, coeffdata + coefflen - p1len, p1len); offset += p1len; if (dlen < mlen) memcpy(key + offset + mlen - dlen, ddata, dlen); else memcpy(key + offset, ddata + dlen - mlen, mlen); lpszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB; rsakey->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC; rsakey->cbPrime1 = p1len; rsakey->cbPrime2 = p2len; } else { lpszBlobType = BCRYPT_RSAPUBLIC_BLOB; rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; rsakey->cbPrime1 = 0; rsakey->cbPrime2 = 0; } ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, lpszBlobType, &hKey, key, keylen, 0); if (!BCRYPT_SUCCESS(ret)) { free(key); return -1; } *rsa = malloc(sizeof(libssh2_rsa_ctx)); if (!(*rsa)) { BCryptDestroyKey(hKey); free(key); return -1; } (*rsa)->hKey = hKey; (*rsa)->pbKeyObject = key; (*rsa)->cbKeyObject = keylen; return 0; }
int _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, _libssh2_bn *a, _libssh2_bn *p, _libssh2_bn *m, _libssh2_bn_ctx *bnctx) { BCRYPT_KEY_HANDLE hKey; BCRYPT_RSAKEY_BLOB *rsakey; unsigned char *key, *bignum; unsigned long keylen, offset, length; int ret; (void)bnctx; if (!r || !a || !p || !m) return -1; offset = sizeof(BCRYPT_RSAKEY_BLOB); keylen = offset + p->length + m->length; key = malloc(keylen); if (!key) return -1; /* http://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ rsakey = (BCRYPT_RSAKEY_BLOB *)key; rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; rsakey->BitLength = m->length * 8; rsakey->cbPublicExp = p->length; rsakey->cbModulus = m->length; rsakey->cbPrime1 = 0; rsakey->cbPrime2 = 0; memcpy(key + offset, p->bignum, p->length); offset += p->length; memcpy(key + offset, m->bignum, m->length); ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, BCRYPT_NO_KEY_VALIDATION); if (BCRYPT_SUCCESS(ret)) { ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0, NULL, 0, &length, BCRYPT_PAD_NONE); if (BCRYPT_SUCCESS(ret)) { if (!_libssh2_wincng_bignum_resize(r, length)) { length = max(a->length, length); bignum = malloc(length); if (bignum) { offset = length - a->length; memset(bignum, 0, offset); memcpy(bignum + offset, a->bignum, a->length); ret = BCryptEncrypt(hKey, bignum, length, NULL, NULL, 0, r->bignum, r->length, &offset, BCRYPT_PAD_NONE); free(bignum); if (BCRYPT_SUCCESS(ret)) { _libssh2_wincng_bignum_resize(r, offset); } } else ret = STATUS_NO_MEMORY; } else ret = STATUS_NO_MEMORY; } BCryptDestroyKey(hKey); } free(key); return BCRYPT_SUCCESS(ret) ? 0 : -1; }
int _libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, _libssh2_cipher_type(type), unsigned char *iv, unsigned char *secret, int encrypt) { BCRYPT_KEY_HANDLE hKey; BCRYPT_KEY_DATA_BLOB_HEADER *header; unsigned char *pbKeyObject, *pbIV, *key; unsigned long dwKeyObject, dwIV, dwBlockLength, cbData, keylen; int ret; (void)encrypt; ret = BCryptGetProperty(*type.phAlg, BCRYPT_OBJECT_LENGTH, (unsigned char *)&dwKeyObject, sizeof(dwKeyObject), &cbData, 0); if (!BCRYPT_SUCCESS(ret)) { return -1; } ret = BCryptGetProperty(*type.phAlg, BCRYPT_BLOCK_LENGTH, (unsigned char *)&dwBlockLength, sizeof(dwBlockLength), &cbData, 0); if (!BCRYPT_SUCCESS(ret)) { return -1; } pbKeyObject = malloc(dwKeyObject); if (!pbKeyObject) { return -1; } keylen = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + type.dwKeyLength; key = malloc(keylen); if (!key) { free(pbKeyObject); return -1; } header = (BCRYPT_KEY_DATA_BLOB_HEADER *)key; header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; header->cbKeyData = type.dwKeyLength; memcpy(key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), secret, type.dwKeyLength); ret = BCryptImportKey(*type.phAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey, pbKeyObject, dwKeyObject, key, keylen, 0); free(key); if (!BCRYPT_SUCCESS(ret)) { free(pbKeyObject); return -1; } if (type.dwUseIV) { pbIV = malloc(dwBlockLength); if (!pbIV) { BCryptDestroyKey(hKey); free(pbKeyObject); return -1; } dwIV = dwBlockLength; memcpy(pbIV, iv, dwIV); } else { pbIV = NULL; dwIV = 0; } ctx->hKey = hKey; ctx->pbKeyObject = pbKeyObject; ctx->pbIV = pbIV; ctx->dwKeyObject = dwKeyObject; ctx->dwIV = dwIV; ctx->dwBlockLength = dwBlockLength; return 0; }
int _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, const unsigned char *pdata, unsigned long plen, const unsigned char *qdata, unsigned long qlen, const unsigned char *gdata, unsigned long glen, const unsigned char *ydata, unsigned long ylen, const unsigned char *xdata, unsigned long xlen) { BCRYPT_KEY_HANDLE hKey; BCRYPT_DSA_KEY_BLOB *dsakey; LPCWSTR lpszBlobType; unsigned char *key; unsigned long keylen, offset, length; int ret; length = max(max(_libssh2_wincng_bn_size(pdata, plen), _libssh2_wincng_bn_size(gdata, glen)), _libssh2_wincng_bn_size(ydata, ylen)); offset = sizeof(BCRYPT_DSA_KEY_BLOB); keylen = offset + length * 3; if (xdata && xlen > 0) keylen += 20; key = malloc(keylen); if (!key) { return -1; } memset(key, 0, keylen); /* http://msdn.microsoft.com/library/windows/desktop/aa833126.aspx */ dsakey = (BCRYPT_DSA_KEY_BLOB *)key; dsakey->cbKey = length; memset(dsakey->Count, -1, sizeof(dsakey->Count)); memset(dsakey->Seed, -1, sizeof(dsakey->Seed)); if (qlen < 20) memcpy(dsakey->q + 20 - qlen, qdata, qlen); else memcpy(dsakey->q, qdata + qlen - 20, 20); if (plen < length) memcpy(key + offset + length - plen, pdata, plen); else memcpy(key + offset, pdata + plen - length, length); offset += length; if (glen < length) memcpy(key + offset + length - glen, gdata, glen); else memcpy(key + offset, gdata + glen - length, length); offset += length; if (ylen < length) memcpy(key + offset + length - ylen, ydata, ylen); else memcpy(key + offset, ydata + ylen - length, length); if (xdata && xlen > 0) { offset += length; if (xlen < 20) memcpy(key + offset + 20 - xlen, xdata, xlen); else memcpy(key + offset, xdata + xlen - 20, 20); lpszBlobType = BCRYPT_DSA_PRIVATE_BLOB; dsakey->dwMagic = BCRYPT_DSA_PRIVATE_MAGIC; } else { lpszBlobType = BCRYPT_DSA_PUBLIC_BLOB; dsakey->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC; } ret = BCryptImportKeyPair(_libssh2_wincng.hAlgDSA, NULL, lpszBlobType, &hKey, key, keylen, 0); if (!BCRYPT_SUCCESS(ret)) { free(key); return -1; } *dsa = malloc(sizeof(libssh2_dsa_ctx)); if (!(*dsa)) { BCryptDestroyKey(hKey); free(key); return -1; } (*dsa)->hKey = hKey; (*dsa)->pbKeyObject = key; (*dsa)->cbKeyObject = keylen; return 0; }
/***************************************************************************** HrVerify This sample demontrates XML signature verification *****************************************************************************/ HRESULT HrVerify( LPCWSTR wszFileIn ) { HRESULT hr = S_FALSE; HCRYPTXML hDoc = NULL; ULONG i; const CRYPT_XML_DOC_CTXT *pDoc = NULL; const CRYPT_XML_SIGNATURE *pSig = NULL; const CRYPT_XML_REFERENCE *pRef = NULL; CRYPT_XML_STATUS Status = {0}; BCRYPT_KEY_HANDLE hKey = NULL; BCRYPT_KEY_HANDLE hKeyAlloc = NULL; // BCryptDestroyKey PCCERT_CONTEXT pCert = NULL; CRYPT_XML_DATA_PROVIDER DataProvider = {0}; CRYPT_XML_BLOB Encoded = { CRYPT_XML_CHARSET_AUTO, 0, NULL }; hr = HrLoadFile( wszFileIn, &Encoded.pbData, &Encoded.cbData ); if( FAILED(hr) ) { goto CleanUp; } hr = CryptXmlOpenToDecode( NULL, // no custom transforms 0, NULL, 0, &Encoded, &hDoc ); if( FAILED(hr) ) { goto CleanUp; } hr = CryptXmlGetDocContext( hDoc, &pDoc ); if( FAILED(hr) ) { goto CleanUp; } if( pDoc->cSignature < 1 ) { wprintf( L"WARNING: The document contains no Signature element.\r\n" ); // No signatures found hr = S_FALSE; goto CleanUp; } for( i=0; i<pDoc->cSignature; i++ ) { hKey = NULL; if( NULL == hKeyAlloc ) { BCryptDestroyKey( hKeyAlloc ); hKeyAlloc = NULL; } // // Find Signer's certificate // for( ULONG ki=0; ki<pDoc->rgpSignature[i]->pKeyInfo->cKeyInfo && NULL == hKey; ki++ ) { if( CRYPT_XML_KEYINFO_TYPE_X509DATA == pDoc->rgpSignature[i]->pKeyInfo->rgKeyInfo[ki].dwType ) { for( ULONG x=0; x<pDoc->rgpSignature[i]->pKeyInfo->rgKeyInfo[ki].X509Data.cX509Data; x++ ) { CRYPT_XML_X509DATA_ITEM *pX = &pDoc->rgpSignature[i]->pKeyInfo->rgKeyInfo[ki].X509Data.rgX509Data[x]; if( CRYPT_XML_X509DATA_TYPE_CERTIFICATE == pX->dwType ) { // // SAMPLE: Just assume that the first cert is the one ... // In production code, implement the full logic // to find the signer's cert, from a set of multiple X.509 data elements // pCert = CertCreateCertificateContext( X509_ASN_ENCODING, pX->Certificate.pbData, pX->Certificate.cbData ); if( NULL != pCert ) { if( CryptImportPublicKeyInfoEx2( X509_ASN_ENCODING, &pCert->pCertInfo->SubjectPublicKeyInfo, CRYPT_OID_INFO_PUBKEY_SIGN_KEY_FLAG, NULL, &hKeyAlloc )) { hKey = hKeyAlloc; break; } } } } } } if( NULL == hKey ) { wprintf( L"ERROR: Unable to find signer's key to verify signature [%d] Id='%s'\r\n", i, pDoc->rgpSignature[i]->wszId ); hr = CRYPT_XML_E_SIGNER; goto CleanUp; } // // SAMPLE: Verify Signer's Trust // { // // TODO: Use CertGetCertificateChain() to build the chain and verify the trust. // // // TODO: Accept only strong cryptographic algorithms and key strengths. // Also, place max key length on key size to avoid Denial of Service (DoS) // attacks on verification key operations. // } hr = CryptXmlVerifySignature( pDoc->rgpSignature[i]->hSignature, hKey, 0 ); if( FAILED(hr) ) { wprintf( L"FAIL: CryptXmlVerifySignature() returned 0x%08x error on signature [%d] Id='%s'\r\n", hr, i, pDoc->rgpSignature[i]->wszId ); goto CleanUp; } wprintf( L"Signature Value on signature [%d] Id='%s' is valid.\r\n", i, pDoc->rgpSignature[i]->wszId ); // // Verify References // hr = CryptXmlGetSignature( pDoc->rgpSignature[i]->hSignature, &pSig ); if( FAILED(hr) ) { goto CleanUp; } for( ULONG r=0; r<pSig->SignedInfo.cReference; r++ ) { hr = CryptXmlGetReference( pSig->SignedInfo.rgpReference[r]->hReference, &pRef ); if( FAILED(hr) ) { goto CleanUp; } hr = CryptXmlGetStatus( pSig->SignedInfo.rgpReference[r]->hReference, &Status ); if( FAILED(hr) ) { goto CleanUp; } if( 0 != ( Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED )) { // // Resolve the external references only. // The internal references was resolved by CryptXml during CryptXmlVerifySignature // if( 0 == ( Status.dwInfoStatus & CRYPT_XML_STATUS_INTERNAL_REFERENCE )) { // // TODO: Verify the scope of the Reference Target URI prior to resolving // hr = HrSampleResolveExternalXmlReference( pRef->wszUri, &DataProvider ); if( FAILED(hr) ) { goto CleanUp; } } if( NULL == DataProvider.pfnRead ) { hr = CRYPT_XML_E_UNRESOLVED_REFERENCE; goto CleanUp; } // // Provider must be released by the callee // hr = CryptXmlDigestReference( pSig->SignedInfo.rgpReference[r]->hReference, 0, &DataProvider ); ZeroMemory( &DataProvider, sizeof DataProvider ); // // Get the status to check it again // hr = CryptXmlGetStatus( pSig->SignedInfo.rgpReference[r]->hReference, &Status ); } if( 0 != ( Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_DIGEST_INVALID )) { wprintf( L"Digest Value on reference[%d] Id='%s' is not valid.\r\n", r, pSig->SignedInfo.rgpReference[r]->wszId ); } else { if( 0 != ( Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED )) { wprintf( L"Reference[%d] Id='%s' is not resolved\r\n", r, pSig->SignedInfo.rgpReference[r]->wszId ); } else { wprintf( L"Digest Value on reference[%d] Id='%s' is valid\r\n", r, pSig->SignedInfo.rgpReference[r]->wszId ); } } } // // Average status on the Signature // hr = CryptXmlGetStatus( pDoc->rgpSignature[i]->hSignature, &Status ); if( FAILED(hr) ) { goto CleanUp; } if( 0 != ( Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_DIGEST_INVALID )) { hr = CRYPT_XML_E_INVALID_DIGEST; goto CleanUp; } if( 0 != ( Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED )) { hr = CRYPT_XML_E_UNRESOLVED_REFERENCE; goto CleanUp; } } hr = S_OK; CleanUp: if( NULL != Encoded.pbData ) { LocalFree( Encoded.pbData ); } if( NULL == hKeyAlloc ) { BCryptDestroyKey( hKeyAlloc ); } if( NULL != pCert ) { CertFreeCertificateContext( pCert ); } return hr; }
UINT SfDecryptPayload( LPWSTR lpParameter ) { BOOL cond = FALSE, bSuccess = FALSE; PBYTE cng_object, hashdata, decrypted, enc_data, extracted; ULONG obj_sz, rlen, hdatasz, enc_data_size; BCRYPT_ALG_HANDLE h_alg = NULL; BCRYPT_HASH_HANDLE h_hash = NULL; BCRYPT_KEY_HANDLE h_rc4key = NULL; NTSTATUS status; HANDLE pheap = NULL; PIMAGE_FILE_HEADER fheader; PVOID pdll = NULL; WCHAR InputFile[MAX_PATH + 1], OutputFile[MAX_PATH + 1]; rlen = 0; RtlSecureZeroMemory(InputFile, sizeof(InputFile)); GetCommandLineParam(lpParameter, 1, InputFile, MAX_PATH, &rlen); if (rlen == 0) { SfcuiPrintText(g_ConOut, T_SFDECRYPTUSAGE, g_ConsoleOutput, FALSE); return (UINT)-1; } do { rlen = 0; GetCommandLineParam(lpParameter, 2, OutputFile, MAX_PATH, &rlen); if (rlen == 0) _strcpy(OutputFile, TEXT("out.bin")); pdll = SfuCreateFileMappingNoExec(InputFile); if (pdll == NULL) break; enc_data_size = 0; enc_data = SfuQueryResourceData(2, pdll, &enc_data_size); if (enc_data == NULL) break; fheader = &(RtlImageNtHeader(pdll)->FileHeader); status = BCryptOpenAlgorithmProvider(&h_alg, BCRYPT_MD5_ALGORITHM, NULL, 0); if (!NT_SUCCESS(status)) break; obj_sz = 0; rlen = 0; status = BCryptGetProperty(h_alg, BCRYPT_OBJECT_LENGTH, (PUCHAR)&obj_sz, sizeof(obj_sz), &rlen, 0); if (!NT_SUCCESS(status)) break; hdatasz = 0; rlen = 0; status = BCryptGetProperty(h_alg, BCRYPT_HASH_LENGTH, (PUCHAR)&hdatasz, sizeof(hdatasz), &rlen, 0); if (!NT_SUCCESS(status)) break; pheap = HeapCreate(0, 0, 0); if (pheap == NULL) break; cng_object = HeapAlloc(pheap, HEAP_ZERO_MEMORY, obj_sz); if (cng_object == NULL) break; hashdata = HeapAlloc(pheap, HEAP_ZERO_MEMORY, hdatasz); if (hashdata == NULL) break; status = BCryptCreateHash(h_alg, &h_hash, cng_object, obj_sz, NULL, 0, 0); if (!NT_SUCCESS(status)) break; status = BCryptHashData(h_hash, (PUCHAR)fheader, sizeof(IMAGE_FILE_HEADER), 0); if (!NT_SUCCESS(status)) break; status = BCryptFinishHash(h_hash, hashdata, hdatasz, 0); if (!NT_SUCCESS(status)) break; BCryptDestroyHash(h_hash); BCryptCloseAlgorithmProvider(h_alg, 0); HeapFree(pheap, 0, cng_object); h_alg = NULL; h_hash = NULL; status = BCryptOpenAlgorithmProvider(&h_alg, BCRYPT_RC4_ALGORITHM, NULL, 0); if (!NT_SUCCESS(status)) break; obj_sz = 0; rlen = 0; status = BCryptGetProperty(h_alg, BCRYPT_OBJECT_LENGTH, (PUCHAR)&obj_sz, sizeof(obj_sz), &rlen, 0); if (!NT_SUCCESS(status)) break; cng_object = HeapAlloc(pheap, HEAP_ZERO_MEMORY, obj_sz); if (cng_object == NULL) break; status = BCryptGenerateSymmetricKey(h_alg, &h_rc4key, cng_object, obj_sz, hashdata, hdatasz, 0); if (!NT_SUCCESS(status)) break; decrypted = HeapAlloc(pheap, HEAP_ZERO_MEMORY, enc_data_size); if (decrypted == NULL) break; rlen = 0; status = BCryptEncrypt(h_rc4key, enc_data, enc_data_size, NULL, NULL, 0, decrypted, enc_data_size, &rlen, 0); if (!NT_SUCCESS(status)) break; bSuccess = FALSE; enc_data_size = rlen; rlen = 0; extracted = SfcabExtractMemory(decrypted, enc_data_size, &rlen); if (extracted) { if (SfuWriteBufferToFile(OutputFile, extracted, rlen, FALSE, FALSE) == rlen) { bSuccess = TRUE; } LocalFree(extracted); } else { //failed to extract, drop cab as is if (SfuWriteBufferToFile(OutputFile, decrypted, enc_data_size, FALSE, FALSE) == enc_data_size) { bSuccess = TRUE; } } if (bSuccess) { SfcuiPrintText(g_ConOut, T_SFDECRYPTED, g_ConsoleOutput, FALSE); SfcuiPrintText(g_ConOut, OutputFile, g_ConsoleOutput, FALSE); } } while (cond); if (bSuccess == FALSE) { SfcuiPrintText(g_ConOut, T_SFDECRYPTFAIL, g_ConsoleOutput, FALSE); } if (h_rc4key != NULL) BCryptDestroyKey(h_rc4key); if (h_hash != NULL) BCryptDestroyHash(h_hash); if (h_alg != NULL) BCryptCloseAlgorithmProvider(h_alg, 0); if (pheap != NULL) HeapDestroy(pheap); if (pdll != 0) NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)pdll); return 0; }
//---------------------------------------------------------------------------- // // PerformKeyDerivation // //---------------------------------------------------------------------------- NTSTATUS PeformKeyDerivation( _In_ DWORD ArrayIndex ) { NTSTATUS Status; BCRYPT_ALG_HANDLE KdfAlgHandle = NULL; BCRYPT_KEY_HANDLE SecretKeyHandle = NULL; DWORD ResultLength = 0; PBYTE DerivedKey = NULL; DWORD DerivedKeyLength = 0; Status = BCryptOpenAlgorithmProvider( &KdfAlgHandle, // Alg Handle pointer KdfAlgorithmNameArray[ArrayIndex], // Cryptographic Algorithm name (null terminated unicode string) NULL, // Provider name; if null, the default provider is loaded 0); // Flags if( !NT_SUCCESS(Status) ) { ReportError(Status); goto cleanup; } Status = BCryptGenerateSymmetricKey( KdfAlgHandle, // Algorithm Handle &SecretKeyHandle, // A pointer to a key handle NULL, // Buffer that recieves the key object;NULL implies memory is allocated and freed by the function 0, // Size of the buffer in bytes (PBYTE) Secret, // Buffer that contains the key material sizeof(Secret), // Size of the buffer in bytes 0); // Flags if( !NT_SUCCESS(Status) ) { ReportError(Status); goto cleanup; } // // Derive the key // DerivedKeyLength = DERIVED_KEY_LEN; DerivedKey = (PBYTE)HeapAlloc(GetProcessHeap(), 0, DerivedKeyLength); if( NULL == DerivedKey ) { Status = STATUS_NO_MEMORY; ReportError(Status); goto cleanup; } // Generic parameters: // KDF_GENERIC_PARAMETER and KDF_HASH_ALGORITHM are the generic parameters that can be passed for the following KDF algorithms: // BCRYPT_SP800108_CTR_HMAC_ALGORITHM // KDF_GENERIC_PARAMETER = KDF_LABEL||0x00||KDF_CONTEXT // BCRYPT_SP80056A_CONCAT_ALGORITHM // KDF_GENERIC_PARAMETER = KDF_ALGORITHMID || KDF_PARTYUINFO || KDF_PARTYVINFO {|| KDF_SUPPPUBINFO } {|| KDF_SUPPPRIVINFO } // BCRYPT_PBKDF2_ALGORITHM // KDF_GENERIC_PARAMETER = KDF_SALT // BCRYPT_CAPI_KDF_ALGORITHM // KDF_GENERIC_PARAMETER = Not used // // Alternatively, KDF specific parameters can be passed. // For BCRYPT_SP800108_CTR_HMAC_ALGORITHM: // KDF_HASH_ALGORITHM, KDF_LABEL and KDF_CONTEXT are required // For BCRYPT_SP80056A_CONCAT_ALGORITHM: // KDF_HASH_ALGORITHM, KDF_ALGORITHMID, KDF_PARTYUINFO, KDF_PARTYVINFO are required // KDF_SUPPPUBINFO, KDF_SUPPPRIVINFO are optional // For BCRYPT_PBKDF2_ALGORITHM // KDF_HASH_ALGORITHM is required // KDF_ITERATION_COUNT, KDF_SALT are optional // Iteration count, (if not specified) will default to 10,000 // For BCRYPT_CAPI_KDF_ALGORITHM // KDF_HASH_ALGORITHM is required // // // This sample uses KDF specific parameters defined in KeyDerivation.h // Status = BCryptKeyDerivation( SecretKeyHandle, // Handle to the password key &ParamList[ArrayIndex], // Parameters to the KDF algorithm DerivedKey, // Address of the buffer which recieves the derived bytes DerivedKeyLength, // Size of the buffer in bytes &ResultLength, // Variable that recieves number of bytes copied to above buffer 0); // Flags if( !NT_SUCCESS(Status) ) { ReportError(Status); goto cleanup; } // // DerivedKeyLength bytes have been derived // cleanup: if( NULL != DerivedKey ) { HeapFree( GetProcessHeap(), 0, DerivedKey); DerivedKey = NULL; } if( NULL != SecretKeyHandle ) { Status = BCryptDestroyKey(SecretKeyHandle); if( !NT_SUCCESS(Status) ) { ReportError(Status); } SecretKeyHandle = NULL; } if( NULL != KdfAlgHandle ) { Status = BCryptCloseAlgorithmProvider(KdfAlgHandle,0); if( !NT_SUCCESS(Status) ) { ReportError(Status); } KdfAlgHandle = NULL; } return Status; }