Crypto API 学习笔记

 

Crypto API 学习笔记一
微软公司在NT4.0以上版本中提供了一套完整的Crypto API的函数,支持密钥交换,数据加密解密,数字签名,给程序员带来了很大方便,用户在对软件进行保护的时候可以直接利用Crypto API来完成这些工作,比如计算注册码,检查程序的完整性等。
  
我们在用这些的API进行加密解密的时候,只需要知道如何去应用它们,而不必知道它们的底层实现。如果想知道它们更为详尽的资料,可以查找相关的资料。
  
Crypto API只是业余型的感兴趣,想通过写学习笔记,一是让自己记的更牢固些,二是想把自己的学的跟大家探讨一下。写的不好,大家多多原谅。我主要通过MSDN来学习,例子也是完全取自MSDN
  
首先,是Crypto API运行的环境。
首先需要Crypt32.lib,将它加到project>setting->link下面,当然你也可以在程序中用#pragma comment (lib, "crypt32.lib")加入。
  
在程序开头,你要加入两个头文件 windows.h Wincrypt.h,和一个#define MY_ENCODING_TYPE   (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
  
在正式应用API进行一系列的加密解密的时候,需要有一些准备工作,下面是介绍一些在正式开始时所需要了解和做的工作。
生成密钥和密钥容器
  
我们知道,在进行加密解密的时候,我们需要一个密钥进行加密,和一个密钥进行解密,加密密钥和解密密钥可能相同,也可能不同。于是在我们进行加密解密的开始时,我们首先需要有密钥。下面这个程序,完成了三个任务,并且介绍了一些函数的用法。
任务一:获取一个指定的密钥容器,如果这个容器不存在,创建一个。
任务二:如果容器中不存在一个签名密钥对,创建一个
任务三:如果容器中不存在一个交换密钥对,创建一个
   //-------------------------------------------------------------------
下面这段程序使用到了这几个函数
CryptAcquireContext
CryptDestroyKey
CryptGenKey
CryptGetUserKey

// Copyright (c) Microsoft Corporation.   All rights reserved.

#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <Wincrypt.h>

//-------------------------------------------------------------------

