Crypto API 学习笔记三
Encoding and Decoding Data
下面逐渐进入主题了,现在来讲讲是如何对数据进行Encoding and Decoding的。依旧是从一段程序中开始。
#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)
{
HCRYPTMSG hMsg;                              指向一个消息句柄
BYTE* pbContent;                   一个BYTE指针指向消息
DWORD cbContent;                   消息长度
DWORD cbEncodedBlob;                          ECODE的BLOB的大小
BYTE *pbEncodedBlob;                           一个BYTE指针指向ENCODE BLOB

DWORD cbData = sizeof(DWORD);                 数据大小
DWORD cbDecoded;                              Decode内容大小
BYTE *pbDecoded;                               指向Decode的指针

pbContent = (BYTE*) "Security is our only business";
cbContent = strlen((char *) pbContent)+1;

printf("The original message => %s\n",pbContent);  

if(cbEncodedBlob = CryptMsgCalculateEncodedLength(
             MY_ENCODING_TYPE,      指定Encode类型,在程序的开头已经预定义了,MY_ENCODING_TYPE 就是 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING
             0,                      // Flags
             CMSG_DATA,                定义了数据的类型,这里指定为BYTE型的字符串
             NULL,                   
             NULL,                   
             cbContent))               内容的大小
这里的的函数的作用是计算指定消息Encode所需要的最大的长度,通过计算,为一个BLOB分配内存空间。
{
    printf("The length of the data has been calculated. \n");
}
else
{
    MyHandleError("Getting cbEncodedBlob length failed");
}
为encode blob分配内存空间

if(pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob))
{
   printf("Memory has been allocated for the signed message. \n");
}
else
{
   MyHandleError("Memory allocation failed");
}

if(hMsg = CryptMsgOpenToEncode(                 CryptMsgOpenToEncode为Encode,开一个消息
          MY_ENCODING_TYPE,            Encode类型,文件开始有说明
          0,                       // Flags
          CMSG_DATA,                        指定Message的类型,CMSG_DATA说明类型没用到
          NULL,                                    现在没有到,为NULL
          NULL,                                    同上
          NULL))                                   不是流加密,这个参数为NULL
{
    printf("The message to be encoded has been opened. \n");
}
else
{
     MyHandleError("OpenToEncode failed");
}
if(CryptMsgUpdate(                              CryptMsgUpdate将数据加到消息中,可以通过循环,将数据一段段的加得到消息中
        hMsg,                                  一个小心句柄
        pbContent,                              指向数据的指针
        cbContent,                               数据的大小
        TRUE))                                 TRUE表明这个是最后一段数据,在开个消息的时候,如果CMSG_DETACHED_FLAG有使用到,这设为FALSE,否则为TRUE。
{
     printf("Content has been added to the encoded message. \n");
}
else
{
      MyHandleError("MsgUpdate failed");
}

if(CryptMsgGetParam(                             CryptMsgGetParam是获取一个消息中的参数
               hMsg,                          一个消息句柄
               CMSG_BARE_CONTENT_PARAM,  指定要获取的参数的类型
               0,                        
               pbEncodedBlob,                   一个接受数据的内存地址
               &cbEncodedBlob))                 BLOB的大小,即是上面接受的数据的大小
{
    printf("Message encoded successfully. \n");
}
else
{
      MyHandleError("MsgGetParam failed");
}
                                                释放消息句柄
if(hMsg)
    CryptMsgClose(hMsg);

if(hMsg = CryptMsgOpenToDecode(                  开个Decode的小心句柄,参数和上面的Encode一样
               MY_ENCODING_TYPE,      
               0,                                   
 CMSG_DATA,             
               NULL,                  
               NULL,                 
               NULL))                
{
     printf("The message to decode is open. \n");
}
else
{
    MyHandleError("OpenToDecode failed");
}
下面的过程和Encode类似,调用的函数和上面相同,只不过是过程逆向

printf("\nThe length of the encoded message is %d.\n\n",
    cbEncodedBlob);

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 BLOB has been added to the message. \n");
}
else
{
    MyHandleError("Decode MsgUpdate failed");
}
if(CryptMsgGetParam(                            CryptMsgGetParam的调用和上面有所不同,这里一共是调用两次,第一次的作用主要是得到消息的大小,第二次是得到消息所在的内存地址
                  hMsg,                         消息句柄
                  CMSG_CONTENT_PARAM,    // Parameter type
                  0,                     
                  NULL,                  // Address for returned 
                                         // information
                  &cbDecoded))           // Size of the returned
                                         // information
{
    printf("The decoded message size is %d. \n", cbDecoded);
}
else
{
    MyHandleError("Decode CMSG_CONTENT_PARAM failed");
}
if(pbDecoded = (BYTE *) malloc(cbDecoded))
{
     printf("Memory has been allocated for the decoded message.\n");
}
else
{
    MyHandleError("Decoding memory allocation failed.");
}
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("The message is %s.\n",(LPSTR)pbDecoded);
}
else
{
     MyHandleError("Decode CMSG_CONTENT_PARAM #2 failed");
}
if(pbEncodedBlob)
   free(pbEncodedBlob);
if(pbDecoded)
   free(pbDecoded);
if(hMsg)
    CryptMsgClose(hMsg);

printf("This program ran to completion without error. \n");

} //  End of main

下面我们来看看如何哈希一个对话密钥,这个密钥可以用来对一个消息,文件进行加密。我们依旧从一个程序开始。
#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()
{

//--------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Declare variables.

HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
HCRYPTKEY hKey;

//--------------------------------------------------------------------
// Begin processing.

printf("Process beginning. Creating a session key. \n");

if(CryptAcquireContext(                           首先依旧是获取一个缺省的CSP句柄
   &hCryptProv, 
   NULL, 
   NULL, 
   PROV_RSA_FULL, 
   0)) 
{
    printf("CryptAcquireContext complete. \n");
}
else
{
     MyHandleError("Acquisition of context failed.");
}

if(CryptCreateHash(                                 创建一个CALG_MD5算法的HASH对象,这个hash对象用的是MD5算法
   hCryptProv,                                        指定一个CSP句柄
   CALG_MD5,                                      指定算法
   0,               
   0, 
   &hHash)) 
{
    printf("An empty hash object has been created. \n");
}
else
{
    MyHandleError("Error during CryptBeginHash!\n");
}

if(CryptGenKey(                                        创建密钥
   hCryptProv,                                         传入一个CSP句柄
   CALG_RC2,                                        指明密钥身成所用算法
   CRYPT_EXPORTABLE,                              说明密钥是可以导出到CSP,用于这个应用程序外的
   &hKey)) 
{
     printf("A random session key has been created. \n");
}
else
{
    MyHandleError("Error during CryptGenKey!\n");
}
if(CryptHashSessionKey(                                   对生成的密钥进行hash
   hHash, 
   hKey, 
   0))
{
     printf("The session key has been hashed. \n");
}
else
{
    MyHandleError("Error during CryptHashSessionKey!\n");
}
在这里就可以添加代码,用生成的密钥进行加密

if(hHash)
{
   if(!(CryptDestroyHash(hHash)))
       MyHandleError("Error during CryptDestroyHash");
}


if(hKey)
{
   if(!(CryptDestroyKey(hKey)))
       MyHandleError("Error during CryptDestroyKey");
}

// Release the CSP.

if(hCryptProv)
{
   if(!(CryptReleaseContext(hCryptProv,0)))
       MyHandleError("Error during CryptReleaseContext");
}

printf("Create random session key completed without error. \n");
} // end main
附件是DOC文档,希望大家多提宝贵意见