windows Sdk for windows7 提供的CrytoAPI是微软推出的安全应用调用函数,用很小的代码就可以实现复杂的安全信息加密。
下面演示对于消息加密与签名,详情请见代码。可以用于信息安全。
包括windows的消息都可以进行签名,防止消息hook,防止消息钩子,防止消息被攥改!
//------------------------------------------------------------------- // 程序功能: 用发送者私钥签名消息,然后用接收者公钥加密签名消息。 #include <stdio.h> #include <tchar.h> #include <windows.h> #include <wincrypt.h> #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) #define MAX_NAME 128 #define SIGNER_NAME L"DUMMY_SIGNER_NAME" //签名者证书名称 #define RECEIVER_NAME L"China-wuhan-ruanou" //接收者证书名称 //函数申明 void HandleError(char *s); void ShowBytes(BYTE *s, DWORD len); BYTE* SignAndEncrypt( const BYTE *pbToBeSignedAndEncrypted, DWORD cbToBeSignedAndEncrypted, DWORD *pcbSignedAndEncryptedBlob); BYTE* DecryptAndVerify( BYTE *pbSignedAndEncryptedBlob, DWORD cbSignedAndEncryptedBlob); void main (void) { //--------------------------------------------------------------- // 变量申明与初始化 //--------------------------------------------------------------- // pbToBeSignedAndEncrypted 为要签名与加密的消息,即原文消息 const BYTE *pbToBeSignedAndEncrypted = (const unsigned char *)"在这里插入要签名的消息"; DWORD cbToBeSignedAndEncrypted = lstrlenA((const char *)pbToBeSignedAndEncrypted) + 1; //消息长度 BYTE *pbSignedAndEncryptedBlob; //加密和签名后的消息 DWORD cbSignedAndEncryptedBlob; //加密和签名后的消息长度 BYTE *pReturnMessage; //--------------------------------------------------------------- // 调用SignAndEncrypt函数签名并加密消息,函数返回签名并加密后的消息及消息长度. pbSignedAndEncryptedBlob = SignAndEncrypt( pbToBeSignedAndEncrypted, cbToBeSignedAndEncrypted, &cbSignedAndEncryptedBlob); printf(TEXT("下面是签名和加密后的") TEXT("消息./n")); ShowBytes(pbSignedAndEncryptedBlob,cbSignedAndEncryptedBlob/4); //--------------------------------------------------------------- // 调用函数DecryptAndVerify解密消息并验证消息签名 if(pReturnMessage = DecryptAndVerify( pbSignedAndEncryptedBlob, cbSignedAndEncryptedBlob)) { printf(TEXT("返回验证后的消息是 ->/n%s/n"), pReturnMessage); printf(TEXT("此程序执行无错./n")); } else { printf(TEXT("Verification failed./n")); } } // End Main. //------------------------------------------------------------------- // 功能:签名原文消息,并加密此消息 // 返回值:签名并加密后的消息 // 参数: // pbToBeSignedAndEncrypted 欲签名并加密消息 // cbToBeSignedAndEncrypted 欲签名并加密消息长度 // pcbSignedAndEncryptedBlob 签名并加密后的消息长度 BYTE* SignAndEncrypt( const BYTE *pbToBeSignedAndEncrypted, DWORD cbToBeSignedAndEncrypted, DWORD *pcbSignedAndEncryptedBlob) { //--------------------------------------------------------------- // 变量申明与初始化 HCERTSTORE hCertStore; //证书库 PCCERT_CONTEXT pSignerCertContext ; //签名证书 PCCERT_CONTEXT pReceiverCertContext; //接收者证书 TCHAR pszNameString[256]; CRYPT_SIGN_MESSAGE_PARA SignPara; //签名参数结构 CRYPT_ENCRYPT_MESSAGE_PARA EncryptPara; //加密参数结构 DWORD cRecipientCert; PCCERT_CONTEXT rgpRecipientCert[5]; BYTE *pbSignedAndEncryptedBlob = NULL; DWORD dwKeySpec; HCRYPTPROV hCryptProv; //--------------------------------------------------------------- // 打开“MY”证书库 if ( !( hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"my"))) { HandleError(TEXT("MY 证书库不能打开.")); } //--------------------------------------------------------------- // 获取签名证书,此证书包含签名密钥对 if(!(pSignerCertContext = CertFindCertificateInStore( hCertStore, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_STR, SIGNER_NAME, NULL))) { HandleError(TEXT("发送者证书未找到./n")); } //--------------------------------------------------------------- // 获取消息签名者证书名称 if(CertGetNameString( pSignerCertContext , CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pszNameString, MAX_NAME) > 1) { _tprintf( TEXT("SIMPLE_DISPLAY_TYPE 消息签名者的名称是 ") TEXT("%s /n"), pszNameString); } else { HandleError(TEXT("获取签名者的名称失败./n")); } //获取签名者证书私钥 if(!( CryptAcquireCertificatePrivateKey( pSignerCertContext, 0, NULL, &hCryptProv, &dwKeySpec, NULL))) { HandleError(TEXT("CryptAcquireCertificatePrivateKey./n")); } // 获取接收者证书 if(!(pReceiverCertContext = CertFindCertificateInStore( hCertStore, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_STR, RECEIVER_NAME, NULL))) { HandleError(TEXT("接收者证书未找到./n")); } //--------------------------------------------------------------- // 获取接收者证书名称. if(CertGetNameString( pReceiverCertContext , CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pszNameString, MAX_NAME) > 1) { _tprintf(TEXT("消息接收者是 %s /n"), pszNameString); } else { HandleError(TEXT("获取接收者的名称失败./n")); } //--------------------------------------------------------------- // 初始化签名参数结构 SignPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA); SignPara.dwMsgEncodingType = MY_ENCODING_TYPE; SignPara.pSigningCert = pSignerCertContext ; SignPara.HashAlgorithm.pszObjId = szOID_RSA_MD2; SignPara.HashAlgorithm.Parameters.cbData = 0; SignPara.pvHashAuxInfo = NULL; SignPara.cMsgCert = 1; SignPara.rgpMsgCert = &pSignerCertContext ; SignPara.cMsgCrl = 0; SignPara.rgpMsgCrl = NULL; SignPara.cAuthAttr = 0; SignPara.rgAuthAttr = NULL; SignPara.cUnauthAttr = 0; SignPara.rgUnauthAttr = NULL; SignPara.dwFlags = 0; SignPara.dwInnerContentType = 0; //--------------------------------------------------------------- // 初始化加密参数结构 EncryptPara.cbSize = sizeof(CRYPT_ENCRYPT_MESSAGE_PARA); EncryptPara.dwMsgEncodingType = MY_ENCODING_TYPE; EncryptPara.hCryptProv = 0; EncryptPara.ContentEncryptionAlgorithm.pszObjId = szOID_RSA_RC4; EncryptPara.ContentEncryptionAlgorithm.Parameters.cbData = 0; EncryptPara.pvEncryptionAuxInfo = NULL; EncryptPara.dwFlags = 0; EncryptPara.dwInnerContentType = 0; cRecipientCert = 1; rgpRecipientCert[0] = pReceiverCertContext; *pcbSignedAndEncryptedBlob = 0; pbSignedAndEncryptedBlob = NULL; //获取签名并加密后的消息长度 if( CryptSignAndEncryptMessage( &SignPara, //签名参数结构 &EncryptPara, //加密参数结构 cRecipientCert, //接收者证书数目 rgpRecipientCert, //接收者证书列表 pbToBeSignedAndEncrypted, //欲签名并加密消息 cbToBeSignedAndEncrypted, //欲签名并加密消息长度 NULL, //签名并加密后的消息 pcbSignedAndEncryptedBlob)) //签名并加密后的消息长度 { _tprintf(TEXT("%d 字节分配给了缓冲区./n"), *pcbSignedAndEncryptedBlob); } else { HandleError(TEXT("获取缓冲区长度失败.")); } //--------------------------------------------------------------- // 分配内存 if(!(pbSignedAndEncryptedBlob = (unsigned char *)malloc(*pcbSignedAndEncryptedBlob))) { HandleError(TEXT("内存分配失败.")); } //--------------------------------------------------------------- // 签名消息,并对前面消息加密 if( CryptSignAndEncryptMessage( &SignPara, //签名参数结构 &EncryptPara, //加密参数结构 cRecipientCert, //接收者证书数目 rgpRecipientCert, //接收者证书列表 pbToBeSignedAndEncrypted, //欲签名并加密消息 cbToBeSignedAndEncrypted, //欲签名并加密消息长度 pbSignedAndEncryptedBlob, //签名并加密后的消息 pcbSignedAndEncryptedBlob)) //签名并加密后的消息长度 { _tprintf(TEXT("此消息已经被签名并加密./n")); } else { HandleError(TEXT("此消息签名和加密失败.")); } //--------------------------------------------------------------- // 释放空间 if(pSignerCertContext ) { CertFreeCertificateContext(pSignerCertContext); } if(pReceiverCertContext ) { CertFreeCertificateContext(pReceiverCertContext); } CertCloseStore(hCertStore, 0); //--------------------------------------------------------------- // 返回签名并加密后的消息 return pbSignedAndEncryptedBlob; } // End SignAndEncrypt. //------------------------------------------------------------------- // 功能:解密消息,验证其签名 // 返回值:解密后消息 // 参数: // pbSignedAndEncryptedBlob 签名并加密后的消息 // cbSignedAndEncryptedBlob 签名并加密后的消息长度 BYTE* DecryptAndVerify( BYTE *pbSignedAndEncryptedBlob, DWORD cbSignedAndEncryptedBlob) { //--------------------------------------------------------------- // 变量申明与初始化 HCERTSTORE hCertStore; CRYPT_DECRYPT_MESSAGE_PARA DecryptPara; CRYPT_VERIFY_MESSAGE_PARA VerifyPara; DWORD dwSignerIndex = 0; BYTE *pbDecrypted; DWORD cbDecrypted; //--------------------------------------------------------------- // 打开“my”证书库 if ( !( hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"my"))) { HandleError(TEXT("MY 证书库不能被打开.")); } //--------------------------------------------------------------- // 初始化解密参数结构 DecryptPara.cbSize = sizeof(CRYPT_DECRYPT_MESSAGE_PARA); DecryptPara.dwMsgAndCertEncodingType = MY_ENCODING_TYPE; DecryptPara.cCertStore = 1; DecryptPara.rghCertStore = &hCertStore; //--------------------------------------------------------------- // 初始化验证参数结构 VerifyPara.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA); VerifyPara.dwMsgAndCertEncodingType = MY_ENCODING_TYPE; VerifyPara.hCryptProv = 0; VerifyPara.pfnGetSignerCertificate = NULL; VerifyPara.pvGetArg = NULL; pbDecrypted = NULL; cbDecrypted = 0; //--------------------------------------------------------------- // 确定解密后消息长度 if(!(CryptDecryptAndVerifyMessageSignature( &DecryptPara, //解密参数结构体 &VerifyPara, //验证参数结构体 dwSignerIndex, //签名消息序号 pbSignedAndEncryptedBlob, //签名、加密、编码后的数据 cbSignedAndEncryptedBlob, //签名、加密、编码后的数据长度 NULL, //解密后的数据 &cbDecrypted, //解密后的数据长度 NULL, NULL))) { HandleError(TEXT("获取解密后消息长度失败.")); } //--------------------------------------------------------------- // 分配内存 if(!(pbDecrypted = (BYTE *)malloc(cbDecrypted))) { HandleError(TEXT("Memory allocation failed.")); } //--------------------------------------------------------------- // 解密消息,并验证消息 if(!(CryptDecryptAndVerifyMessageSignature( &DecryptPara, //解密参数结构体 &VerifyPara, //验证参数结构体 dwSignerIndex, //签名消息序号 pbSignedAndEncryptedBlob, //签名、加密、编码后的数据 cbSignedAndEncryptedBlob, //签名、加密、编码后的数据长度 pbDecrypted, //解密后的数据 &cbDecrypted, //解密后的数据长度 NULL, NULL))) { pbDecrypted = NULL; } //--------------------------------------------------------------- // 关闭证书库 CertCloseStore( hCertStore, 0); //--------------------------------------------------------------- // 返回解密后消息 return pbDecrypted; } // End of DecryptandVerify. //------------------------------------------------------------------- // 功能:显示BYTE数据,小于'0'及大于'-'的字符都显示为'-' // 参数:s BYTE数据;len 数据长度 void ShowBytes(BYTE *s, DWORD len) { DWORD TotalChars = 0; DWORD ThisLine = 0; while(TotalChars < len) { if(ThisLine > 70) { ThisLine = 0; _tprintf(TEXT("/n")); } if( s[TotalChars] < '0' || s[TotalChars] > 'z') { _tprintf(TEXT("-")); } else { _tprintf(TEXT("%c"), s[TotalChars]); } TotalChars++; ThisLine++; } _tprintf(TEXT("/n")); } // End of ShowBytes. // HandleError:错误处理函数,打印错误信息,并退出程序 void HandleError(char *s) { printf("程序执行发生错误!/n"); printf("%s/n",s); printf("错误代码为: %x./n",GetLastError()); printf("程序终止执行!/n"); exit(1); }
本文作者专著《Visual C++2010开发权威指南》即将推出,敬请关注,Visual C++2010最近技术,Windows7开发最新技术!