标 题: 【原创】Crypto API 学习笔记一
作 者: jdxyw
时 间: 2006-09-01,16:47
链 接: http://bbs.pediy.com/showthread.php?t=31357
Crypto API 学习笔记一
微软公司在NT4.0以上版本中提供了一套完整的Crypto API的函数,支持密钥交换,数据加密解密,数字签名,给程序员带来了很大方便,用户在对软件进行保护的时候可以直接利用Crypto API来完成这些工作,比如计算注册码,检查程序的完整性等。
  我们在用这些的API进行加密解密的时候,只需要知道如何去应用它们,而不必知道它们的底层实现。如果想知道它们更为详尽的资料,可以查找相关的资料。
  对Crypto API只是业余型的感兴趣,想通过写学习笔记,一是让自己记的更牢固些,二是想把自己的学的跟大家探讨一下。写的不好,大家多多原谅。我主要通过MSDN来学习,例子也是完全取自MSDN。
  首先,是Crypto API运行的环境。
首先需要Crypt32.lib,将它加到project->setting->link下面,当然你也可以在程序中用#pragma comment (lib, "crypt32.lib")加入。
  在程序开头,你要加入两个头文件 windows.h 和 Wincrypt.h,和一个#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
  在正式应用API进行一系列的加密解密的时候,需要有一些准备工作,下面是介绍一些在正式开始时所需要了解和做的工作。
生成密钥和密钥容器
  我们知道,在进行加密解密的时候,我们需要一个密钥进行加密,和一个密钥进行解密,加密密钥和解密密钥可能相同,也可能不同。于是在我们进行加密解密的开始时,我们首先需要有密钥。下面这个程序,完成了三个任务,并且介绍了一些函数的用法。
任务一:获取一个指定的密钥容器,如果这个容器不存在,创建一个。
任务二:如果容器中不存在一个签名密钥对,创建一个
任务三:如果容器中不存在一个交换密钥对,创建一个
  //-------------------------------------------------------------------
下面这段程序使用到了这几个函数

Code
CryptAcquireContext  
CryptDestroyKey  
CryptGenKey  
CryptGetUserKey  
// Copyright (c) Microsoft Corporation.  All rights reserved. 
#include <stdio.h> 
#include <tchar.h> 
#include <windows.h> 
#include <Wincrypt.h> 
//------------------------------------------------------------------- 
void MyHandleError(LPTSTR psz) 

    _ftprintf(stderr, TEXT("An error occurred in the program. \n")); 
    _ftprintf(stderr, TEXT("%s\n"), psz); 
    _ftprintf(stderr, TEXT("Error number %x.\n"), GetLastError()); 
    _ftprintf(stderr, TEXT("Program terminating. \n")); 
    exit(1); 
} // End of MyHandleError. 

上面这个函数是一个异常处理函数,当出现错误的时候,出现提示,并推出程序。以后的程序中都有这个函数,以后就会将这个函数的实现省去。现在这个函数的实现在后面。

