Welcome to MSDN Blogs Sign in | Join | Help

Decrypt my World

Cryptography, Security, Debugging and more!

News

  • Any of my posts is supported under any Microsoft standard support program or service. They are provided "AS IS" without warranty of any kind, and confer no rights.

Where are my readers?

Locations of visitors to this page

Favorite Posts

How to sign and verify with CryptoAPI and a user certificate

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)

Posted: Wednesday, January 23, 2008 11:35 AM by alejacma
Filed under:

Comments

No Comments

Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker