예제 C 프로그램: 해시된 메시지 인코딩 및 디코딩
다음 예제에서는 문자 메시지를 해시 하고 인코딩한 다음 메시지를 디코딩하고 확인합니다.
간단히 하기 위해 이 예제에서는 두 가지 함수가 결합되었지만 보다 현실적인 설정에서는 두 부분을 별도로 사용합니다.
이 예제에서는 다음 작업 및 CryptoAPI 함수를 보여 줍니다.
- CryptAcquireContext를 호출하여 CSP 공급자를 획득합니다.
- CryptMsgCalculateEncodedLength를 사용하여 인코딩된 메시지의 길이를 계산합니다.
- 인코딩된 데이터를 저장할 버퍼에 대한 메모리 할당
- CryptMsgOpenToEncode를 사용하여 인코딩할 메시지를 엽니다.
- CryptMsgUpdate를 사용하여 인코딩할 메시지에 콘텐츠 추가
- CryptMsgGetParam을 사용하여 인코딩된 메시지를 할당된 버퍼에 복사합니다.
- CryptMsgOpenToDecode를 사용하여 디코딩할 메시지를 엽니다.
- CryptMsgUpdate를 사용하여 디코딩할 인코딩된 메시지를 메시지에 추가합니다.
- CryptMsgDuplicate를 사용하여 메시지에 대한 중복 포인터를 만듭니다.
- CryptMsgGetParam을 사용하여 메시지 유형을 확인합니다.
- CryptMsgGetParam을 사용하여 메시지를 디코딩합니다.
- CryptMsgControl을 사용하여 해시를 확인합니다.
- CryptMsgClose를 사용하여 메시지 핸들을 해제합니다.
- CryptReleaseContext를 사용하여 CSP를 해제합니다.
이 예제에서는 MyHandleError 함수를 사용합니다. 이 함수에 대한 코드는 샘플에 포함되어 있습니다.
이 함수 및 기타 보조 함수에 대한 코드도 범용 함수 아래에 나열됩니다.
#pragma comment(lib, "crypt32.lib")
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void MyHandleError(char *s);
void main(void)
{
//-------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Declare and initialize variables. This includes creating a
// pointer to the message content. In real situations,
// the message content will usually exist somewhere and a pointer
// to it will get passed to the application.
BYTE* pbContent = (BYTE*) "A razzle-dazzle hashed message \n"
"Hashing is better than trashing. \n"; // The message
DWORD cbContent = strlen((char *)pbContent)+1; // Size of message
// including the
// final NULL.
HCRYPTPROV hCryptProv; // CSP handle
DWORD HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
CMSG_HASHED_ENCODE_INFO HashedEncodeInfo;
DWORD cbEncodedBlob;
BYTE *pbEncodedBlob;
HCRYPTMSG hMsg;
HCRYPTMSG hDupMsg;
//-------------------------------------------------------------------
// Variables to be used in decoding.
DWORD cbData = sizeof(DWORD);
DWORD dwMsgType;
DWORD cbDecoded;
BYTE *pbDecoded;
//-------------------------------------------------------------------
// Begin processing.
printf("Begin processing. \n");
printf("The message to be hashed and encoded is: \n");
printf("%s\n",pbContent); // Display original message.
printf("The starting message length is %d\n",cbContent);
//-------------------------------------------------------------------
// Acquire a cryptographic provider context handle.
if(CryptAcquireContext(
&hCryptProv, // Address for the handle.
NULL, // Use the current user's logon name.
NULL, // Use the default provider.
PROV_RSA_FULL, // Provider type.
0)) // Zero allows access to
// private keys.
{
printf("A CSP context has been acquired. \n");
}
else
{
MyHandleError("CryptAcquireContext failed.");
}
//-------------------------------------------------------------------
// The function succeeded; hCryptProv is the CSP handle.
//-------------------------------------------------------------------
// Initialize the algorithm identifier structure.
HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize); // Initialize to zero.
HashAlgorithm.pszObjId = szOID_RSA_MD5; // Then set the
// necessary member.
//-------------------------------------------------------------------
// Initialize the CMSG_HASHED_ENCODE_INFO structure.
memset(&HashedEncodeInfo, 0, sizeof(CMSG_HASHED_ENCODE_INFO));
HashedEncodeInfo.cbSize = sizeof(CMSG_HASHED_ENCODE_INFO);
HashedEncodeInfo.hCryptProv = hCryptProv;
HashedEncodeInfo.HashAlgorithm = HashAlgorithm;
HashedEncodeInfo.pvHashAuxInfo = NULL;
//-------------------------------------------------------------------
// Get the size of the encoded message BLOB.
if(cbEncodedBlob = CryptMsgCalculateEncodedLength(
MY_ENCODING_TYPE, // Message encoding type
0, // Flags
CMSG_HASHED, // Message type
&HashedEncodeInfo, // Pointer to structure
NULL, // Inner content object ID
cbContent)) // Size of content
{
printf("The length to be allocated is %d bytes.\n",
cbEncodedBlob);
}
else
{
MyHandleError("Getting cbEncodedBlob length failed");
}
//-------------------------------------------------------------------
// Allocate memory for the encoded BLOB.
if(pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob))
{
printf("%d bytes of memory have been allocated.\n",
cbEncodedBlob);
}
else
{
MyHandleError("Malloc operation failed.");
}
//-------------------------------------------------------------------
// Open a message to encode.
if(hMsg = CryptMsgOpenToEncode(
MY_ENCODING_TYPE, // Encoding type
0, // Flags
CMSG_HASHED, // Message type
&HashedEncodeInfo, // Pointer to structure
NULL, // Inner content object ID
NULL)) // Stream information (not used)
{
printf("The message to encode has been opened. \n");
}
else
{
MyHandleError("OpenToEncode failed");
}
//-------------------------------------------------------------------
// Update the message with the data.
if(CryptMsgUpdate(
hMsg, // Handle to the message
pbContent, // Pointer to the content
cbContent, // Size of the content
TRUE)) // Last call
{
printf("Data has been added to the message to encode. \n");
}
else
{
MyHandleError("MsgUpdate failed");
}
//-------------------------------------------------------------------
// Create a duplicate of the message.
if(hDupMsg = CryptMsgDuplicate(hMsg))
{
printf("The message has been duplicated.\n");
}
else
{
MyHandleError("Duplication of the message failed.");
}
//-------------------------------------------------------------------
// Get the resulting message from the duplicate of the message.
if(CryptMsgGetParam(
hDupMsg, // Handle to the message
CMSG_CONTENT_PARAM, // Parameter type
0, // Index
pbEncodedBlob, // Pointer to the BLOB
&cbEncodedBlob)) // Size of the BLOB
{
printf("Message encoded successfully. \n");
}
else
{
MyHandleError("MsgGetParam failed");
}
//-------------------------------------------------------------------
// Close both messages to prepare for decoding.
CryptMsgClose(hMsg);
CryptMsgClose(hDupMsg);
// The following code decodes the hashed message.
// Usually, this would be in a separate program and the encoded,
// hashed data would be input from a file, from an email message,
// or from some other source.
//
// The variables used in this code have already been
// declared and initialized.
//-------------------------------------------------------------------
// Open the message for decoding.
if(hMsg = CryptMsgOpenToDecode(
MY_ENCODING_TYPE, // Encoding type
0, // Flags
0, // Message type
// (get from message)
hCryptProv, // Cryptographic provider
NULL, // Recipient information
NULL)) // Stream information
{
printf("The message has been opened for decoding. \n");
}
else
{
MyHandleError("OpenToDecode failed");
}
//-------------------------------------------------------------------
// Update the message with the encoded BLOB.
if(CryptMsgUpdate(
hMsg, // Handle to the message
pbEncodedBlob, // Pointer to the encoded BLOB
cbEncodedBlob, // Size of the encoded BLOB
TRUE)) // Last call
{
printf("The encoded data is added to the message "
"to decode. \n");
}
else
{
MyHandleError("Decode MsgUpdate failed");
}
//-------------------------------------------------------------------
// Get the message type.
if(CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_TYPE_PARAM, // Parameter type
0, // Index
&dwMsgType, // Address for returned information
&cbData)) // Size of the returned information
{
printf("The message type has been obtained. \n");
}
else
{
MyHandleError("Decode CMSG_TYPE_PARAM failed");
}
//-------------------------------------------------------------------
// Some applications may need to use a switch statement here
// and process the message differently, depending on the
// message type.
if(dwMsgType == CMSG_HASHED)
{
printf("The message is a hashed message. Proceed. \n");
}
else
{
MyHandleError("Wrong message type");
}
//-------------------------------------------------------------------
// Get the size of the content.
if(CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_CONTENT_PARAM, // Parameter type
0, // Index
NULL, // Address for returned
// information
&cbDecoded)) // Size of the returned
// information
{
printf("The length %d of the message obtained. \n", cbDecoded);
}
else
{
MyHandleError("Decode CMSG_CONTENT_PARAM failed");
}
//-------------------------------------------------------------------
// Allocate memory.
if(pbDecoded = (BYTE *) malloc(cbDecoded))
{
printf("Memory for the decoded message has been allocated.\n");
}
else
{
MyHandleError("Decoding memory allocation failed");
}
//-------------------------------------------------------------------
// Copy the decoded message into the buffer just allocated.
if(CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_CONTENT_PARAM, // Parameter type
0, // Index
pbDecoded, // Address for returned
// information
&cbDecoded)) // Size of the returned
// information
{
printf("Message decoded successfully \n");
printf("The decoded message is \n%s\n", (LPSTR)pbDecoded);
}
else
{
MyHandleError("Decoding CMSG_CONTENT_PARAM #2 failed");
}
//-------------------------------------------------------------------
// Verify the hash.
if(CryptMsgControl(
hMsg, // Handle to the message
0, // Flags
CMSG_CTRL_VERIFY_HASH, // Control type
NULL)) // Pointer not used
{
printf("Verification of hash succeeded. \n");
printf("The data has not been tampered with.\n");
}
else
{
printf("Verification of hash failed. Something changed "
"this message .\n");
}
printf("Test program completed without error. \n");
//-------------------------------------------------------------------
// Clean up
if(pbEncodedBlob)
free(pbEncodedBlob);
if(pbDecoded)
free(pbDecoded);
CryptMsgClose(hMsg);
// Release the CSP.
if(hCryptProv)
CryptReleaseContext(hCryptProv,0);
} // End of main
//-------------------------------------------------------------------
// This example uses the function MyHandleError, a simple error
// handling function, to print an error message to the standard
// error (stderr) file and exit the program.
// For most applications, replace this function with one
// that does more extensive error reporting.
void MyHandleError(char *s)
{
fprintf(stderr,"An error occurred in running the program. \n");
fprintf(stderr,"%s\n",s);
fprintf(stderr, "Error number %x.\n", GetLastError());
fprintf(stderr, "Program terminating. \n");
exit(1);
} // End of MyHandleError