Code
void main(void)  
{  
        HCRYPTPROV hCryptProv;   //定义一个CSP模块的句柄。“CSP模块,请查看《加密解密二》222页,那里有简单的说明,这里就不说了。      
        LPCTSTR pszContainerName = TEXT("My Sample Key Container");//用一个TEXT宏定义一个容器的名字, 
    if(CryptAcquireContext(        //这个函数是获取有某个容器的CSP模块的指针,成功返回TRUE。 
        &hCryptProv,            //指向一个CSP模块句柄指针,里面用指定的容器 
        pszContainerName,       //指定容器的名称 
     NULL,                //这个参数这里用的是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块 
        PROV_RSA_FULL,      //确定密钥的类型 
        0))                    //常设为0,还有些其他的类型,请看MSDN 
    { 
        _tprintf( 
            TEXT("A crypto context with the %s key container ") 
            TEXT("has been acquired.\n"),  
            pszContainerName); 
    } 
    else 
    {  
        //不成功的处理段 
        if(GetLastError() == NTE_BAD_KEYSET)     // NTE_BAD_KEYSET意味着密钥 
//容器不存在,下面就去创建一个 
//新的密钥容器 
        { 
            if(CryptAcquireContext( 
                &hCryptProv,  
                pszContainerName,  
                NULL,  
                PROV_RSA_FULL,  
                CRYPT_NEWKEYSET))           // CRYPT_NEWKEYSET意味着当指定容器不存在的时候,去创建一个容器。 
            { 
                _tprintf(TEXT("A new key container has been ") 
                    TEXT("created.\n")); 
            } 
            else 
            { 
                MyHandleError(TEXT("Could not create a new key ") 
                    TEXT("container.\n")); 
            } 
        } 
        else 
        { 
            MyHandleError(TEXT("CryptAcquireContext failed.\n")); 
        } 
    } 
    HCRYPTKEY hKey;                            //创建一个密钥句柄 
    if(CryptGetUserKey(                           // CryptGetUserKey是获取一个密钥//句柄的函数,成功返回TRUE 
        hCryptProv,                               //指定容器的CSP模块句柄 
        AT_SIGNATURE,                         //指定私钥的类型 
        &hKey))                                //原来接收获取的密钥句柄 
    { 
        _tprintf(TEXT("A signature key is available.\n")); 
    } 
    else 
    { 
        _tprintf(TEXT("No signature key is available.\n")); 
        if(GetLastError() == NTE_NO_KEY)              // NTE_NO_KEY意味着密钥不存在,下面就生成一个密钥 
        { 
            _tprintf(TEXT("The signature key does not exist.\n")); 
            _tprintf(TEXT("Create a signature key pair.\n"));  
            if(CryptGenKey(                          // CryptGenKey生成一个密钥 
                hCryptProv,                          //指定CSP模块的句柄 
                AT_SIGNATURE,                    //对于公钥密码系统,生成一个私钥和一个公钥,这个参数指定了这个密钥是公钥,于是生成了一个密码对。如果不是公钥系统,则指定了密码算法,具体看MSDN。 
                0,                                 //指定了生成密钥的类型,这个参数的说明挺多的,想获取更为详尽的资料请看MSDN。 
                &hKey))  
            { 
                _tprintf(TEXT("Created a signature key pair.\n")); 
            } 
            else 
            { 
                MyHandleError(TEXT("Error occurred creating a ") 
                    TEXT("signature key.\n"));  
            } 
        } 
        else 
        { 
            MyHandleError(TEXT("An error other than NTE_NO_KEY ") 
                TEXT("getting a signature key.\n")); 
        } 
    } // End if. 
    _tprintf(TEXT("A signature key pair existed, or one was ") 
        TEXT("created.\n\n")); 
        if(hKey)                              //将密钥句柄销毁 
    { 
        if(!(CryptDestroyKey(hKey))) 
        { 
            MyHandleError(TEXT("Error during CryptDestroyKey.")); 
        } 
        hKey = NULL; 
    }  
    下面这部分和上面是类似的,只不过密钥类型不相同而已。 
    if(CryptGetUserKey( 
        hCryptProv, 
        AT_KEYEXCHANGE, 
        &hKey))  
    { 
        _tprintf(TEXT("An exchange key exists.\n")); 
    } 
    else 
    { 
        _tprintf(TEXT("No exchange key is available.\n")); 
        // Check to determine whether an exchange key  
        // needs to be created. 
        if(GetLastError() == NTE_NO_KEY)  
        {  
            // Create a key exchange key pair. 
            _tprintf(TEXT("The exchange key does not exist.\n")); 
            _tprintf(TEXT("Attempting to create an exchange key ") 
                TEXT("pair.\n")); 
            if(CryptGenKey( 
                hCryptProv, 
                AT_KEYEXCHANGE, 
                0, 
                &hKey))  
            { 
                _tprintf(TEXT("Exchange key pair created.\n")); 
            } 
            else 
            { 
                MyHandleError(TEXT("Error occurred attempting to ") 
                    TEXT("create an exchange key.\n")); 
            } 
        } 
        else 
        { 
            MyHandleError(TEXT("An error other than NTE_NO_KEY ") 
                TEXT("occurred.\n")); 
        } 
    } 
    // Destroy the exchange key. 
    if(hKey) 
    { 
        if(!(CryptDestroyKey(hKey))) 
        { 
            MyHandleError(TEXT("Error during CryptDestroyKey.")); 
        } 
        hKey = NULL; 
    } 
    // Release the CSP. 
    if(hCryptProv) 
    { 
        if(!(CryptReleaseContext(hCryptProv, 0))) 
        { 
            MyHandleError(TEXT("Error during CryptReleaseContext.")); 
        } 
    }  
    _tprintf(TEXT("Everything is okay. A signature key ")); 
    _tprintf(TEXT("pair and an exchange key exist in ")); 
    _tprintf(TEXT("the %s key container.\n"), pszContainerName);   
} // End main.

