《ASCE1885的信息安全》のCryptoAPI---密钥的产生和交换函数

在公开密码算法的前提下,数据的安全取决于密钥。因此,密钥的产生、销毁、交换(分发)是数据保密工作中的重要部分。

CryptoAPI密钥产生和交换函数主要有生成密钥函数CryptGenKey、派生密钥函数CryptDeriveKey、销毁密钥函数CryptDestroyKey、复制密钥函数CryptDuplicateKey、导出密钥函数CryptExportKey、导入密钥函数CryptImportKey、获得密钥参数函数CryptGetKeyParam、设置密钥参数函数CryptSetKeyParam、产生随机函数CryptGenRandom、

一、生成函数CryptGenKey:

功能:产生一个随机的对称或非对称算法的密钥;

原型:

BOOL WINAPI CryptGenKey(

__in   HCRYPTPROV hProv,         //CSP句柄指针

__in   ALG_ID Algid,       //密码算法标识

__in   DWORD dwFlags,        //标志位,指定生成密钥的参数,

//如对称密钥的长度,RSA密钥的长度

__out  HCRYPTKEY *phKey  //新产生的密钥的句柄

);

其中,Algid参数取值如下:

CALG_HMAC---HMAC带密钥的摘要算法;

CALG_MD2---MD2摘要算法;

CALG_MD4---MD4摘要算法;

CALG_MD5---MD5摘要算法;

CALG_SHA---SHA摘要算法;

CALG_SHA1---SHA1摘要算法;

CALG_MAC---MAC算法;

CALG_SSL3_SHAMD5---SSLV3客户端算法;

CALG_RSA_SIGN---RSA签名算法;

CALG_DSS_SIGN---DSS签名算法;

CALG_RSA_KEYX---RSA加密算法;

CALG_DES---DES---对称加密算法;

CALG_3DES_112---112位的3DES加密算法;

CALG_3DES---3DES加密算法;

CALG_RC2---RC2分组算法;

CALG_RC4---RC4流加密算法。

返回值:操作成功返回TRUE,否则返回FALSE,使用GetLastError获取更多信息。

二、派生密钥函数CryptDeriveKey:

功能:根据基础数据派生以对称密钥(会话密钥);

原型:

BOOL WINAPI CryptDeriveKey(

__in     HCRYPTPROV hProv,     //CSP句柄指针

__in     ALG_ID Algid,  //密码算法标识

__in     HCRYPTHASH hBaseData,     //基础数据的摘要句柄

__in     DWORD dwFlags,   //标志位

__inout  HCRYPTKEY *phKey        //新产生的会话密钥句柄

);

此函数和CryptGenKey函数相似,不同的是CryptGenKey是通过随机数产生的,而CryptDeriveKey是通过指定的数据产生的。CryptDeriveKey只能产生对称算法的会话密钥,不能产生非对称算法的公/私钥。

返回值:操作成功返回TRUE,否则返回FALSE,使用GetLastError获取更多信息。

三、销毁密钥函数CryptDestroyKey:

功能:销毁密钥;

原型:

BOOL WINAPI CryptDestroyKey(

__in  HCRYPTKEY hKey //密钥句柄

);

返回值:操作成功返回TRUE,否则返回FALSE,使用GetLastError()获取更多信息。

下面的示例由一个密码产生会话密钥:

#include <windows.h>

#include <wincrypt.h>

#include <iostream>

#include <string.h>

#include <conio.h>

#include <stdio.h>

#pragma comment(lib, "crypt32.lib")

#define PASSWORD_LENGTH 512

void HandleError(TCHAR* s);

void GetConsoleInput(CHAR*, UINT);

int _tmain(int argc, _TCHAR* argv[])

{

HCRYPTPROV hCryptProv;

HCRYPTKEY hKey;

HCRYPTHASH hHash;

CHAR szPassword[PASSWORD_LENGTH] = "";

DWORD dwLength;

fprintf(stderr, "请输入用于产生会话密钥的密码:");

//获得用户输入密码,控制台上显示的是*号

GetConsoleInput(szPassword, PASSWORD_LENGTH);

printf("密码已保存/n");

dwLength = (DWORD)strlen(szPassword);

//获得CSP句柄

if(!CryptAcquireContext(&hCryptProv, NULL, NULL,

PROV_RSA_FULL, 0))

{

HandleError(L"获取CSP句柄时出错");

}

//创建一个空的哈希对象

if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash))

{

HandleError(L"创建空的哈希对象时出错");

}

//对密码进行哈希

