woaidongmao

文章均收录自他人博客,但不喜标题前加-[转贴],因其丑陋,见谅!~
随笔 - 1469, 文章 - 0, 评论 - 661, 引用 - 0
数据加载中……

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

同加密
相关参考资料:
学习CRYPTOAPI第一天(这个网站还有另外的两篇 二/三天)    http://www.wangchao.org/bbsdetail_66820.html
VC
知识库文档中心(Microsoft CryptoAPI加密技术 一/二) http://www.vckbase.com/document/listdoc.asp?mclsid=&sclsid=109&page=1
Crypto API
学习笔记一//三(另外两篇baidu下)  http://www.pediy.com/bbshtml/bbs8/pediy8-364.htm

posted on 2010-08-25 22:01 肥仔 阅读(744) 评论(0)  编辑 收藏 引用 所属分类: Windows开发


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理