下面我们再通过一个程序,用几种不同的方法,将CryptAcquireContext和其他的API函数联系起来,看看它们是如何与一个CSP和容器工作的。这个程序演示了以下内容和几个函数。
一.  用CryptAcquireContext获取一个缺省容器的缺省CSP的句柄。如果缺省容器不存在,用CryptAcquireContext创建一个。
二.  用CryptGetProvParam获取CSP和容器的信息。
三.  用CryptContextAddRef增加CSP的引用计数器的数值。
四.  用CryptAcquireContext创建一个指定的容器
五.  用CryptAcquireContext删除一个容器
六.  用一个新创建的容器获取一个CSP的句柄。

Code
#include <stdio.h> 
#include <tchar.h> 
#include <windows.h> 
#include <Wincrypt.h> 
异常处理函数省略 
void main(void) 

    HCRYPTPROV hCryptProv;                            //定义CSP句柄 
    if(CryptAcquireContext( 
        &hCryptProv,  
        NULL,                                           //缺省容器 
        NULL,                                           //缺省CSP 
        PROV_RSA_FULL,  
        0))  
    { 
        _tprintf(TEXT("CryptAcquireContext succeeded.\n")); 
    } 
    else 
    { 
        if (GetLastError() == NTE_BAD_KEYSET)               //同样,如果当不存在这样的容器的时候,创建一个 
        { 
            if(CryptAcquireContext( 
                &hCryptProv,  
                NULL,  
                NULL,  
                PROV_RSA_FULL,  
                CRYPT_NEWKEYSET))                      
            { 
                _tprintf(TEXT("CryptAcquireContext succeeded.\n")); 
            } 
            else 
            { 
                MyHandleError(TEXT("Could not create the default ") 
                    TEXT("key container.\n")); 
            } 
        } 
        else 
        { 
            MyHandleError(TEXT("A general error running ") 
                TEXT("CryptAcquireContext.")); 
        } 
    } 
    CHAR pszName[1000]; 
    DWORD cbName; 
    cbName = 1000; 
    if(CryptGetProvParam( 
        hCryptProv,                                     //CSP模块句柄 
        PP_NAME,                                     //指定获取哪些信息,这里是指定获取CSP名字的信息 
        (BYTE*)pszName,                               //缓冲区接受信息返回值 
        &cbName,  
        0)) 
    { 
        _tprintf(TEXT("CryptGetProvParam succeeded.\n")); 
        printf("Provider name: %s\n", pszName); 
    } 
    else 
    { 
        MyHandleError(TEXT("Error reading CSP name.\n")); 
    } 
    //--------------------------------------------------------------- 
    // Read the name of the key container. 
    cbName = 1000; 
    if(CryptGetProvParam( 
        hCryptProv,  
        PP_CONTAINER,                                       //获取容器名字 
        (BYTE*)pszName,  
        &cbName,  
        0)) 
    { 
        _tprintf(TEXT("CryptGetProvParam succeeded.\n")); 
        printf("Key Container name: %s\n", pszName); 
    } 
    else 
    { 
        MyHandleError(TEXT("Error reading key container name.\n")); 
    } 
    if(CryptContextAddRef(                       // CryptContextAddRef是向一个CSP的引用计数器增加一个值的函数 
        hCryptProv,  
        NULL,                                //保留值,必须为NULL 
        0))                     //保留值,必须为0 
    { 
        _tprintf(TEXT("CryptcontextAddRef succeeded.\n")); 
    } 
    else 
    { 
        MyHandleError(TEXT("Error during CryptContextAddRef!\n")); 
    } 
    //--------------------------------------------------------------- 
    //  The reference count on hCryptProv is now greater than one.  
    //  The first call to CryptReleaseContext will not release the  
    //  provider handle.  
    //--------------------------------------------------------------- 
    //  Release the context once. 
    if (CryptReleaseContext(hCryptProv, 0))                // CryptReleaseContext是用来释放CSP句柄的,当这个函数调用一次的时候,CSP里面的引用计数就减少一,当引用计数减少的0的时候。CSP将不能再被这个程序中的任何函数调用了。 
    { 
        _tprintf(TEXT("The first call to CryptReleaseContext ") 
            TEXT("succeeded.\n")); 
    } 
    else 
    { 
        MyHandleError(TEXT("Error during ") 
            TEXT("CryptReleaseContext #1!\n")); 
    } 
    if (CryptReleaseContext(hCryptProv, 0))                //再次释放CSP模块 
    { 
        _tprintf(TEXT("The second call to CryptReleaseContext ") 
            TEXT("succeeded.\n")); 
    } 
    else 
    { 
        MyHandleError(TEXT("Error during ") 
            TEXT("CryptReleaseContext #2!\n")); 
    } 
   下面是从PROV_RSA_FULL的CSP模块中创建一个自己的容器 
    LPCTSTR pszContainerName = TEXT("My Sample Key Container"); 
    hCryptProv = NULL; 
    if(CryptAcquireContext( 
        &hCryptProv,  
        pszContainerName, 
        NULL,  
        PROV_RSA_FULL,  
        CRYPT_NEWKEYSET))  
    { 
        _tprintf(TEXT("CryptAcquireContext succeeded. \n")); 
        _tprintf(TEXT("New key set created. \n"));  
        //----------------------------------------------------------- 
        // Release the provider handle and the key container. 
        if(hCryptProv) 
        { 
            if(CryptReleaseContext(hCryptProv, 0))  
            { 
                hCryptProv = NULL; 
                _tprintf(TEXT("CryptReleaseContext succeeded. \n")); 
            } 
            else 
            { 
                MyHandleError(TEXT("Error during ") 
                    TEXT("CryptReleaseContext!\n")); 
            } 
        } 
    } 
    else 
    { 
        if(GetLastError() == NTE_EXISTS) 
        { 
            _tprintf(TEXT("The named key container could not be ") 
                TEXT("created because it already exists.\n")); 
        } 
        else 
        { 
            MyHandleError(TEXT("Error during CryptAcquireContext ") 
                TEXT("for a new key container.")); 
        } 
    } 
    if(CryptAcquireContext( 
        &hCryptProv,  
        pszContainerName,  
        NULL,  
        PROV_RSA_FULL, 
        0))  
    { 
        _tprintf(TEXT("Acquired the key set just created. \n")); 
    } 
    else 
    { 
        MyHandleError(TEXT("Error during CryptAcquireContext!\n")); 
    } 
    //--------------------------------------------------------------- 
    // Perform cryptographic operations. 
    //--------------------------------------------------------------- 
       if(CryptReleaseContext( 
        hCryptProv,  
        0))  
    { 
        _tprintf(TEXT("CryptReleaseContext succeeded. \n")); 
    } 
    else 
    { 
        MyHandleError(TEXT("Error during CryptReleaseContext!\n")); 
    } 
    if(CryptAcquireContext( 
        &hCryptProv,  
        pszContainerName,  
        NULL,  
        PROV_RSA_FULL, 
        CRYPT_DELETEKEYSET))                    //CRYPT_DELETEKEYSET意味着CryptAcquireContex删除一个指定的容器 
    { 
        _tprintf(TEXT("Deleted the key container just created. \n")); 
    } 
    else 
    { 
        MyHandleError(TEXT("Error during CryptAcquireContext!\n")); 
    } 