void MyHandleError(LPTSTR psz)
{
     _ftprintf(stderr, TEXT("An error occurred in the program. /n"));
     _ftprintf(stderr, TEXT("%s/n"), psz);
     _ftprintf(stderr, TEXT("Error number %x./n"), GetLastError());
     _ftprintf(stderr, TEXT("Program terminating. /n"));
     exit(1);
} // End of MyHandleError.
上面这个函数是一个异常处理函数,当出现错误的时候,出现提示,并推出程序。以后的程序中都有这个函数,以后就会将这个函数的实现省去。现在这个函数的实现在后面。
void main(void)
{
         HCRYPTPROV hCryptProv;    //
定义一个CSP模块的句柄。“CSP模块,请查看《加密解密二》222页,那里有简单的说明,这里就不说了。    
    
         LPCTSTR pszContainerName = TEXT("My Sample Key Container");//
用一个TEXT宏定义一个容器的名字,

    
     if(CryptAcquireContext(         //
这个函数是获取有某个容器的CSP模块的指针,成功返回TRUE
         &hCryptProv,             //
指向一个CSP模块句柄指针,里面用指定的容器
         pszContainerName,        //
指定容器的名称
      NULL,                 //
这个参数这里用的是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块
         PROV_RSA_FULL,       //
确定密钥的类型
         0))                     //
常设为0,还有些其他的类型,请看MSDN
     {
         _tprintf(
             TEXT("A crypto context with the %s key container ")
             TEXT("has been acquired./n"),
             pszContainerName);
     }
     else
     {
         //
不成功的处理段
         if(GetLastError() == NTE_BAD_KEYSET)      // NTE_BAD_KEYSET
意味着密钥
//
容器不存在,下面就去创建一个
//
新的密钥容器
         {
             if(CryptAcquireContext(
                 &hCryptProv,
                 pszContainerName,
                 NULL,
                 PROV_RSA_FULL,
                 CRYPT_NEWKEYSET))            // CRYPT_NEWKEYSET
意味着当指定容器不存在的时候,去创建一个容器。
             {
                 _tprintf(TEXT("A new key container has been ")
                     TEXT("created./n"));
             }
             else
             {
                 MyHandleError(TEXT("Could not create a new key ")
                     TEXT("container./n"));
             }
         }
         else
         {
             MyHandleError(TEXT("CryptAcquireContext failed./n"));
         }
     }

    
     HCRYPTKEY hKey;                             //
创建一个密钥句柄
    
     if(CryptGetUserKey(                            // CryptGetUserKey
是获取一个密钥//句柄的函数,成功返回TRUE
         hCryptProv,                                //
指定容器的CSP模块句柄
         AT_SIGNATURE,                          //
指定私钥的类型
         &hKey))                                 //
原来接收获取的密钥句柄
     {
         _tprintf(TEXT("A signature key is available./n"));
     }
     else
     {
         _tprintf(TEXT("No signature key is available./n"));
         if(GetLastError() == NTE_NO_KEY)               // NTE_NO_KEY
意味着密钥不存在,下面就生成一个密钥
         {
          
             _tprintf(TEXT("The signature key does not exist./n"));
             _tprintf(TEXT("Create a signature key pair./n"));
             if(CryptGenKey(                           // CryptGenKey
生成一个密钥
                 hCryptProv,                           //
指定CSP模块的句柄
                 AT_SIGNATURE,                     //
对于公钥密码系统,生成一个私钥和一个公钥,这个参数指定了这个密钥是公钥,于是生成了一个密码对。如果不是公钥系统,则指定了密码算法,具体看MSDN
                 0,                                  //
指定了生成密钥的类型,这个参数的说明挺多的,想获取更为详尽的资料请看MSDN
                 &hKey))
             {
                 _tprintf(TEXT("Created a signature key pair./n"));
             }
             else
             {
                 MyHandleError(TEXT("Error occurred creating a ")
                     TEXT("signature key./n"));
             }
         }
         else
         {
             MyHandleError(TEXT("An error other than NTE_NO_KEY ")
                 TEXT("getting a signature key./n"));
         }
     } // End if.

     _tprintf(TEXT("A signature key pair existed, or one was ")
         TEXT("created./n/n"));

         if(hKey)                               //
将密钥句柄销毁
     {
         if(!(CryptDestroyKey(hKey)))
         {
             MyHandleError(TEXT("Error during CryptDestroyKey."));
         }

         hKey = NULL;
     }

    
下面这部分和上面是类似的,只不过密钥类型不相同而已。
     if(CryptGetUserKey(
         hCryptProv,
         AT_KEYEXCHANGE,
         &hKey))
     {
         _tprintf(TEXT("An exchange key exists./n"));
     }
     else
     {
         _tprintf(TEXT("No exchange key is available./n"));

         // Check to determine whether an exchange key
         // needs to be created.
         if(GetLastError() == NTE_NO_KEY)
         {
             // Create a key exchange key pair.
             _tprintf(TEXT("The exchange key does not exist./n"));
             _tprintf(TEXT("Attempting to create an exchange key ")
                 TEXT("pair./n"));
             if(CryptGenKey(
                 hCryptProv,
                 AT_KEYEXCHANGE,
                 0,
                 &hKey))
             {
                 _tprintf(TEXT("Exchange key pair created./n"));
             }
             else
             {
                 MyHandleError(TEXT("Error occurred attempting to ")
                     TEXT("create an exchange key./n"));
             }
         }
         else
         {
             MyHandleError(TEXT("An error other than NTE_NO_KEY ")
                 TEXT("occurred./n"));
         }
     }

     // Destroy the exchange key.
     if(hKey)
     {
         if(!(CryptDestroyKey(hKey)))
         {
             MyHandleError(TEXT("Error during CryptDestroyKey."));
         }

         hKey = NULL;
     }

     // Release the CSP.
     if(hCryptProv)
     {
         if(!(CryptReleaseContext(hCryptProv, 0)))
         {
             MyHandleError(TEXT("Error during CryptReleaseContext."));
         }
     }
    
     _tprintf(TEXT("Everything is okay. A signature key "));
     _tprintf(TEXT("pair and an exchange key exist in "));
     _tprintf(TEXT("the %s key container./n"), pszContainerName);  
} // End main.
  
