目录
一、微软的CryptoAPI加密技术
微软的CryptoAPI是PKI推荐使用的加密API。其功能是为应用程序开发者提供在Win32环境下使用加密、验证等安全服务时的标准加密接口。CryptoAPI处于应用程序和CSP之间
CryptoAPI共有五部分组成:简单消息函数、低层消息函数、基本加密函数、证书编解码函数和证书库管理函数。前三者可用于对敏感信息进行加密或签名处理,可保证网络传输信心的私有性;后两者通过对证书的使用,可保证网络信息交流中的认证性。
-
基本加密函数:为开发加密应用程序提供了足够灵活的空间。所有CSP 的通讯都是通过这些函数。一个CSP 是实现所有加密操作的独立模块。在每一个应用程序中至少需要提供一个CSP来完成所需的加密操作。如果使用多于一个以上的CSP,在加密函数调用中就要指定所需的CSP。基本加密函数包含了以下几种:
-
服务提供者函数:应用程序使用服务提供者函数来连接和断开一个CSP。
-
密钥的产生和交换函数:密钥产生函数创建、配置和销毁加密密钥。他们也用于和其他用户进行交换密钥。
-
编码/解码函数:用来对证书、证书撤销列表、证书请求和证书扩展进行编码和解码。
-
数据加密/解密函数:这些函数支持数据的加密/解密操作。CryptEncrypt 和CryptDecrypt 要求在被调用前指定一个密钥。这个密钥可以由CryptGenKey、CryptDeriveKey 或CryptImportKey 产生。创建密钥时要指定加密算法。CryptSetKeyParam 函数可以指定额外的加密参数。
-
哈希和数字签名函数:这些函数在应用程序中完成计算哈希、创建和校验数字签名。
-
-
证书和证书库函数:这组函数管理、使用和取得证书、证书撤销列表和证书信任列表。这些函数可以分成一下几组:
-
证书库函数:一个用户站点可以收集许多证书。这些证书是为这个站点的用户所使用的,证书描述了这个用户的具体身份。对于每个人,可能有一个以上的证书。证书库和其相关的函数提供了对库获得、枚举、验证和使用证书库里的信息。
-
-
- 维护函数:
-
- 证书函数:下列函数是针对于证书的。大多数函数都是处理CRL 和CTL 的。
-
- 证书撤销列表函数:
-
-
证书信任列表函数:
-
-
-
扩展属性函数:
-
-
证书验证函数:证书验证是通过CTL 和证书列表进行的。
-
使用CTL 的函数:
-
-
-
证书链验证函数:
-
-
消息函数:CryptoAPI 消息函数包括两组——低级消息函数和简化消息函数。
-
低级消息函数直接和PKCS#7 消息工作。这些函数对传输的PKCS#7 数据进行编码,对接收到的PKCS#7 数据进行解码,并且对接收到的消息进行解密和验证。
-
-
- 简化消息函数是比较高级的函数,是对几个低级消息函数和证书函数的封装,用来执行指定任务。这些函数在完成一个任务时,减少了函数调用的数量,因此简化了CryptoAPI的使用。
-
辅助函数
-
数据管理函数
-
-
-
数据转换函数
-
-
-
增强密钥用法函数
-
-
-
密钥标示函数
-
-
-
证书库回调函数
-
-
-
OID 支持函数
-
-
-
远程对象恢复函数
-
-
-
PFX 函数
-
CSP:真正实行加密的独立模块,既可以由软件实现也可以由硬件实现。但是必须符合CryptoAPI接口的规范。
创建密钥容器,得到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 ", UserName); printf("has been acquired. "); } else //如果密钥容器不存在,我们需要创建这个密钥容器 { if(CryptAcquireContext( &hCryptProv, UserName, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) //创建以UserName为名的密钥容器 { //创建密钥容器成功,并得到CSP句柄 printf("A new key container has been created. "); } else { HandleError("Could not create a new key container. "); } } // End of else
代码实现:
#include "tool.h" #include <windows.h> #include <wincrypt.h> #include <stdio.h> #include <QDebug> BOOL CalHash(unsigned char* src, unsigned char* hash, int len) { HCRYPTPROV hCryptProv; //定义一个CSP模块的句柄。 LPCTSTR pszContainerName = TEXT("Hash");//用一个TEXT宏定义一个容器的名字, if(CryptAcquireContext( //这个函数是获取有某个容器的CSP模块的指针,成功返回TRUE。 &hCryptProv, //指向一个CSP模块句柄指针,里面用指定的容器 pszContainerName, //指定容器的名称 NULL, //这个参数这里用的是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块 PROV_RSA_AES, //确定密钥的类型 0)) { printf("CSP Create Success "); }else //不成功的处理段 { if(GetLastError() == NTE_BAD_KEYSET) // NTE_BAD_KEYSET意味着密钥容器不存在,下面就去创建一个新的密钥容器 { if(CryptAcquireContext(&hCryptProv, pszContainerName,NULL,PROV_RSA_AES, CRYPT_NEWKEYSET)) // CRYPT_NEWKEYSET意味着当指定容器不存在的时候,去创建一个容器。 { printf("A new key container has been created. "); }else { printf("CSP Create Fail "); return FALSE; } } } HCRYPTHASH hHash; //创建hash对象 if(!CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hHash)) { printf("CryptCreateHash fail!"); return FALSE; } if(!CryptHashData( hHash, (BYTE*)src, len, 0 )) { printf("CryptHashData fail!"); return FALSE; } DWORD dwHashLen= 16; if(!CryptGetHashParam(hHash, HP_HASHVAL, (BYTE*)hash, &dwHashLen, 0)) { printf("CryptGetHashParam fail!"); return FALSE; } CryptDestroyHash(hHash); CryptReleaseContext(hCryptProv, 0); return TRUE; } BOOL Encrypt(unsigned char* src, unsigned char* dest, char* passwd ) { HCRYPTPROV hCryptProv; //定义一个CSP模块的句柄。 LPCTSTR pszContainerName = TEXT("Encrypt");//用一个TEXT宏定义一个容器的名字, if(CryptAcquireContext( //这个函数是获取有某个容器的CSP模块的指针,成功返回TRUE。 &hCryptProv, //指向一个CSP模块句柄指针,里面用指定的容器 pszContainerName, //指定容器的名称 NULL, //这个参数这里用的是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块 PROV_RSA_AES, //确定密钥的类型 0)) { printf("CSP Create Success "); } else { //不成功的处理段 if(GetLastError() == NTE_BAD_KEYSET) // NTE_BAD_KEYSET意味着密钥容器不存在,下面就去创建一个新的密钥容器 { if(CryptAcquireContext(&hCryptProv, pszContainerName,NULL,PROV_RSA_AES, CRYPT_NEWKEYSET)) // CRYPT_NEWKEYSET意味着当指定容器不存在的时候,去创建一个容器 { printf("A new key container has been created. "); } } HCRYPTHASH hCryptHash; //创建hash对象 if(!CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hCryptHash)) { printf("CryptCreateHash fail!"); return FALSE; } //用输入的密码作哈稀散列 if(!CryptHashData( hCryptHash,lse { printf("CSP Create Fail "); return FALSE; } } (BYTE*)passwd, strlen(passwd), 0)) { printf("CryptHashData fail!"); return FALSE; } //用哈稀散列生成会话密钥 HCRYPTKEY hCryptKey; if(!CryptDeriveKey(hCryptProv, CALG_AES_128, hCryptHash, CRYPT_EXPORTABLE, &hCryptKey )) { printf("CryptDeriveKey fail!"); return FALSE; } //对文件进行加密,hCryptKey已经与加密算法相关联了CALG_AES_128 unsigned char buf[16]; DWORD lenght = 16; memcpy(buf,src,16); if(!CryptEncrypt(hCryptKey, NULL,//如果数据同时进行散列和加密,这里传入一个散列对象 0,//如果是最后一个块为TRUE 0, (BYTE*)buf,//输入被加密的数据,输出加密数据 &lenght,//输入输入数据长度,输出加密后数据长度 16 )) { qDebug() << "errre"; qDebug() << GetLastError(); } memcpy(dest,buf,16); CryptDestroyHash(hCryptHash); CryptReleaseContext(hCryptProv, 0); return TRUE; } BOOL Decrypt(unsigned char* src, unsigned char* dest, char* passwd ) { HCRYPTPROV hCryptProv; //定义一个CSP模块的句柄。“CSP模块,请查看《加密解密二》222页,那里有简单的说明,这里就不说了。 LPCTSTR pszContainerName = TEXT("Decrypt");//用一个TEXT宏定义一个容器的名字, if(CryptAcquireContext( //这个函数是获取有某个容器的CSP模块的指针,成功返回TRUE。 &hCryptProv, //指向一个CSP模块句柄指针,里面用指定的容器 pszContainerName, //指定容器的名称 NULL, //这个参数这里用的是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块 PROV_RSA_AES, //确定密钥的类型 0)) //常设为0,还有些其他的类型,请看MSDN { printf("CSP Create Success "); } else { //不成功的处理段 if(GetLastError() == NTE_BAD_KEYSET) // NTE_BAD_KEYSET意味着密钥容器不存在,下面就去创建一个新的密钥容器 { if(CryptAcquireContext(&hCryptProv, pszContainerName,NULL,PROV_RSA_AES, CRYPT_NEWKEYSET)) // CRYPT_NEWKEYSET意味着当指定容器不存在的时候,去创建一个容器。 { printf("A new key container has been created. "); } else { printf("CSP Create Fail "); return FALSE; } } } HCRYPTHASH hCryptHash; //创建hash对象 if(!CryptCreateHash( hCryptProv, CALG_MD5, 0, 0, &hCryptHash)) { printf("CryptCreateHash fail!"); return FALSE; } //用输入的密码作哈稀散列 if(!CryptHashData( hCryptHash, (BYTE*)passwd, strlen(passwd), 0 )) { printf("CryptHashData fail!"); return FALSE; } //用哈稀散列生成会话密钥 HCRYPTKEY hCryptKey; if(!CryptDeriveKey(hCryptProv, CALG_AES_128, hCryptHash, CRYPT_EXPORTABLE, &hCryptKey )) { printf("CryptDeriveKey fail!"); return FALSE; } CryptDestroyHash(hCryptHash); //对文件进行加密,hCryptKey已经与加密算法相关联了CALG_AES_128 unsigned char buf[16]; DWORD lenght = 16; memcpy(buf,src,16); CryptDecrypt(hCryptKey, NULL,//如果数据同时进行散列和加密,这里传入一个散列对象 0,//如果是最后一个块为TRUE 0, (BYTE*)buf,//输入被加密的数据,输出加密数据 &lenght//输入输入数据长度,输出加密后数据长度 ); memcpy(dest,buf,16); CryptReleaseContext(hCryptProv, 0); return TRUE; } BOOL Sign(unsigned char* src, unsigned char* dest, int len) { HCRYPTPROV hCryptProv; //定义一个CSP模块的句柄。“CSP模块,请查看《加密解密二》222页,那里有简单的说明,这里就不说了。 LPCTSTR pszContainerName = TEXT("Decrypt");//用一个TEXT宏定义一个容器的名字, if(CryptAcquireContext( //这个函数是获取有某个容器的CSP模块的指针,成功返回TRUE。 &hCryptProv, //指向一个CSP模块句柄指针,里面用指定的容器 pszContainerName, //指定容器的名称 NULL, //这个参数这里用的是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块 PROV_RSA_FULL, //确定密钥的类型 0)) //常设为0,还有些其他的类型,请看MSDN { printf("CSP Create Success "); } else { //不成功的处理段 if(GetLastError() == NTE_BAD_KEYSET) // NTE_BAD_KEYSET意味着密钥容器不存在,下面就去创建一个新的密钥容器 { if(CryptAcquireContext(&hCryptProv, pszContainerName,NULL,PROV_RSA_AES, CRYPT_NEWKEYSET)) // CRYPT_NEWKEYSET意味着当指定容器不存在的时候,去创建一个容器。 { printf("A new key container has been created. "); } else { printf("CSP Create Fail "); return FALSE; } } } HCRYPTKEY hKey; //创建一个密钥句柄 if(CryptGetUserKey( // CryptGetUserKey是获取一个密钥句柄的函数,成功返回TRUE hCryptProv, //指定容器的CSP模块句柄 AT_SIGNATURE, //指定私钥的类型 &hKey)) //原来接收获取的密钥句柄 { printf("A signature key is available. "); } else { printf("No signature key is available. "); if(GetLastError() == NTE_NO_KEY) // NTE_NO_KEY意味着密钥不存在,下面就生成一个密钥 { printf("The signature key does not exist. "); printf("Create a signature key pair. "); if(CryptGenKey( // CryptGenKey生成一个密钥 hCryptProv, //指定CSP模块的句柄 AT_SIGNATURE, //对于公钥密码系统,生成一个私钥和一个公钥,这个参数指定了这个密钥是公钥,于是生成了一个密码对。如果不是公钥系统,则指定了密码算法,具体看MSDN。 0, //指定了生成密钥的类型,这个参数的说明挺多的,想获取更为详尽的资料请看MSDN。 &hKey)) { printf("Created a signature key pair. "); } else { printf("Created a signature key fail. "); return FALSE; } } else { printf("An error other than NTE_NO_KEY "); return FALSE; } } HCRYPTHASH hHash; if(!CryptHashData( hHash, (BYTE*)src, len, 0 )) { printf("CryptHashData fail!"); return FALSE; } DWORD lenght = 32; if(!CryptSignHash(hHash,AT_SIGNATURE,NULL,CRYPT_TYPE2_FORMAT,(BYTE*)dest,&lenght)) { printf("CryptSignHash fail!"); return FALSE; } if(hKey) //将密钥句柄销毁 { if(!(CryptDestroyKey(hKey))) { printf("Error during CryptDestroyKey."); } hKey = NULL; } CryptDestroyHash(hHash); CryptReleaseContext(hCryptProv, 0); return TRUE; } char *qstoc(const QString Qstr) { QByteArray ba = Qstr.toLatin1(); char *c_str; c_str = (char *)malloc(ba.length() + 1); memset(c_str, 0, ba.length()); memcpy(c_str, ba.data(), ba.length()); c_str[ba.length()] = '