if(!CryptHashData(hHash, (BYTE*)szPassword, dwLength, 0))

{

HandleError(L"对密码进行哈希时出错");

}

//由密码的哈希值创建会话密钥

if(!CryptDeriveKey(hCryptProv, CALG_RC2, hHash,

CRYPT_EXPORTABLE, &hKey))

{

HandleError(L"由密码的哈希值创建会话密钥时出错");

}

//这里使用上面得到的会话密钥进行加解密等操作,略...

//释放资源

if(hHash)

{

if(!CryptDestroyHash(hHash))

HandleError(L"销毁哈希对象时出错");

}

if(hKey)

{

if(!CryptDestroyKey(hKey))

HandleError(L"销毁会话密钥时出错");

}

if(hCryptProv)

{

if(!CryptReleaseContext(hCryptProv, 0))

HandleError(L"释放CSP句柄时出错");

}

printf("程序正常结束运行/n");

system("pause");

return 0;

}

void HandleError(TCHAR* s)

{

_tprintf(TEXT("程序运行出现错误./n"));

_tprintf(TEXT("%s/n"),s);

_tprintf(TEXT("错误代码%x/n."), GetLastError());

_tprintf(TEXT("程序终止./n"));

exit(1);

}

//从键盘获取字符串输入,并控制台上*号显示

void GetConsoleInput(char* strInput, UINT 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‘);

}

四、复制密钥函数CryptDuplicateKey:

功能:复制一个密钥,产生一个密钥的拷贝,包括其状态;

原型:

BOOL WINAPI CryptDuplicateKey(

__in   HCRYPTKEY hKey,       //密钥句柄

__in   DWORD *pdwReserved,   //保留参数,必须为NULL

__in   DWORD dwFlags,        //保留参数,必须为0

__out  HCRYPTKEY *phKey  //复制后的密钥句柄

);

返回值:操作成功返回TRUE,否则返回FALSE,使用GetLastError()获取更多信息。

五、获得密钥参数函数CryptGetKeyParam:

功能:获得key句柄的各项参数;

原型:

BOOL WINAPI CryptGetKeyParam(

__in     HCRYPTKEY hKey,  //密钥句柄

__in     DWORD dwParam,         //参数类型

__out    BYTE *pbData,          //接收key参数数据缓冲区指针

__inout  DWORD *pdwDataLen,          //输出的数据长度

__in     DWORD dwFlags    //保留参数,必须为0

);

其中,对于所有的key,dwParam可取值如下:

KP_ALGID---算法ID;

KP_BLOCKLEN---如果hKey为会话密钥,则此参数获得对称算法分组长度(单位为比特);

如果hKey为非对称密钥,则此参数获得密钥对加密强度(单位为比特,如1024bits RSA)

KP_KEYLEN---密钥长度;

KP_SALT---salt值,不使用于非对称密钥对;

对于对称密钥或者会话密钥,dwParam还可取值如下:

KP_IV---初始化向量;

KP_PADDING---补位的方式;

KP_MODE---加密模式(CBC、ECB等)。

返回值:操作成功返回TRUE,否则返回FALSE,调用GetLastError()获得更多信息。

六、获得密钥参数函数CryptSetKeyParam:

功能:设置key句柄的各项参数;

原型:

BOOL WINAPI CryptSetKeyParam(

__in  HCRYPTKEY hKey,         //密钥句柄

__in  DWORD dwParam,       //参数类型

__in  const BYTE *pbData,      //参数数据缓冲区指针

__in  DWORD dwFlags  //只用于dwParam为KP_ALGID时

);

其中dwParam可取值如下:

KP_ALGID---算法ID;

KP_SALT---salt值,不适用于非对称密钥对;

KP_IV---初始化向量;

KP_PADDING---补位的方式;

KP_MODE---加密模式(CBC,ECB等);

KP_CERTIFICATE---设置数字证书,对于RSA密钥,设置与其对应的数字证书;pbData即为DER编码的X509证书指针;

KP_KEYEXCHANGE_PIN---设置操作该交换密钥的口令;

KP_SIGNATRUE_PIN---设置操作该签名密钥的口令。

返回值:操作成功返回TRUE,否则返回FALSE,调用GetLastError()获得更多信息。

七、获得随机数函数CryptGenRandom:

功能:生成随机数;

原型:

BOOL WINAPI CryptGenRandom(

__in     HCRYPTPROV hProv,     //CSP句柄

__in     DWORD dwLen,      //生成随机数的长度

__inout  BYTE *pbBuffer         //接收随机数缓冲区的指针

);