下面我们再通过一个程序,用几种不同的方法,将CryptAcquireContext和其他的API函数联系起来,看看它们是如何与一个CSP和容器工作的。这个程序演示了以下内容和几个函数。
一.   CryptAcquireContext获取一个缺省容器的缺省CSP的句柄。如果缺省容器不存在,用CryptAcquireContext创建一个。
二.   CryptGetProvParam获取CSP和容器的信息。
三.   CryptContextAddRef增加CSP的引用计数器的数值。
四.   CryptAcquireContext创建一个指定的容器
五.   CryptAcquireContext删除一个容器
六.   用一个新创建的容器获取一个CSP的句柄。
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <Wincrypt.h>
异常处理函数省略
void main(void)
{
    
     HCRYPTPROV hCryptProv;                             //
定义CSP句柄

     if(CryptAcquireContext(
         &hCryptProv,
         NULL,                                            //
缺省容器
         NULL,                                            //
缺省CSP
         PROV_RSA_FULL,
         0))
     {
         _tprintf(TEXT("CryptAcquireContext succeeded./n"));
     }
     else
     {
         if (GetLastError() == NTE_BAD_KEYSET)                //
同样,如果当不存在这样的容器的时候,创建一个
         {
             if(CryptAcquireContext(
                 &hCryptProv,
                 NULL,
                 NULL,
                 PROV_RSA_FULL,
                 CRYPT_NEWKEYSET))                    
             {
                 _tprintf(TEXT("CryptAcquireContext succeeded./n"));
             }
             else
             {
                 MyHandleError(TEXT("Could not create the default ")
                     TEXT("key container./n"));
             }
         }
         else
         {
             MyHandleError(TEXT("A general error running ")
                 TEXT("CryptAcquireContext."));
         }
     }

     CHAR pszName[1000];
     DWORD cbName;

     cbName = 1000;
     if(CryptGetProvParam(
         hCryptProv,                                      //CSP
模块句柄
         PP_NAME,                                      //
指定获取哪些信息,这里是指定获取CSP名字的信息
         (BYTE*)pszName,                                //
缓冲区接受信息返回值
         &cbName,
         0))
     {
         _tprintf(TEXT("CryptGetProvParam succeeded./n"));
         printf("Provider name: %s/n", pszName);
     }
     else
     {
         MyHandleError(TEXT("Error reading CSP name./n"));
     }

     //---------------------------------------------------------------
     // Read the name of the key container.
     cbName = 1000;
     if(CryptGetProvParam(
         hCryptProv,
         PP_CONTAINER,                                        //
获取容器名字
         (BYTE*)pszName,
         &cbName,
         0))
     {
         _tprintf(TEXT("CryptGetProvParam succeeded./n"));
         printf("Key Container name: %s/n", pszName);
     }
     else
     {
         MyHandleError(TEXT("Error reading key container name./n"));
     }
    

     if(CryptContextAddRef(                        // CryptContextAddRef
是向一个CSP的引用计数器增加一个值的函数
         hCryptProv,
         NULL,                                 //
保留值,必须为NULL
         0))                      //
保留值,必须为0
     {
         _tprintf(TEXT("CryptcontextAddRef succeeded./n"));
     }
     else
     {
         MyHandleError(TEXT("Error during CryptContextAddRef!/n"));
     }

     //---------------------------------------------------------------
     //   The reference count on hCryptProv is now greater than one.
     //   The first call to CryptReleaseContext will not release the
     //   provider handle.

     //---------------------------------------------------------------
     //   Release the context once.
     if (CryptReleaseContext(hCryptProv, 0))                 // CryptReleaseContext
是用来释放CSP句柄的,当这个函数调用一次的时候,CSP里面的引用计数就减少一,当引用计数减少的0的时候。CSP将不能再被这个程序中的任何函数调用了。
     {
         _tprintf(TEXT("The first call to CryptReleaseContext ")
             TEXT("succeeded./n"));
     }
     else
     {
         MyHandleError(TEXT("Error during ")
             TEXT("CryptReleaseContext #1!/n"));
     }

     if (CryptReleaseContext(hCryptProv, 0))                 //
再次释放CSP模块
     {
         _tprintf(TEXT("The second call to CryptReleaseContext ")
             TEXT("succeeded./n"));
     }
     else
     {
         MyHandleError(TEXT("Error during ")
             TEXT("CryptReleaseContext #2!/n"));
     }

    
下面是从PROV_RSA_FULLCSP模块中创建一个自己的容器
     LPCTSTR pszContainerName = TEXT("My Sample Key Container");

     hCryptProv = NULL;
     if(CryptAcquireContext(
         &hCryptProv,
         pszContainerName,
         NULL,
         PROV_RSA_FULL,
         CRYPT_NEWKEYSET))
     {
         _tprintf(TEXT("CryptAcquireContext succeeded. /n"));
         _tprintf(TEXT("New key set created. /n"));

         //-----------------------------------------------------------
         // Release the provider handle and the key container.
         if(hCryptProv)
         {
             if(CryptReleaseContext(hCryptProv, 0))
             {
                 hCryptProv = NULL;
                 _tprintf(TEXT("CryptReleaseContext succeeded. /n"));
             }
             else
             {
                 MyHandleError(TEXT("Error during ")
                     TEXT("CryptReleaseContext!/n"));
             }
         }
     }
     else
     {
         if(GetLastError() == NTE_EXISTS)
         {
             _tprintf(TEXT("The named key container could not be ")
                 TEXT("created because it already exists./n"));
            
         }
         else
         {
             MyHandleError(TEXT("Error during CryptAcquireContext ")
                 TEXT("for a new key container."));
         }
     }

  
     if(CryptAcquireContext(
         &hCryptProv,
         pszContainerName,
         NULL,
         PROV_RSA_FULL,
         0))
     {
         _tprintf(TEXT("Acquired the key set just created. /n"));
     }
     else
     {
         MyHandleError(TEXT("Error during CryptAcquireContext!/n"));
     }

     //---------------------------------------------------------------
     // Perform cryptographic operations.

     //---------------------------------------------------------------
        if(CryptReleaseContext(
         hCryptProv,
         0))
     {
         _tprintf(TEXT("CryptReleaseContext succeeded. /n"));
     }
     else
     {
         MyHandleError(TEXT("Error during CryptReleaseContext!/n"));
     }

  
     if(CryptAcquireContext(
         &hCryptProv,
         pszContainerName,
         NULL,
         PROV_RSA_FULL,
         CRYPT_DeleteKEYSET))                     //CRYPT_DeleteKEYSET
意味着CryptAcquireContex删除一个指定的容器
     {
         _tprintf(TEXT("Deleted the key container just created. /n"));
     }
     else
     {
         MyHandleError(TEXT("Error during CryptAcquireContext!/n"));
     }
}
Cryptography API 学习笔记二
前面学习了密钥容器的建立的一些知识,现在我们接下来自然是学习如何获取一个密钥,首先是获取一个session key,即对话密钥,是对称密钥。
  
