zoukankan      html  css  js  c++  java
  • 《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;

    }

  • 相关阅读:
    Mysql实战面试题
    初探Google Guava
    Spring IOC核心源码学习
    用3句话像老太太讲清楚什么是数据库
    matlab如何读入mat型的矩阵
    工作记忆数据处理
    功能连接
    奖励学习
    格兰杰因果关系及其在医学影像数据中的应用
    GC wm
  • 原文地址:https://www.cnblogs.com/testlife007/p/7058879.html
Copyright © 2011-2022 走看看