返回值:操作成功返回TRUE,否则返回FALSE,调用GetLastError()获得更多信息。

下面代码示例演示了复制一个会话密钥的过程:

#include <windows.h>

#include <wincrypt.h>

#include <iostream>

#include <string.h>

#include <conio.h>

#include <stdio.h>

#pragma comment(lib, "crypt32.lib")

//#define ASCE_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

#define PASSWORD_LENGTH 512

void HandleError(TCHAR* s);

void GetConsoleInput(CHAR*, UINT);

int _tmain(int argc, _TCHAR* argv[])

{

HCRYPTPROV hCryptProv;

HCRYPTKEY hOriginalKey;

HCRYPTKEY hDuplicateKey;

DWORD dwMode;

BYTE pbData[16];

printf("本程序创建一个会话密钥,并复制它,同时添加参数到原会话密钥中/n");

if(!CryptAcquireContext(&hCryptProv, NULL, NULL,

PROV_RSA_FULL, 0))

{

HandleError("创建CSP句柄时出错");

}

//生成一个会话密钥

if(!CryptGenKey(hCryptProv, CALG_RC4, 0, &hOriginalKey))

{

HandleError("生成会话密钥时出错");

}

//复制会话密钥

if(!CryptDuplicateKey(hOriginalKey, NULL, 0, &hDuplicateKey))

{

HandleError("复制会话密钥时出错");

}

//给原会话密钥设置参数

dwMode = CRYPT_MODE_ECB;

if(!CryptSetKeyParam(hOriginalKey, KP_MODE,

(BYTE*)&dwMode, 0))

{

HandleError("给原会话密钥设置参数时出错");

}

//生成一个随机初始化向量

if(!CryptGenRandom(hCryptProv, 8, pbData))

{

HandleError("生成一个随机初始化向量时出错");

}

//给原会话密钥设置初始化向量

if(!CryptSetKeyParam(hOriginalKey, KP_IV, pbData, 0))

{

HandleError("给原会话密钥设置初始化向量时出错");

}

//释放资源

if(hOriginalKey)

{

if(!CryptDestroyKey(hOriginalKey))

HandleError(L"销毁原会话密钥时出错");

}

if(hDuplicateKey)

{

if(!CryptDestroyKey(hDuplicateKey))

HandleError(L"销毁复制会话密钥时出错");

}

if(hCryptProv)

{

if(!CryptReleaseContext(hCryptProv, 0))

HandleError(L"释放CSP句柄时出错");

}

printf("程序正常结束运行/n");

system("pause");

return 0;

}

void HandleError(TCHAR* s)

{

_tprintf(TEXT("程序运行出现错误./n"));

_tprintf(TEXT("%s/n"),s);

_tprintf(TEXT("错误代码%x/n."), GetLastError());

_tprintf(TEXT("程序终止./n"));

exit(1);

}

八、导出密钥函数CryptExportKey:

功能:从CSP导出密钥或密钥对;

原型:

BOOL WINAPI CryptExportKey(

__in     HCRYPTKEY hKey,  //要导出的密钥句柄

__in     HCRYPTKEY hExpKey, //目标用户的加密密钥,用于加密要导出的数

__in     DWORD dwBlobType,   //pbData中的数据类型

__in     DWORD dwFlags,   //标志位

__out    BYTE *pbData,          //接收导出密钥数据块的缓冲区指针

__inout  DWORD *pdwDataLen  //pbData字节大小

);

返回值:操作成功返回TRUE,否则返回FALSE,调用GetLastError()获得更多信息。

九、导入密钥函数CryptImportKey:

功能:把BLOB数据导入CSP,该函数可导入会话密钥、公钥、或者公私钥对。

原型:

BOOL WINAPI CryptImportKey(

__in   HCRYPTPROV hProv,         //CSP句柄

__in   BYTE *pbData,      //BLOB数据

__in   DWORD dwDataLen, //BLOB数据长度

__in   HCRYPTKEY hPubKey,        //此参数的意义根据CSP类型以及导入的BLOB数据的类型不同而不同:如果BLOB数据是由交换密钥加密的,该参数就是交换密钥的句柄

如果BLOB数据是由会话密钥加密的,该参数就是会话密钥的句柄

如果BLOB数据没有被加密,则该参数为NULL

__in   DWORD dwFlags,        //标志位

__out  HCRYPTKEY *phKey  //导入密钥的句柄

);

返回值:操作成功返回TRUE,否则返回FALSE,调用GetLastError()获得更多信息。

