Programa C de ejemplo: codificación y descodificación de un mensaje con hash
En el ejemplo siguiente se codifican y se codifica un mensaje de texto y, a continuación, se descodifica y se comprueba el mensaje.
Aunque, por simplicidad, las dos funciones diferentes se han combinado en este ejemplo, en una configuración más realista, las dos partes se usarían por separado.
En este ejemplo se muestran las siguientes tareas y funciones CryptoAPI:
- Llamar a CryptAcquireContext para adquirir un proveedor de CSP.
- Con CryptMsgCalculateEncodedLength para calcular la longitud del mensaje codificado.
- Asignar memoria para que un búfer contenga los datos codificados.
- Abrir un mensaje para codificar mediante CryptMsgOpenToEncode.
- Agregar contenido al mensaje para codificar mediante CryptMsgUpdate.
- Con CryptMsgGetParam para copiar el mensaje codificado en el búfer asignado.
- Abrir un mensaje para descodificar mediante CryptMsgOpenToDecode.
- Agregar el mensaje codificado al mensaje para descodificar mediante CryptMsgUpdate.
- Crear un puntero duplicado al mensaje mediante CryptMsgDuplicate.
- Comprobación del tipo de mensaje con CryptMsgGetParam.
- Usar CryptMsgGetParam para descodificar el mensaje.
- Comprobación del hash mediante CryptMsgControl.
- Usar CryptMsgClose para liberar el identificador del mensaje.
- Uso de CryptReleaseContext para liberar el CSP.
En este ejemplo se usa la función MyHandleError. El código de esta función se incluye con el ejemplo.
El código de esta y otras funciones auxiliares también aparece en funciones De uso general.
#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