Hi, welcome back,
Today I will show how to sign data and verify that signature using CryptoAPI and a certificate from our Personal store. The comments in the code should help to understand it. Remember that this is just a sample, and some more cleanup would be needed in case of error, for instance.
<SAMPLE>
// Includes #include <stdio.h> #include <conio.h> #include <windows.h> #include <wincrypt.h> // Defines #define CERT_PERSONAL_STORE_NAME L"My" #define CERT_OTHER_PEOPLE_STORE_NAME L"AddressBook" #define MY_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) #define BUFSIZE 1024 // Local functions void Sign(wchar_t * SignerName, wchar_t * DataFileName, wchar_t * SignatureFileName); void Verify(wchar_t * SignerName, wchar_t * SignatureFileName, wchar_t * DataFileName); // ShowUsageAndExit void ShowUsageAndExit() { wprintf(L"Usage:\n"); wprintf(L" - To sign: SignVerify s signer_name data_file signature_file\n"); wprintf(L" - To verify: SignVerify v signer_name data_file signature_file\n"); wprintf(L"\n<< Press any key to continue >>\n"); _getch(); exit(1); } // End of ShowUsageAndExit // CheckError void CheckError(BOOL condition, wchar_t * message) { wprintf(message); if (condition) { wprintf(L"SUCCESS\n"); } else { // TODO: Some cleanup wprintf(L"FAILURE (0x%x)\n", GetLastError()); wprintf(L"\n<< Press any key to continue >>\n"); _getch(); exit(1); } } // End CheckError // Main void wmain(int argc, wchar_t * argv[]) { // Usage if (argc != 5) { ShowUsageAndExit(); } if (!wcscmp(argv[1], L"s")) { // Sign Sign(argv[2], argv[3], argv[4]); } else if (!wcscmp(argv[1], L"v")) { // Verify Verify(argv[2], argv[3], argv[4]); } else { // Error ShowUsageAndExit(); } // The end wprintf(L"\n<< Press any key to continue >>\n"); _getch(); } // End of main // Sign void Sign(wchar_t * SignerName, wchar_t * DataFileName, wchar_t * SignatureFileName) { // Variables HCERTSTORE hStoreHandle = NULL; PCCERT_CONTEXT pSignerCert = NULL; HCRYPTPROV hCryptProv = NULL; DWORD dwKeySpec = 0; HCRYPTHASH hHash = NULL; HANDLE hDataFile = NULL; BOOL bResult = FALSE; BYTE rgbFile[BUFSIZE]; DWORD cbRead = 0; DWORD dwSigLen = 0; BYTE * pbSignature = NULL; HANDLE hSignatureFile = NULL; DWORD lpNumberOfBytesWritten = 0; wprintf(L"SIGNING\n\n"); // Open the certificate store. hStoreHandle = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, CERT_PERSONAL_STORE_NAME ); CheckError((BOOL)hStoreHandle, L"CertOpenStore....................... "); // Get signer's certificate with access to private key. do { // Get a certificate that matches the search criteria pSignerCert = CertFindCertificateInStore( hStoreHandle, MY_TYPE, 0, CERT_FIND_SUBJECT_STR, SignerName, pSignerCert ); CheckError((BOOL)pSignerCert, L"CertFindCertificateInStore.......... "); // Get the CSP, and check if we can sign with the private key bResult = CryptAcquireCertificatePrivateKey( pSignerCert, 0, NULL, &hCryptProv, &dwKeySpec, NULL ); CheckError(bResult, L"CryptAcquireCertificatePrivateKey... "); } while ((dwKeySpec & AT_SIGNATURE) != AT_SIGNATURE); // Create the hash object. bResult = CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash ); CheckError(bResult, L"CryptCreateHash..................... "); // Open the file with the content to be signed hDataFile = CreateFileW(DataFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL ); CheckError((hDataFile != INVALID_HANDLE_VALUE), L"CreateFile.......................... "); // Compute the cryptographic hash of the data. while (bResult = ReadFile(hDataFile, rgbFile, BUFSIZE, &cbRead, NULL)) { if (cbRead == 0) { break; } CheckError(bResult, L"ReadFile............................ "); bResult = CryptHashData( hHash, rgbFile, cbRead, 0 ); CheckError(bResult, L"CryptHashData....................... "); } CheckError(bResult, L"ReadFile............................ "); // Sign the hash object dwSigLen = 0; bResult = CryptSignHash( hHash, AT_SIGNATURE, NULL, 0, NULL, &dwSigLen ); CheckError(bResult, L"CryptSignHash....................... "); pbSignature = (BYTE *)malloc(dwSigLen); CheckError((BOOL)pbSignature, L"malloc.............................. "); bResult = CryptSignHash( hHash, AT_SIGNATURE, NULL, 0, pbSignature, &dwSigLen ); CheckError(bResult, L"CryptSignHash....................... "); // Create a file to save the signature hSignatureFile = CreateFileW( SignatureFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); CheckError((hSignatureFile != INVALID_HANDLE_VALUE), L"CreateFile.......................... "); // Write the signature to the file bResult = WriteFile( hSignatureFile, (LPCVOID)pbSignature, dwSigLen, &lpNumberOfBytesWritten, NULL ); CheckError(bResult, L"WriteFile........................... "); // Clean up and free memory. free(pbSignature); CloseHandle(hDataFile); CloseHandle(hSignatureFile); bResult = CryptDestroyHash(hHash); CheckError(bResult, L"CryptDestroyHash.................... "); bResult = CertFreeCertificateContext(pSignerCert); CheckError(bResult, L"CertFreeCertificateContext.......... "); bResult = CertCloseStore( hStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG ); CheckError(bResult, L"CertCloseStore...................... "); } // End of Sign // Verify void Verify(wchar_t * SignerName, wchar_t * DataFileName, wchar_t * SignatureFileName) { // Variables HCERTSTORE hStoreHandle = NULL; PCCERT_CONTEXT pSignerCert = NULL; DWORD dwKeySpec = 0; HCRYPTPROV hCryptProv = NULL; HCRYPTHASH hHash = NULL; HANDLE hDataFile = NULL; BOOL bResult = FALSE; BYTE rgbFile[BUFSIZE]; DWORD cbRead = 0; HANDLE hSignatureFile = NULL; BYTE * pbBinary = NULL; DWORD cbBinary = 0; HCRYPTKEY hPubKey = NULL; wprintf(L"VERIFYING\n\n"); // Open the certificate store. hStoreHandle = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, CERT_PERSONAL_STORE_NAME ); CheckError((BOOL)hStoreHandle, L"CertOpenStore....................... "); // Get a certificate that matches the search criteria pSignerCert = CertFindCertificateInStore( hStoreHandle, MY_TYPE, 0, CERT_FIND_SUBJECT_STR, SignerName, pSignerCert ); CheckError((BOOL)pSignerCert, L"CertFindCertificateInStore.......... "); // Get the CSP bResult = CryptAcquireContext( &hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ); CheckError(bResult, L"CryptAcquireContext................. "); // Create the hash object. bResult = CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash ); CheckError(bResult, L"CryptCreateHash..................... "); // Open the file with the content that was signed. hDataFile = CreateFileW( DataFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL ); CheckError((hDataFile != INVALID_HANDLE_VALUE), L"CreateFile.......................... "); // Compute the cryptographic hash of the data. while (bResult = ReadFile(hDataFile, rgbFile, BUFSIZE, &cbRead, NULL)) { if (cbRead == 0) { break; } CheckError(bResult, L"ReadFile............................ "); bResult = CryptHashData( hHash, rgbFile, cbRead, 0 ); CheckError(bResult, L"CryptHashData....................... "); } CheckError(bResult, L"ReadFile............................ "); // Open the file with the signature hSignatureFile = CreateFileW( SignatureFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL ); CheckError((hSignatureFile != INVALID_HANDLE_VALUE), L"CreateFile.......................... "); // Read the signature from the file pbBinary = (BYTE *)malloc(BUFSIZE); CheckError((BOOL)pbBinary, L"malloc.............................. "); bResult = ReadFile(hSignatureFile, pbBinary, BUFSIZE, &cbBinary, NULL); CheckError(bResult, L"ReadFile............................ "); // Get the public key from the certificate CryptImportPublicKeyInfo( hCryptProv, MY_TYPE, &pSignerCert->pCertInfo->SubjectPublicKeyInfo, &hPubKey ); CheckError(bResult, L"CryptImportPublicKeyInfo............ "); // Verify the signature bResult = CryptVerifySignature( hHash, pbBinary, cbBinary, hPubKey, NULL, 0 ); CheckError(bResult, L"CryptVerifySignature................ "); // Clean up and free memory. free(pbBinary); CloseHandle(hDataFile); CloseHandle(hSignatureFile); bResult = CryptDestroyHash(hHash); CheckError(bResult, L"CryptDestroyHash.................... "); bResult = CertFreeCertificateContext(pSignerCert); CheckError(bResult, L"CertFreeCertificateContext.......... "); bResult = CertCloseStore( hStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG ); CheckError(bResult, L"CertCloseStore...................... "); bResult = CryptReleaseContext( hCryptProv, 0 ); CheckError(bResult, L"CryptReleaseContext................. "); } // End of Verify
</SAMPLE>
I hope this helps.
Cheers,
Alex (Alejandro Campos Magencio)
thanks very much for this article.
this is exactly what i needed!
Hi,
I'm new to the cryptoAPI. I am trying to use it for automated code signing 'a la' signtool.exe but your code places the signature in a distinct file. What should be changed to add the signature to the file ?
Is there a way to strip a file of its signature in order to confirm that the signed file has the same "content " as its unsigned original ?
Hi dtieuf,
To sign binaries like you do with signtool, you can check these posts of mine:
How to sign EXE files with an Authenticode certificate (VB.NET)
blogs.msdn.com/.../how-to-sign-exe-files-with-an-authenticode-certificate-vb-net.aspx
How to sign EXE files with an Authenticode certificate (part 2)
blogs.msdn.com/.../how-to-sign-exe-files-with-an-authenticode-certificate-part-2.aspx
Thx,
Alex
Can you tell how can i attach signed hash to a binary or executable. I dont want to use a second file for storing hash. Is there any Crypto API available in C.
As you solved the same problem in VB Net , can you tell how can i do the same thing in C++
Hi vondamn,
To sign binaries programmatically, we use this:
How to sign EXE files with an Authenticode certificate (part 2)blogs.msdn.com/.../how-to-sign-exe-files-with-an-authenticode-certificate-part-2.aspx
Thank you sir.
I am able to sign my executable with Authenticode Certificate.
Now i need to verify this signed executable (done via SignerSignEx API) with the public key of the certificate.
Is there any link which does the same.
I don't have a sample for that, but if I recall well, you have to use WinVerifyTrust API for that (msdn.microsoft.com/.../aa388208(v=VS.85).aspx)
Hi Alejandro Campos Magencio,
I appreciate if you can tell me WinAPI which extracts the sign data from the signed file i..e i have a signed file and want to extracts its signed blob.
Thanks a lot.