这些学习笔记主要是从MSDN中的例子中,学习基本的Cryptography API的用法,了解一些用法的过程。欢迎大家多提宝贵意见。
  
下面依旧是从一个小程序开始。这个程序的学习任务有以下几个:
  
任务一:调用CryptAcquireContext,获取一个缺省CSP和缺省密钥容器的句柄
  
任务二:用CryptCreateHash去创建一个空的哈希对象
  
任务三:用CryptHashData.哈希密码
任务四:调用CryptDeriveKey获取一个对话密钥
任务五:销毁密码和哈希后的数据
任务六:释放CSP
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include <Wincrypt.h>

#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void MyHandleError(char *s);
void GetConsoleInput(char*, int);

void main()
{

HCRYPTPROV hCryptProv;                        
定义CSP句柄
HCRYPTKEY hKey;                              
定义密钥句柄
HCRYPTHASH hHash;                            
定义一个HASH对象的句柄
CHAR szPassword[512] = "";                      
定义512大小的字符数组,用来保存密码
DWORD dwLength;                              
保存密码长度
fprintf(stderr,"Enter a password to be used to create a key:");

GetConsoleInput(szPassword, 512);                  
获取密码,这个是自己写的函数,目的是在屏幕上显示的是*
printf("The password has been stored./n");
dwLength = strlen(szPassword);


if(CryptAcquireContext(                  
以下是获取一个缺省的PROV_RSA_FULL  CSP 句柄
   &hCryptProv,
   NULL,
   NULL,
   PROV_RSA_FULL,
   0))
{
    printf("A context has been acquired. /n");
}
else
{
     MyHandleError("Error during CryptAcquireContext!");
}
//--------------------------------------------------------------------
if(CryptCreateHash(                                  
调用CryptCreateHash创建一个HASH对象
   hCryptProv,                                    
一个CSP句柄
   CALG_MD5,                                    
确定哈希算法
   0,  
对于非密钥算法,这个参数一定是0,如果是密钥算法,那么这个参数就是密钥
   0,                          
保留参数,为0
   &hHash))                                        
一个哈希对象的指针
{
    printf("An empty hash object has been created. /n");
}
else
{
    MyHandleError("Error during CryptCreateHash!");
}
//--------------------------------------------------------------------
if(CryptHashData(                                  
调用CryptHashData哈希密码
   hHash,                                        
哈希对象
   (BYTE *)szPassword,                
指向缓冲区的地址
   dwLength,                                      
密码长度
   0))
{
     printf("The password has been hashed. /n");
}
else
{
     MyHandleError("Error during CryptHashData!");
}
//--------------------------------------------------------------------
if(CryptDeriveKey(                            
调用CryptDeriveKey获取对话密码
   hCryptProv,                                CSP
句柄
   CALG_RC2,                              
一个ALG_ID结构,用来指定对称密钥生成的算法
   hHash,                                      
哈希对象
   CRYPT_EXPORTABLE,            
指定生成密钥的类型,CRYPT_EXPORTABLE意味着这个程序生成的密钥可以被其它程序调用,而不是仅仅限于这个程序当中。但是它不能用于非对称密码中。
   &hKey))
{
    printf("The key has been derived. /n");
}
else
{
    MyHandleError("Error during CryptDeriveKey!");
}
if(hHash)                                          
销毁哈希对象
{
   if(!(CryptDestroyHash(hHash)))
       MyHandleError("Error during CryptDestroyHash");
}

if(hKey)                                            
销毁密钥句柄
{
    if(!(CryptDestroyKey(hKey)))
        MyHandleError("Error during CryptDestroyKey");
}

if(hCryptProv)                                      
销毁CSP句柄
{
   if(!(CryptReleaseContext(hCryptProv, 0)))
       MyHandleError("Error during CryptReleaseContext");
}
printf("The program to derive a key completed without error. /n");
} // end main
void MyHandleError
函数的实现省略,在上一篇中有
void GetConsoleInput(char* strInput,
           int   intMaxChars)
{
  char ch;
  char minChar = ' ';
  minChar++;

  ch = getch();
  while (ch != '/r')
  {
    if (ch == '/b' && strlen(strInput) > 0)
    {
      strInput[strlen(strInput)-1]   = '/0';
      printf("/b /b");
    }
    else if (ch >= minChar && strlen(strInput) < intMaxChars)
    {
      strInput[strlen(strInput)+1] = '/0';
      strInput[strlen(strInput)]   = ch;
      putch('*');
    }
    ch = getch();
  }
  putch('/n');
}

