`

Microsoft CryptoAPI加密技术

阅读更多

一、 加密方法:

当初,计算机的研究就是为了破解德国人的密码,人们并没有想到计算机给今天带来的信息革命。随着计算机的发展,运算能力的增强,密码学已经取得了巨大的进展。大体来说有以下几种形式。
1、 公用密钥加密技术
加密和解密使用不同的密钥,分别叫做“公钥”和“私钥”。顾名思义,“私钥”就是不能让别人知道的,而“公钥”就是可以公开的。这两个必须配对使用,用公钥加密的数据必须用与其对应的私钥才能解开。这种技术安全性高,得到广泛运用,但是效率太低。
2、 对称密钥加密技术
要求加密和解密过程使用相同的密钥,这样,密钥必须只能被加解密双方知道,否则就不安全。这种技术安全性不高,但是效率高。
3、 结合公用和对称密钥加密技术
公钥加密技术以速度为代价换取了高安全性,而对称加密以低安全换取高性能,所以另一种常见的加密方法就是结合以上两种技术。
用对称加密算法对数据进行加密,然后使用更安全的但效率更低的公钥加密算法对对称密钥进行加密。
4、 数字签名和鉴别
就是对已经加密的数据“签名”,这样接收者可以知道加密的数据的来源,以及是否被更改。

二、 CryptoAPI

微软的CryptoAPI是PKI推荐使用的加密 API。其功能是为应用程序开发者提供在Win32环境下使用加密、验证等安全服务时的标准加密接口。CryptoAPI处于应用程序和CSP(cryptographic service provider)之间(见图一)。

CryptoAPI的编程模型同Windows系统的图形设备接口 GDI比较类似,其中加密服务提供者CSP等同于图形设备驱动程序 ,加密硬件(可选)等同于图形硬件,其上层的应用程序也类似,都不需要同设备驱动程序和硬件直接打交道。

CryptoAPI共有五部分组成:简单消息函数(Simplified Message Functions)、低层消息函数(Low-level Message Functions)、基本加密函数(Base Cryptographic Functions)、证书编解码函数(Certificate Encode/Decode Functions)和证书库管理函数(Certificate Store Functions)。其中前三者可用于对敏感信息进行加密或签名处理,可保证网络传输信心的私有性;后两者通过对证书的使用,可保证网络信息交流中的认证性。

三、 CSP

看到这里,大家也许对CSP还比较迷惑。其实CSP是真正实行加密的独立模块,他既可以由软件实现也可以由硬件实现。但是他必须符合CryptoAPI接口的规范。

每个CSP都有一个名字和一个类型。每个CSP的名字是唯一的,这样便于CryptoAPI找到对应的CSP。目前已经有9种CSP类型,并且还在增长。下表列出出它们支持的密钥交换算法、签名算法、对称加密算法和Hash算法。
(表一)

CSP类型 交换算法 签名算法 对称加密算法 Hash算法
PROV_RSA_FULL RSA RSA RC2
RC4
MD5
SHA
PROV_RSA_SIG none RSA none MD5
SHA
PROV_RSA_SCHANNEL RSA RSA RC4
DES
Triple DES
MD5
SHA
PROV_DSS DSS none DSS MD5
SHA
PROV_DSS_DH DH DSS CYLINK_MEK MD5
SHA
PROV_DH_SCHANNEL DH DSS DES
Triple DES
MD5
SHA
PROV_FORTEZZA KEA DSS Skipjack SHA
PROV_MS_EXCHANGE RSA RSA CAST MD5
PROV_SSL RSA RSA Varies Varies

从图一可以看到,每个CSP有一个密钥库,密钥库用于存储密钥。而每个密钥库包括一个或多个密钥容器(Key Containers)。每个密钥容器中含属于一个特定用户的所有密钥对。每个密钥容器被赋予一个唯一的名字。在销毁密钥容器前CSP将永久保存每一个密钥容器,包括保存每个密钥容器中的公/私钥对(见图二)。



四、 创建密钥容器,得到CSP句柄

说了这么多只是一些理论性的东西,后面将详细介绍一下Microsoft CryptoAPI的使用方法。

我们已经提过,每一个CSP都有一个名字和一个类型,并且名字保证唯一。所以可以通过名字和类型得到一个CSP。然而,要想加密肯定需要密钥,那么密钥放哪里呢?对了,就放在密钥容器。(有人会问,密码库有什么用?其实密钥库是在安装CSP的时候已经存在了,他与CSP是相对应的。)但是密钥容器并不是一开始就存在的,需要用户去创建。下面的代码实现以上功能(得到CSP即密码容器)。

if(CryptAcquireContext(
&hCryptProv,               // 返回CSP句柄
UserName,                  // 密码容器名
NULL,                      // NULL时使用默认CSP名(微软RSA Base Provider)
PROV_RSA_FULL,             // CSP类型
0))                        // Flag values
{
//以UserName为名的密钥容器存在,那么我们已经得到了CSP的句柄
    printf("A crypto context with the %s key container \n", UserName);
    printf("has been acquired.\n\n");
}
else //如果密钥容器不存在,我们需要创建这个密钥容器
{ 
   if(CryptAcquireContext(
      &hCryptProv, 
      UserName, 
      NULL, 
      PROV_RSA_FULL, 
      CRYPT_NEWKEYSET)) //创建以UserName为名的密钥容器
   {
 //创建密钥容器成功,并得到CSP句柄
      printf("A new key container has been created.\n");
   }
   else
   {
      HandleError("Could not create a new key container.\n");
    }
} // End of else

好了,我们已经创建了密钥容器,并得到了CSP的句柄。也可以这样理解,我们得到了一个CSP的句柄,并且它被绑定到以UserName为名的密钥容器上。嘿嘿……

那么,以后的加解密等操作,都将在这个CSP上进行。
可以如下删除密钥容器。
CryptAcquireContext(&hCryptProv, userName, NULL, PROV_RSA_FULL, CRYPT_DELETEKEYSET);

五、 一个文件加密的例子

看到这里肯定有人开始说了,“这么多废话,还不快讲怎么加密怎么解密!”您先别急,有些原理性的东西还是先了解了比较好,对以后的使用会有很大帮助。

言归正传,我们来看一段文件加密的代码。

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define KEYLENGTH  0x00800000
void HandleError(char *s);

//--------------------------------------------------------------------
//  These additional #define statements are required.
#define ENCRYPT_ALGORITHM CALG_RC4 
#define ENCRYPT_BLOCK_SIZE 8 

//   Declare the function EncryptFile. The function definition
//   follows main.

BOOL EncryptFile(
     PCHAR szSource, 
     PCHAR szDestination, 
     PCHAR szPassword); 

//--------------------------------------------------------------------
//   Begin main.

void main(void) 
{ 
    CHAR szSource[100]; 
    CHAR szDestination[100]; 
    CHAR szPassword[100]; 
 
 
 printf("Encrypt a file. \n\n");
 printf("Enter the name of the file to be encrypted: ");
 scanf("%s",szSource);
 printf("Enter the name of the output file: ");
 scanf("%s",szDestination);
 printf("Enter the password:");
 scanf("%s",szPassword);
 
 //--------------------------------------------------------------------
 // Call EncryptFile to do the actual encryption.
 
 if(EncryptFile(szSource, szDestination, szPassword))
 {
  printf("Encryption of the file %s was a success. \n", szSource);
  printf("The encrypted data is in file %s.\n",szDestination);
 }
 else
 {
  HandleError("Error encrypting file!"); 
 } 
} // End of main

//--------------------------------------------------------------------
//   Code for the function EncryptFile called by main.

static BOOL EncryptFile(
      PCHAR szSource, 
      PCHAR szDestination, 
      PCHAR szPassword)
      //--------------------------------------------------------------------
      //   Parameters passed are:
      //     szSource, the name of the input, a plaintext file.
      //     szDestination, the name of the output, an encrypted file to be 
      //         created.
      //     szPassword, the password.
{ 
 //--------------------------------------------------------------------
 //   Declare and initialize local variables.
 
 FILE *hSource; 
 FILE *hDestination; 
 
 HCRYPTPROV hCryptProv; 
 HCRYPTKEY hKey; 
 HCRYPTHASH hHash; 
  
 PBYTE pbBuffer; 
 DWORD dwBlockLen; 
 DWORD dwBufferLen; 
 DWORD dwCount; 
 
 //--------------------------------------------------------------------
 // Open source file. 
 if(hSource = fopen(szSource,"rb"))
 {
  printf("The source plaintext file, %s, is open. \n", szSource);
 }
 else
 { 
  HandleError("Error opening source plaintext file!");
 } 

 //--------------------------------------------------------------------
 // Open destination file. 
 if(hDestination = fopen(szDestination,"wb"))
 {
  printf("Destination file %s is open. \n", szDestination);
 }
 else
 {
  HandleError("Error opening destination ciphertext file!"); 
 }

 //以下获得一个CSP句柄
 if(CryptAcquireContext(
  &hCryptProv, 
  NULL,    //NULL表示使用默认密钥容器,默认密钥容器名
//为用户登陆名
  NULL, 
  PROV_RSA_FULL, 
  0))
 {
  printf("A cryptographic provider has been acquired. \n");
 }
 else
 {
  if(CryptAcquireContext(
   &hCryptProv, 
   NULL, 
   NULL, 
   PROV_RSA_FULL, 
   CRYPT_NEWKEYSET))//创建密钥容器
  {
   //创建密钥容器成功,并得到CSP句柄
   printf("A new key container has been created.\n");
  }
  else
  {
   HandleError("Could not create a new key container.\n");
  }
  
 }

 //--------------------------------------------------------------------
 // 创建一个会话密钥(session key)
 // 会话密钥也叫对称密钥,用于对称加密算法。
 // (注: 一个Session是指从调用函数CryptAcquireContext到调用函数
 //   CryptReleaseContext 期间的阶段。会话密钥只能存在于一个会话过程)

 //--------------------------------------------------------------------
 // Create a hash object. 
 if(CryptCreateHash(
  hCryptProv, 
  CALG_MD5, 
  0, 
  0, 
  &hHash))
    {
        printf("A hash object has been created. \n");
    }
    else
    { 
  HandleError("Error during CryptCreateHash!\n");
    }  

 //--------------------------------------------------------------------
 // 用输入的密码产生一个散列
 if(CryptHashData(
  hHash, 
  (BYTE *)szPassword, 
  strlen(szPassword), 
  0))
 {
  printf("The password has been added to the hash. \n");
 }
 else
 {
  HandleError("Error during CryptHashData. \n"); 
 }

 //--------------------------------------------------------------------
 // 通过散列生成会话密钥
 if(CryptDeriveKey(
  hCryptProv, 
  ENCRYPT_ALGORITHM, 
  hHash, 
  KEYLENGTH, 
  &hKey))
 {
  printf("An encryption key is derived from the password hash. \n"); 
 }
 else
 {
  HandleError("Error during CryptDeriveKey!\n"); 
 }
 //--------------------------------------------------------------------
 // Destroy the hash object. 
 
 CryptDestroyHash(hHash); 
 hHash = NULL; 
 
 //--------------------------------------------------------------------
 //  The session key is now ready. 
 
 //--------------------------------------------------------------------
 // 因为加密算法是按ENCRYPT_BLOCK_SIZE 大小的块加密的,所以被加密的
// 数据长度必须是ENCRYPT_BLOCK_SIZE 的整数倍。下面计算一次加密的
// 数据长度。

 dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE; 
 
 //--------------------------------------------------------------------
 // Determine the block size. If a block cipher is used, 
 // it must have room for an extra block. 
 
 if(ENCRYPT_BLOCK_SIZE > 1) 
  dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE; 
 else 
  dwBufferLen = dwBlockLen; 
 
 //--------------------------------------------------------------------
 // Allocate memory. 
 if(pbBuffer = (BYTE *)malloc(dwBufferLen))
 {
  printf("Memory has been allocated for the buffer. \n");
 }
 else
 { 
  HandleError("Out of memory. \n"); 
 }
 //--------------------------------------------------------------------
 // In a do loop, encrypt the source file and write to the source file. 
 
 do 
 { 
  
  //--------------------------------------------------------------------
  // Read up to dwBlockLen bytes from the source file. 
  dwCount = fread(pbBuffer, 1, dwBlockLen, hSource); 
  if(ferror(hSource))
  { 
   HandleError("Error reading plaintext!\n");
  }
  
  //--------------------------------------------------------------------
  // 加密数据
  if(!CryptEncrypt(
   hKey,   //密钥
   0,    //如果数据同时进行散列和加密,这里传入一个
//散列对象
   feof(hSource), //如果是最后一个被加密的块,输入TRUE.如果不是输.
       //入FALSE这里通过判断是否到文件尾来决定是否为
//最后一块。
   0,    //保留
   pbBuffer,  //输入被加密数据,输出加密后的数据
   &dwCount,  //输入被加密数据实际长度,输出加密后数据长度
   dwBufferLen)) //pbBuffer的大小。
  { 
   HandleError("Error during CryptEncrypt. \n"); 
  } 
  
  //--------------------------------------------------------------------
  // Write data to the destination file. 
  
  fwrite(pbBuffer, 1, dwCount, hDestination); 
  if(ferror(hDestination))
  { 
   HandleError("Error writing ciphertext.");
  }
  
 } 
 while(!feof(hSource)); 
 //--------------------------------------------------------------------
 //  End the do loop when the last block of the source file has been
 //  read, encrypted, and written to the destination file.
 
 //--------------------------------------------------------------------
 // Close files.
 
 if(hSource) 
  fclose(hSource); 
 if(hDestination) 
  fclose(hDestination); 
 
 //--------------------------------------------------------------------
 // Free memory. 
 
 if(pbBuffer) 
  free(pbBuffer); 
 
 //--------------------------------------------------------------------
 // Destroy session key. 
 
 if(hKey) 
  CryptDestroyKey(hKey); 
 
 //--------------------------------------------------------------------
 // Destroy hash object. 
 
 if(hHash) 
  CryptDestroyHash(hHash); 
 
 //--------------------------------------------------------------------
 // Release provider handle. 
 
 if(hCryptProv) 
  CryptReleaseContext(hCryptProv, 0);
 return(TRUE); 
} // End of Encryptfile

//--------------------------------------------------------------------
//  This example uses the function HandleError, 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 HandleError(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 HandleError

上面的代码来自MSDN,并作了修改。注释已经很详细了,这里就不赘述了,
解密与加密大同小异,大家可以自己看代码。

这次先写这么多,也许很多人觉得我写这些大家都知道,并且也太简单了。不要急慢慢来,嘿嘿:)接下来会有一些比较深入和实用的技术。

分享到:
评论

相关推荐

    Microsoft CryptoAPI加密技术 源代码.zip

    Microsoft CryptoAPI加密技术 源代码.zip

    FreeOTFE文档

    FreeOTFE 磁盘加密技术能够实现对文件特定位置进行解密,也能够对光盘中的每一个字节进行加密,克服了... 本文档主要介绍了FreeOTFE 磁盘加密技术及FreeOTFE的安装于使用,另外还介绍了Microsoft CryptoAPI加密技术。

    狮王 写狗工具 系统加密 软件保护

    ET199提供符合业界广泛认可的PKCS#11和Microsoft CryptoAPI两种标准的接口。任何兼容这两种接口的应用程序,都可以立即集成ET199进行使用。同时,ET199也针对多个第三方的软件产品进行了兼容性优化。此外,ET199...

    PowerTCP SSL Tool – 用于解密网络传输数据的控件

    PowerTCP SSL Tool集成了Microsoft CryptoAPI、Security SupportProvider Interface和Winsock API,通过SSL2、SSL3、PCT和TLS安全协议确保TCP/IP数据的安全。它所包含的功能可用于安全的web访问、FTP客户端和服务器...

    PowerTCP_SSL_Tool_2_0_4_keygen

    PowerTCP SSL Tool集成了Microsoft CryptoAPI、Security SupportProvider Interface和Winsock API,通过SSL2、SSL3、PCT和TLS安全协议确保TCP/IP数据的安全。它所包含的功能可用于安全的web访问、FTP客户端和服务器...

    Microsoft SQL Server 2005 Express Edition SP3

    Windows 加密服务提供程序 (CSP) 是执行身份验证、编码和加密服务的代码,基于 Windows 的应用程序通过 Windows Server 2003 中的 CryptoAPI 访问这些服务。如果停止或禁用 CSP 服务,则 SQL Server 安装程序会失败...

    openssl-1.0.0a

    现在还出现了支持PKCS#11接口的Engine接口,支持微软CryptoAPI的接口也有人进行开发。当然,所有上述Engine接口支持不一定很全面,比如,可能支持其中一两种公开密钥算法。 [编辑本段]辅助功能  BIO机制是OpenSSL...

    OpenSSL-1_0_0d_Win32

    现在还出现了支持PKCS#11接口的Engine接口,支持微软CryptoAPI的接口也有人进行开发。当然,所有上述Engine接口支持不一定很全面,比如,可能支持其中一两种公开密钥算法。 8.辅助功能 BIO机制是OpenSSL提供的一种...

    Visual C++2010开发权威指南(共三部分).part1.rar

    9.3 微软GDI绘图简介 416 9.3.1 GDI基础 416 9.3.2 GDI结构 417 9.3.3 GDI函数调用 417 9.3.4 GDI基本图形 418 9.4 GDI笔绘图 419 9.4.1 CPen类简介 419 9.4.2 使用GDI绘制线条 419 9.4.3 使用CPen类绘制指定的线条 ...

Global site tag (gtag.js) - Google Analytics