• MicroSoft CryptoAPI data/file encrypt/decrypt


    linux 用第三方库 Crypto++, 还未实战。

    CryptoAPI使用两种密钥:会话密钥与公共/私人密钥对。会话密钥使用相同的加密和解密密钥,这种算法较快,但必须保证密钥的安全传递。公共/私人密钥对使用一个公共密钥和一个私人密钥,私人密钥只有专人才能使用,公共密钥可以广泛传播。如果密钥对中的一个用于加密,另一个一定用于解密。公共/私人密钥对算法很慢,一般只用于加密小批数据,例如用于加密会话密钥。

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

    //#include <conio.h>

    //#pragma comment (lib, "advapi32")

    #define KEYLENGTH  0x00800000

    #define ENCRYPT_ALGORITHM CALG_RC4 

    #define ENCRYPT_BLOCK_SIZE 8

    常用步骤:

    一. 获取容器handle

    CryptAcquireContext(   

       &hCryptProv, //返回的CSP句柄,密钥容器   

       NULL,   //密钥容器的名字   

       MS_ENHANCED_PROV, //这个参数这里用的是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块   

       PROV_RSA_FULL, //这里为使用的加密策略   0

    );

    返回true, 则正常; false, 则异常

    二. 创建密钥

    1. 根据固定password, 主要用于对称加密

            //初始化一个HASH对象,产生一个空的HASH对象

    CryptCreateHash(   

      hCryptProv,   //密钥容器句柄   

      CALG_MD5, //指定的hash算法

      0,   

      0,   

      &hHash  //hash句柄

    );

    //对数据使用hash后, 保存在hHash中

    CryptHashData(   

      hHash,   

      (BYTE *)pszPassword,   //LPTSTR pszPassword   

      lstrlen(pszPassword),   

      0

    );

    //利用hash对象生成密钥

    CryptDeriveKey(  //从某一数据产生会话密钥。有点类似CryptGenKey,但是产生的会话密钥来自固定数据,而CryptGenKey是随机产生的。并且不能产生公 / 私钥对   

      hCryptProv,   //密钥容器句柄   

      ENCRYPT_ALGORITHM, //in,指定的算法,类似CryptGenKey   

      hHash, //in,HASH对象的句柄   

      KEYLENGTH, //in,指定产生密钥的类型   

      &hKey);    //in, out, 产生的密钥句柄地址

    2. 随机产生, 每次产生都不一样,解密时,要根据获取的blob解密, 主要用于非对称加密

    //产生一个随机的交换密钥或者公/私钥对

    CryptGenKey( 

      hCryptProv,   //密钥容器句柄   

      ENCRYPT_ALGORITHM,  //表明产生私钥所使用的算法或者公钥生成的算法   

      KEYLENGTH | CRYPT_EXPORTABLE, //表示密钥使用的长度,参数可以为0,采用默认的密钥长度   

      &hKey  //获取密钥句柄

    );

    //获取交换密钥

    CryptGetUserKey(   

      hCryptProv,   //密钥容器句柄   

      AT_KEYEXCHANGE, //AT_KEYEXCHANGE(交换密钥) or AT_SIGNATURE(签名密钥)   

      &hXchgKey  //获取交换密钥

    );

    //以下3步是用交换密钥将密钥加密后,存储到Blob

    a. 导出密钥只是先获取导出key Blob的长度

    CryptExportKey(   

      hKey, //需要导出的密钥句柄   

      hXchgKey, //将待导出密钥用交换密钥进行加密,假如是公开的BLOG当然就设置为0   

      SIMPLEBLOB, // 指定导出的密钥BLOB类型,BLOB也就是一种存储结构。六个参数见MSDN   

      0,   

      NULL, //导出的数据指针,以后就可以将这个数据写如磁盘或者别的任务   

      &dwKeyBlobLen  //导出的数据长度

    );

    b. 为Blob分配内存

      pbKeyBlob = (BYTE *)malloc(dwKeyBlobLen);

    c. 用交换密钥加密后,存储到Blob

      CryptExportKey(    hKey,    hXchgKey,    SIMPLEBLOB,    0,    pbKeyBlob,    &dwKeyBlobLen);

    //释放交换密钥 if(hXchgKey)  

      CryptDestroyKey(hXchgKey);

    //创建导出的Keyblob目标文件

      hexportkeyDestinationFile  = CreateFile(pszexportkeyDestination,   FILE_WRITE_DATA,   FILE_SHARE_READ,   NULL,   OPEN_ALWAYS,   FILE_ATTRIBUTE_NORMAL,   NULL);

    //将keyblob长度保存到文件中

      WriteFile(   hexportkeyDestinationFile,   &dwKeyBlobLen,   sizeof(DWORD),   &dwCount,   NULL)

    //将keyblob内容写入

      WriteFile(    hexportkeyDestinationFile,    pbKeyBlob,    dwKeyBlobLen,    &dwCount,    NULL);

    free(pbKeyBlob);

    3. 根据key产生固定的blob产生, 用于对称加密

    #define ENCRYPT_ALGORITHM CALG_DES

    #define ENCRYPT_BLOCK_SIZE 8

    #define KEYSIZE 8

    typedef struct _stKeyBlob

    {  

      BLOBHEADER hdr;  

      DWORD cbKeySize;  

      BYTE rgbKeyData[KEYSIZE];

       _stKeyBlob()  

      {   

        hdr.bType = PLAINTEXTKEYBLOB;   

        hdr.bVersion = CUR_BLOB_VERSION;   

        hdr.reserved = 0;   

        hdr.aiKeyAlg = ENCRYPT_ALGORITHM;   

        cbKeySize = KEYSIZE;   

        memset(rgbKeyData, 0, KEYSIZE);  

      }

    } stKeyBlobType;    //结构参考MSDN - CryptImportKey

    XML_EnDecryption::XML_EnDecryption(BYTE pbKey[], DWORD dwKeyLen)

    {

       init();  m_pstKeyBlob = new stKeyBlobType();  

       memcpy(m_pstKeyBlob->rgbKeyData, pbKey, dwKeyLen > KEYSIZE ? KEYSIZE : dwKeyLen);

       if (!CryptImportKey(m_hProv, (BYTE*)m_pstKeyBlob, sizeof(stKeyBlobType), 0, 0, &m_hKey))  

      {

      }

    }

    三. 解密

    经过一和二,the session key(会话密钥)就创建好了,如果不是随机产生出来的,the session key(会话密钥)就被写到文件中或保存起来以便解密时用

    由password或key产生的hKey, 可由CrytImportKey导入

    CryptImportKey(m_hProv, (BYTE*)m_pstKeyBlob, sizeof(stKeyBlobType), 0, 0, &m_hKey)); //获取key句柄

     四. 代码

    1. 根据key产生固定的blob

    #ifndef _XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894FJ3F23OFJ230FJFJWEFJWWEFWE

    #define _XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894FJ3F23OFJ230FJFJWEFJWWEFWE

    #include <tchar.h>

    #include <stdio.h>

    #include <windows.h>

    #include <wincrypt.h>

    //#include <conio.h>

    //#pragma comment (lib, "advapi32")

    //#define KEYLENGTH  0x00800000 #define ENCRYPT_ALGORITHM CALG_DES #define ENCRYPT_BLOCK_SIZE 8

    #define KEYSIZE 8

    typedef struct _stKeyBlob

    {  

      BLOBHEADER hdr;  

      DWORD cbKeySize;  

      BYTE rgbKeyData[KEYSIZE];

       _stKeyBlob()  

      {   

        hdr.bType = PLAINTEXTKEYBLOB;   

        hdr.bVersion = CUR_BLOB_VERSION;   

        hdr.reserved = 0;   

        hdr.aiKeyAlg = ENCRYPT_ALGORITHM;   

        cbKeySize = KEYSIZE;   

        memset(rgbKeyData, 0, KEYSIZE);  

      }

    } stKeyBlobType;    //结构参考MSDN - CryptImportKey

    class XML_EnDecryption

    {

    public:  

      XML_EnDecryption(BYTE pbKey[] = NULL, DWORD dwKeyLen = 0);  

      virtual ~XML_EnDecryption();

       void GetLastCryptError(LPTSTR psz, int nErrorNumber);

       BOOL DES(__in const BYTE* pbData, __in DWORD cbDataLen, __out BYTE* pbBuf, __inout DWORD* pcbBufLen, __in BOOL bIsDecrypt = FALSE, __in BOOL isLast = TRUE);

       void GetBufferLen(__in const BYTE* pbData, __in DWORD cbDataLen, DWORD* pBufferLen);

       BOOL XmlEncDec(LPTSTR pszSourceFile, LPTSTR pszDestinationFile, BOOL isDecrypt = FALSE);

    private:   

      bool init();  

      bool InitialCSP();  

      bool IsCSPValided();  

      bool ReleaseCSP();

    private:  

      HCRYPTPROV m_hProv;  

      bool  m_bAcquireContextOK;

       HCRYPTKEY m_hKey;

       DWORD m_dwLastError;

       stKeyBlobType* m_pstKeyBlob;

    };

    #endif  //_PUBLIC_H_EFOFWEJOSDJFJ3933F3F894FJ3F23OFJ230FJFJWEFJWWEFWE

    2. 根据password, hash后得到hKey

    #ifndef _XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894PEPROGEPROGPOEPWEOVWOEVOWEV

    #define _XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894PEPROGEPROGPOEPWEOVWOEVOWEV

    #include <tchar.h>

    #include <stdio.h>

    #include <windows.h>

    #include <wincrypt.h>

    //#include <conio.h>

    //#pragma comment (lib, "advapi32")

    #define KEYLENGTH  0x00800000

    #define ENCRYPT_ALGORITHM CALG_RC4 

    #define ENCRYPT_BLOCK_SIZE 8

    class XML_EnDecryption

    {

    public:  

      XML_EnDecryption(LPTSTR m_pszPassword);  

      virtual ~XML_EnDecryption();

       void GetBufferLen(__in const BYTE* pbData, __in DWORD cbDataLen, DWORD* pBufferLen);

       BOOL DES(__in const BYTE* pbData, __in DWORD cbDataLen, __out BYTE* pbBuf, __inout DWORD* pcbBufLen, __in BOOL bIsDecrypt = FALSE, __in BOOL isLast = TRUE);

       BOOL XmlDes(LPTSTR pszSourceFile, LPTSTR pszDestinationFile, BOOL isDecrypt = FALSE);

       void GetLastCryptError(LPTSTR psz, int nErrorNumber);   private: // int getKey();  bool HashPassword();

    private:  

      bool init();  

      bool ReleaseCSP();  

      bool InitialCSP();  

      bool IsCSPValided();

    private:  

      HCRYPTPROV m_hProv;  

      bool  m_bAcquireContextOK;  

      HCRYPTHASH  m_hHash;  

      HCRYPTKEY m_hKey;  

      DWORD m_dwLastError;  

      LPTSTR m_pszPassword;

    };

    #endif  //_XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894PEPROGEPROGPOEPWEOVWOEVOWEV

    3. 随机产生hKey, 每次都不一样

    来自微软的例子。

    https://docs.microsoft.com/zh-cn/windows/desktop/SecCrypto/example-c-program-encrypting-a-file

    https://docs.microsoft.com/zh-cn/windows/desktop/SecCrypto/example-c-program-decrypting-a-file

  • 相关阅读:
    PHP识别二维码功能,php-zbarcode 安装
    《架构即未来》读后感(三)
    MVC设计模式案例分析
    SOA
    《架构即未来》读后感(二)
    基于网络拓扑及告警的故障根因定位系统实现及算法研究赛题需求分析
    《架构即未来》读后感(一)
    《大型网站技术架构》读后感(二)
    《一线架构师实践指南》读后感(三)
    《大型网站技术架构》读后感(三)
  • 原文地址:https://www.cnblogs.com/henryliublog/p/10287327.html
Copyright © 2020-2023  润新知