下面讲讲如何复制一个对话密钥,照例是从一个程序讲起,完成以下任务。获取一个CSP句柄,创建一个对话密钥,复制密钥。改变密钥生成过程,随机填充一个缓冲区,销毁密钥句柄,释放CSP句柄。
#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()
{
//-------------------------------------------------------------------
// Declare and initialize variables.

HCRYPTPROV   hCryptProv;                         CSP
句柄
HCRYPTKEY    hOriginalKey;              
源密钥句柄
HCRYPTKEY    hDuplicateKey;              
复制后的密钥句柄
DWORD        dwMode;                            
BYTE          pbData[16];

printf("This program creates a session key and duplicates /n");
printf("that key. Next, parameters are added to the original /n");
printf("key. Finally, both keys are destroyed. /n/n");

if(CryptAcquireContext(                            
获取CSP句柄,前面叙述过了,这里就不叙述了
   &hCryptProv,
   NULL,
   NULL,
   PROV_RSA_FULL,
   0))
{    
    printf("CryptAcquireContext succeeded. /n");
}
else
{
    MyHandleError("Error during CryptAcquireContext!/n");
}
//-------------------------------------------------------------------
if (CryptGenKey(                                      
生成一个CALG_RC4算法生成的密钥,保存在hOriginalKey
     hCryptProv,
     CALG_RC4,                                    ALG_ID
结构,指定生成这个密钥使用的算法
     0,
     &hOriginalKey))
{
   printf("Original session key is created. /n");
}
else
{
   MyHandleError("ERROR - CryptGenKey.");
}

if (CryptDuplicateKey(                                
复制密钥
     hOriginalKey,                                  
源密钥
     NULL,                                        
保留参数,必须为NULL
     0,                                            
保留参数,必须为0
     &hDuplicateKey))                              
副本密钥
{
   printf("The session key has been duplicated. /n");
}
else
{
   MyHandleError("ERROR - CryptDuplicateKey");
}
给源密钥设置附加参数
dwMode = CRYPT_MODE_ECB;                        CRYPT_MODE_ECB
是一个没有反馈的块加密模式  
if(CryptSetKeyParam(
   hOriginalKey,
   KP_MODE,                  
指定密钥的某种属性被改变,
KP_MODE
意味着改变的是加密模式
(BYTE*)&dwMode,                  
指向一个已经被初始化的缓冲区
   0))                                          
{
     printf("Key Parameters set. /n");
}
else
{
     MyHandleError("Error during CryptSetKeyParam.");
}
if(CryptGenRandom(                            
随机填充一块缓冲区
   hCryptProv,                                  CSP
句柄
   8,                        
缓冲区大小
   pbData))                      
缓冲区地址
{
     printf("Random sequence generated. /n");
}
else
{
     MyHandleError("Error during CryptGenRandom.");
}
if(CryptSetKeyParam(                            
再次给密钥设置属性
   hOriginalKey,
     KP_IV,               KP_IV
意味着,这个函数的第三个参数指向一个BYTE数组,数组大小为块大小/8
   pbData,
   0))
{
     printf("Parameter set with random sequence as "
     "initialization vector. /n");
}
else
{
     MyHandleError("Error during CryptSetKeyParam.");
}
//-------------------------------------------------------------------

if (hOriginalKey)                                  
以下依次销毁,释放源密钥句柄,副本句柄,CSP句柄,
    if (!CryptDestroyKey(hOriginalKey))
        MyHandleError("Failed CryptDestroyKey/n");

if (hDuplicateKey)
    if (!CryptDestroyKey(hDuplicateKey))
            MyHandleError("Failed CryptDestroyKey/n");

if(hCryptProv)
    if (!CryptReleaseContext(hCryptProv, 0))
        MyHandleError("Failed CryptReleaseContext/n");

printf("/nThe 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(void)
{
//--------------------------------------------------------------------
// Declare and initialize variables.

HCRYPTPROV hProv;       // CSP handle
HCRYPTKEY hSignKey;     // Signature key pair handle
HCRYPTKEY hXchgKey;     // Exchange key pair handle
HCRYPTKEY hKey;         // Session key handle
BYTE *pbKeyBlob;        // Pointer to a simple key BLOB
DWORD dwBlobLen;        // The length of the key BLOB

//--------------------------------------------------------------------
// Acquire a cryptographic provider context handle.

if(CryptAcquireContext(                            
获取一个缺省容器的CSP句柄
   &hProv,
   NULL,
   NULL,
   PROV_RSA_FULL,
   0))
{
    printf("The CSP has been acquired. /n");
}
else
{
    MyHandleError("Error during CryptAcquireContext.");
}

if(CryptGetUserKey(                                    
获取一个AT_SIGNATURE类型的密钥句柄
   hProv,
   AT_SIGNATURE,
   &hSignKey))
{
    printf("The signature key has been acquired. /n");
}
else
{
    MyHandleError("Error during CryptGetUserKey for signkey.");
}
//--------------------------------------------------------------------

if(CryptGetUserKey(                                      
获取一个AT_KEYEXCHANGE,类型的密钥句柄,保存在hXchgKey
   hProv,
   AT_KEYEXCHANGE,
   &hXchgKey))
{
    printf("The key exchange key has been acquired. /n");
}
else
{
    printf("Error during CryptGetUserKey exchange key.");
}
// Generate a session key.

if (CryptGenKey(                                  
生成一个CRYPT_EXPORTABLE(可导出的),CALG_RC4(指定算法)的密钥,保存在hKey
    hProv,      
    CALG_RC4,      
    CRYPT_EXPORTABLE,
    &hKey))
{  
    printf("Original session key is created. /n");
}
else
{
   MyHandleError("ERROR -- CryptGenKey.");
}
if(CryptExportKey(                                   CryptExportKey
导出一个密钥
   hKey,                                          
将要导出的密钥的句柄
   hXchgKey,                  
用户最终使用到的密钥的句柄
   SIMPLEBLOB,                                
指定BLOB的类型,SIMPLEBLOB说明是用来导出对话密钥的
   0,                                            
指定密钥的附加属性
   NULL,                                        
   &dwBlobLen))                                  
当时这个函数在这里的主要
                        
目的是得到这个BLOB的长度
{
     printf("Size of the BLOB for the session key determined. /n");
}
else
{
     MyHandleError("Error computing BLOB length.");
}

if(pbKeyBlob = (BYTE*)malloc(dwBlobLen))
{
    printf("Memory has been allocated for the BLOB. /n");
}
else
{
    MyHandleError("Out of memory. /n");
}
if(CryptExportKey(                            
这是这个函数才是真正的导出密钥
   hKey,
   hXchgKey,
   SIMPLEBLOB,
   0,
   pbKeyBlob,
   &dwBlobLen))
{
     printf("Contents have been written to the BLOB. /n");
}
else
{
    MyHandleError("Error during CryptExportKey.");
}
free(pbKeyBlob);                                  
释放内存

// Destroy the session key.
if(hKey)
    CryptDestroyKey(hKey);

// Destroy the signature key handle.
if(hSignKey)
    CryptDestroyKey(hSignKey);

// Destroy the key exchange key handle.
if(hXchgKey)
     CryptDestroyKey(hXchgKey);

// Release the provider handle.
if(hProv)
   CryptReleaseContext(hProv, 0);
printf("The program ran to completion without error. /n");

}
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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值