下面代码演示了密钥的导入和导出操作:

#include <windows.h>

#include <wincrypt.h>

#include <iostream>

#include <stdio.h>

#pragma comment(lib, "crypt32.lib")

//存在数组中的明文密钥BLOB,数组格式必须如下所示:

//      BLOBHEADER hdr;

//      DWORD dwKeySize;

//      BYTE rgbKeyData[];

BYTE DesKeyBlob[] =

{

0x08, 0x02, 0x00, 0x00, 0x01, 0x66, 0x00, 0x00, //BLOB header

0x08, 0x00, 0x00, 0x00,      //key length, in bytes

0xf1, 0x0e, 0x25, 0x7c, 0x6b, 0xce, 0x0d, 0x34 //DES key with parity

};

//#define ASCE_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

#define PASSWORD_LENGTH 512

void HandleError(TCHAR* s);

void GetConsoleInput(CHAR*, UINT);

int _tmain(int argc, _TCHAR* argv[])

{

HCRYPTPROV hCryptProv = NULL;

HCRYPTKEY hKey = NULL;

DWORD dwBlobLen;

BYTE* pbKeyBlob;

//获得CSP句柄

if(!CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV,

PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))

{

//如果密钥容器打不开,则创建一个新的

if(NTE_BAD_KEYSET == GetLastError())

{

if(!CryptAcquireContext(&hCryptProv, L"ASCEContainer",

MS_ENHANCED_PROV, PROV_RSA_FULL,

CRYPT_NEWKEYSET |CRYPT_VERIFYCONTEXT))

{

printf("创建新的密钥容器出错/n");

return -1;

}

else

{

printf("打开密钥容器失败/n");

return -1;

}

}

}

//导入PLAINTEXTKEYBLOB数组到密钥容器中

if(!CryptImportKey(hCryptProv, DesKeyBlob,

sizeof(DesKeyBlob), 0, CRYPT_EXPORTABLE, &hKey))

{

printf("导入密钥时出错/n");

return -1;

}

//将刚导入的密钥导出来,验证是否正确

if(!CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB,

0, NULL, &dwBlobLen))

{

printf("获取BLOB长度时出错/n");

return -1;

}

if(!(pbKeyBlob = (BYTE*)malloc(dwBlobLen)))

{

printf("分配内存时出错/n");

return -1;

}

if(!CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB,

0, pbKeyBlob, &dwBlobLen))

{

printf("导出密钥时出错/n");

return -1;

}

DWORD count;

//打印明文BLOB以验证密钥导入是否正确

for(count=0; count<dwBlobLen;)

{

printf("%02x", pbKeyBlob[count]);

count++;

}

//释放资源

if(pbKeyBlob)

{

free(pbKeyBlob);

}

if(hCryptProv)

{

if(!CryptReleaseContext(hCryptProv, 0))

HandleError(L"释放CSP句柄时出错");

}

printf("程序正常结束运行/n");

system("pause");

return 0;

}

时间: 2024-11-06 21:58:27

《ASCE1885的信息安全》のCryptoAPI---密钥的产生和交换函数的相关文章

CSP应用开发-CryptAPI函数库介绍

基本加密函数为开发加密应用程序提供了足够灵活的空间.所有CSP的通讯都是通过这些函数.一个CSP是实现所有加密操作的独立模块.在每一个应用程序中至少需要提供一个CSP来完成所需的加密操作.如果使用多于一个以上的CSP,在加密函数调用中就要指定所需的CSP.微软基本加密提供者(Microsoft Base Cryptographic Provider),是缺省绑定到CryptoAPI 里的.如果没有指定其他CSP时,这个CSP 就是却省的.每一个CSP对CryptoAPI 提供了一套不同的实现.一

[加密解密]CryptoAPI简介

CryptoAPI概述 Windows CryptoAPI是Microsoft 公司提出的安全加密应用服务框架,也是PKI推荐使用的加密 API.它提供了在Win32 环境下使用认证.编码.加密和签名等安全服务时的标准加密接口,用于增强应用程序的安全性与可控性.应用开发者可以在不了解复杂的加密机制和加密算法的情况下,简便.快速地开发出标准.通用和易于扩展的安全加密应用程序.CryptoAPI 提供的功能主要有:密钥管理.数据加密和解密.数字签名和验证.证书管理.可信根证书管理.数据编码和解码.数

HTTPS中的对称密钥加密,公开密钥加密,数字证书