转载于:https://www.cnblogs.com/wanghao111/archive/2009/05/25/1489031.html

Crypto API 学习笔记一相关推荐

  1. Crypto++入门学习笔记(DES、AES、RSA、SHA-256)

    Crypto++入门学习笔记(DES.AES.RSA.SHA-256) 背景(只是个人感想,技术上不对后面的内容构成知识性障碍,可以skip): 最近,基于某些原因和需要,笔者需要去了解一下Crypt ...

  2. Crypto++入门学习笔记(DES、AES、RSA、SHA-256)(转)

    Crypto++入门学习笔记(DES.AES.RSA.SHA-256)(转) 2012-11-19 11:28:00|  分类: c++|举报|字号 订阅 背景(只是个人感想,技术上不对后面的内容构成 ...

  3. SiKi学院 Unity中常用api学习笔记(001-014)

    Api 应用程序编程接口 前言 笔记是看siki学院中<Unity中常用api>的学习笔记 课程地址:  http://www.sikiedu.com/my/course/59 强烈推荐大 ...

  4. SiKi学院 Unity中常用api学习笔记(015-019)

    Api 应用程序编程接口 前言 笔记是看siki学院中<Unity中常用api>的学习笔记 课程地址:  http://www.sikiedu.com/my/course/59 强烈推荐大 ...

  5. libvirt API学习笔记

    为环境CentOS5.5 从官方网站上下载了文档   libvirt 0.7.5  Application  Development Guide 由于CentOS自带libvirt版本为0.6.3的, ...

  6. linux crypto API 学习

    linux 内核里实现了crypto模块,其用法介绍的很少: 参考:linux-3.18.21/Documentation/crypto/api-intro.txt Here's an example ...

  7. Lumerical Python API学习笔记(二)

    笔记参考 LINK 1.会话管理 fdtd = lumapi.FDTD 打开新的FDTD Solutions界面 可以一次创建同一产品和不同产品的多个会话,例如: mode1 = lumapi.MOD ...

  8. android dropbox API 学习笔记。

    由于一个android 平台上面的应用程序要做dropbox的集成,所以研究了下dropbox官网的一些文档,记下此笔记方便日后查看. 1,打开dropbox 官网 https://www.dropb ...

  9. Crypto++入门学习笔记(DES、AES、RSA、SHA-256)(加解密)

    转自http://www.cppblog.com/ArthasLee/archive/2010/12/01/135186.html 最近,基于某些原因和需要,笔者需要去了解一下Crypto++库,然后 ...

最新文章

  1. 《LeetCode力扣练习》第4题 C语言版 (做出来就行,别问我效率。。。。)
  2. HDU-1541 Stars 树状数组
  3. 【反欺诈】互金欺诈与反欺诈
  4. 产品分析:岛APP,青年文化拍了拍社交赛道
  5. 小心了!这18位数字一泄漏,支付宝账户就可能会被他人盗刷!
  6. 学web前端好找工作吗?想给初学者们几点建议
  7. 【386天】跃迁之路——程序员高效学习方法论探索系列(实验阶段143-2018.02.26)...
  8. logback日志pattern_Springboot整合log4j2日志全解
  9. .ashx文件与.ashx.cs
  10. Easy Data Transform如何在Excel中删除重复的行?
  11. Mscomm32.ocx注册
  12. 三菱PLC控制器FX3GA USB驱动 程序下载
  13. 7月22日 暑假的一些心得记录
  14. Android电子白板
  15. 智能眼镜现在是什么水平?
  16. [PHP] Larval 主从读写分离配置
  17. 利用三星S3C6410源码实现同时压缩视频和图片
  18. 概率统计Python计算:条件概率和概率乘法公式
  19. CentOS 8.1安装MySQL 8.0详解
  20. 2007年IBM合作伙伴峰会及新年策略发布

热门文章

  1. RTX3090 Super曝光:完整GA102核心加持、性能提升5%
  2. 孙悟空为什么被封为斗战胜佛
  3. Oracle的AWR报告分析
  4. MySQL的GTID复制与传统复制的相互切换
  5. ReactNative开发笔记(持续更新...)
  6. 程序员的自我反省-十条原则
  7. 2017-2018-2 20179215 《密码与安全新技术》第5周作业
  8. angularjs 添加拦截器
  9. linux下能ping ip不能ping域名详解
  10. 在sitecopy中设置不支持passive模式的ftp服务器