zoukankan      html  css  js  c++  java
  • Crypto 加密的基本流程

    前言:
        Crypto是微软的加密API,如果看懂了,使用起来是很简单的一件事,不过就是最开始没有看懂,被虐了两天。然后又被其他问题给虐了两天。最后做出来的东西也不是让自己十分满意。不过还好,最后的结果还不算太糟。
        本想对代码进行一次整理,写一个demo代码,不过现在有些慵懒了,还是随便贴些笔记好了。

    PS:   
        发现Delphi盒子要卖了。这似乎也验证了一句话,有商业价值的东西才会有持续的生命力。

    Crypto 加密的基本流程

    1. 创建/获取一个密码容器CSP
    2. 创建/获取/导入一个密钥
    3. 使用密钥进行加密/解密

    加密具体流程:

    1. 创建/获取一个密码容器CSP。这一部分基本上所有程序都一样,直接复制过来到程序里就可以了。

    //以下获得一个CSP句柄
        if(CryptAcquireContext(
            &hProv,   //out 密码容器
            NULL,                //NULL表示使用默认密钥容器,默认密钥容器名为用户登陆名。
            NULL,
            PROV_RSA_FULL, //in 使用RSA密钥
            0))
        {
            printf("A cryptographic provider has been acquired. \n");
        }
        else//密钥容器不存在
        {
            if(CryptAcquireContext(
                &hProv,
                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");
            }      
        }

    1. 创建/获取一个密钥。这里有些程序里会创建一个sessionKey会话密钥用于对称加密,这里创建的是非对称加密的密钥。

        //--------------------------------------------------------------------
        // 从密钥容器中取交换密钥
        if(CryptGetUserKey(  
            hProv,    //CSP句柄,也就是在一里面创建的,密码容器。
            AT_KEYEXCHANGE,    //密钥的类型,这里指名的是交换密钥。还有一个AT_SIGNATURE,这个是数字签名用的。
            &hKey)) //out 获取到的密钥
        {
            printf("The signature key has been acquired. \n");
        }
        else
        {
            if(GetLastError() == NTE_NO_KEY) //密钥容器里不存在key pair创建之
            {
                if(CryptGenKey(
                    hProv,            //in CSP句柄
                    AT_SIGNATURE,    //in 创建的密钥对类型为signature key pair
                    0,                //key类型,这里用默认值
                    &hKey))         //out 创建成功返回新创建的密钥对的句柄
                {
                    printf("Created a signature key pair.\n");
                }
                else
                {
                    MyHandleError("Error occurred creating a signature key.\n");
                }
            }
            else
            {
                MyHandleError("Error during CryptGetUserKey for signkey.");
            }
        }

    1. 使用密钥进行加密

            //--------------------------------------------------------------------
            // 加密数据
            if(!CryptEncrypt(
                hKey,            //in 密钥
                0,                //如果数据同时进行散列和加密,这里传入一个散列对象
                TRUE,    //如果是最后一个被加密的块,输入TRUE.如果不是输入FALSE.
                                //这里通过判断是否到文件尾来决定是否为最后一块。
                0,                //保留
                pbBuffer,        // in/out输入被加密数据,输出加密后的数据。将pbBuffer分配大一些,防止长度不够。
                &dwCount,        // in/out输入被加密数据实际长度,输出加密后数据长度。这个需要根据pbBuffer的实际输入长度进行计算(strlen?),不然不能正常运行。
                dwBufferLen))    //in pbBuffer的大小。这里填大点,
            {
                HandleError("Error during CryptEncrypt. \n");
            }
    到这里加密就已经做完了,加密后的数据保存在pbBuffer中。

    1. 导出公/私钥

    私钥在加密的时候需要,以后使用的时候不再生成,直接导入。(备注:如果需要导出私钥需要在创建密钥时候设置参数,具体见MSDN)
    解密的时候需要用到公钥,需要将公钥分发给解密用户。
        //--------------------------------------------------------------------
        // 因为接收消息者要验证数字签名,所以要导出公钥给接收者。
        if(CryptExportKey(  
            hKey,  //in 密钥句柄
            NULL,   
            PUBLICKEYBLOB,// out 公钥输出数据。在导出后,需要将公钥的数据保存成文件等,以便分发。
            0,   
            NULL,
            &dwBlobLen)) //out 得到公钥的大小
        {
            printf("Size of the BLOB for the public key determined. \n");
        }
        else
        {
            MyHandleError("Error computing BLOB length.");
        }

    1. 销毁容器和Key

    在完成加密后,需要对key和容器进行销毁,相关函数如下。
        if(hKey)
    CryptDestroyKey(hKey);
        if(hCryptProv)
    CryptReleaseContext(hCryptProv, 0);
    解密的具体流程:

    1. 同加密流程
    2. 导入解密用的公钥。

        HCRYPTKEY hPubKey;
        if(CryptImportKey(
            hProv,//in CSP密码容器
            pbKeyBlob,//in 需要导入的公钥数据(在加密的时候导出的公钥,加密中的4)
            dwBlobLen,//in 公钥数据的长度
            0,
            0,
            &hPubKey))//out 公钥导入得到的公钥句柄
        {
            printf("The key has been imported.\n");
        }
        else
        {
            MyHandleError("Public key import failed.");
        }

    1. 解密

    解密的参数和加密的参数基本相同。
            //--------------------------------------------------------------------
            // Decrypt data.
            if(!CryptDecrypt(
                hPubKey, //in 解密用的公钥,也就是在2中导入的公钥
                0,
               TRUE,    //如果是最后一个被加密的块,输入TRUE.如果不是输入FALSE.
                0,
                pbBuffer,        // in/out输入被解密数据,输出加密后的数据。将pbBuffer分配大一些,防止长度不够。
                &dwCount))    // in/out输入被解密数据实际长度,输出加密后数据长度。这个需要根据pbBuffer的实际输入长度进行计算(strlen?),不然不能正常运行。
            {
                HandleError("Error during CryptDecrypt!");
            }

    1. 销毁容器和Key
  • 相关阅读:
    linux终端发送邮件
    ubuntu交换Caps 和 ESC
    pycharm快捷键
    python catch socket timeout
    pgsql restart
    python re.sub
    文件写入与缓存
    HTTP协议再分析
    leetcode-45
    Java的锁
  • 原文地址:https://www.cnblogs.com/lzjsky/p/1833716.html
Copyright © 2011-2022 走看看