HTTPS中的对称密钥加密,公开密钥加密,数字证书 密钥 我们将未加密的内容称为明文,加密之后的内容称为密文. 简单来说,要加密一段明文,可以将这段内容输入到一个加密函数中,输出密文.但这种简单的加密方式存在被人盗取到加密函数从而破解明文的危险,且加密函数一般构成复杂,一旦被盗取更换成本较高. 于是人们想出了一个办法,在加密函数中再添加一个参数,这个参数只有通信双方知道,没有参数则无法正确解密出密码.这个参数被称为密钥.对于同一个加密函数而言,密钥值的不同则加密方式也不同,得出的密文也就不同.这

数据加密解密初探

在一次网络通信或者是进程通信中,如果传输数据采用明文的方式,那么很容易被第三方"窃听"到,安全性难以保障. 而所谓加密是让数据从明文变成密文,传输过程中是密文,传送过去之后对方接收到的也是密文.--可以理解为密文就是乱码,看不出内在的任何意义,通常也都是逐位对应的. 在接收方接收到密文之后只有把它还原为原来的样子才可以理解对方说的具体是什么,此过程就叫做解密. 所谓系统的安全要实现的目标应该包括:机密性-confidentiality,完整性-integrity 和可用性-availa

IPSec VPN的原理与配置

博主QQ:819594300 博客地址:http://zpf666.blog.51cto.com/ 有什么疑问的朋友可以联系博主,博主会帮你们解答,谢谢支持! 一.VPN概述 VPN技术最早是为了解决明文数据在网络上传输带来的安全隐患而产生的.TCP/IP协议族中很多协议都是采用明文传输的,比如telnet.ftp.tftp等. VPN技术可以对公网上传输的数据进行加密,也可以实现数据传输双方的身份验证. 1.VPN的定义 VPN(虚拟专用网),就是在两个网络实体之间建立的一个受保护的连接.这两

用于 SELECT 和 WHERE 子句的函数

1 一个 SQL 语句中的 select_expression 或 where_definition 可由任何使用了下面所描述函数的表达式组成. 2 3 包含 NULL 的表达式总是得出一个 NULL 值结果,除非表达式中的操作和函数在文档中有另外的说明. 4 5 注意:在一个函数名和跟随它的括号之间必须不存在空格.这有助于 MySQL 语法分析程序区分函数调用和对恰巧与函数同名表或列的引用.然而,参数左右两边的空格却是允许的. 6 7 你可以强制 MySQL 接受函数名后存在空格的形式,这需要

IPSec VPN原理与配置

需求:IPSec在VPN对等体设备实现的安全特性,如数据的机密性,完整性,验证等. 效果:对公网上传输的数据进行加密,即使黑客通过某种窃听工具截获到数据,也无法了解数据信息的含义:也可以实现数据传输双方的身份验证,避免黑客伪装成网络中的合法用户攻击网络资源. 理论:    VPN概述 VPN起源是为了解决明文数据在网络上传输带来的安全隐患而兴起的.TCP/IP协议簇中的很多协议都采用明文传输,如telnet,ftp,ftfp等. VPN可以对公网上传输的数据进行加密,即使黑客通过某种窃听工具截获

网络安全简介

在一个面向公共网络的项目中,安全无疑是项目面临的巨大挑战之一.在公网上,蛋疼份子与无聊人士无时无刻嗅探着我们的服务器,有些人是想要展示自己的能力,而还有着一部分不法分子,想要监听拦截我们的敏感信息,进入我们的主机进行各种各样的破坏与偷窃.这些人一旦得手,轻则降低系统的稳定性,重则使企业的敏感数据丢失,毁掉企业的信誉.所以,向用户提供可靠与稳定的服务,防止重要数据的丢失与盗取,是我们在构建一个面向公共网络的WEB系统中一定要做到的. 要想构建一个安全的网络环境,首先我们必须了解安全威胁来自哪里.以

证书制作 z

一.WCF中的安全方式 说到安全就会涉及到认证,消息一致性和机密性,WCF的安全方式分为两种,即传输安全和消息安全. 传输安全和消息安全的区别:传输安全提供点对点的安全: 比如 A 提供服务,B和C直接连接到A,这时候A与B 及 A与C直接的传输是安全的,如果B通过C连接到A,那么A与B直接是安全的,B与C之间是不安全的.消息安全:是把安全机制都应用在消息级别上面的,能够提供端对端的安全,不管消息的路由路径多么复杂,也能保证消息的安全传输.传输安全我们一般应用在局域网中,消息安全主要应用在复杂的