VC++网络安全编程范例(2)

Wesley13
• 阅读 371

数字证书采用公钥体制,即利用一对互相匹配的密钥进行加密、解密。每个用户自己设定一把特定的仅为本人所知的私有密钥(私钥),用它进行解密和签名;同时设定一把公共密钥(公钥)并由本人公开,为一组用户所共享,用于加密和验证签名。当发送一份保密文件时,发送方使用接收方的公钥对数据加密,而接收方则使用 自己的私钥解密,这样信息就可以安全无误地到达目的地了。通过数字的手段保证加 密过程是一个不可逆过程,即只有用私有密钥才能解密。在公开密钥密码体制中,常用的一种是RSA体制。其数学原理是将一个大数分解成两个质数的乘积,加密和解密用的是两个不同的密钥。即使已知明文、密文和加密密钥(公开密钥),想要推导出解密密钥(私密密钥),在计算上是不可能的。按现在的计算机技术水平,要破解目前采用的1024位RSA密钥,需要上千年的计算时间。公开密钥技术解决了密钥发布的管理问题,商户可以公开其公开密钥,而保留其私有密钥。购物者可以用人人皆知的公开密钥对发送的信息进行加密,安全地传送给商户,然后由商户用自己的私有密钥 进行解密
用户也可以采用自己的私钥对信息加以处理,由于密钥仅为本人所有,这样就产生了别人无法生成的文件,也就形成了数字签名。采用数字签名,能够确认以下两点:
(1)保证信息是由签名者自己签名发送的,签名者不能否认或难以否认;
(2)保证信息自签发后到收到为止未曾作过任何修改,签发的文件是真实文件
数字签名具体做法是:
(1)将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证:只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性
(2)将该报文摘要值用发送者的私人密钥加密,然后连同原报文一起发送给接收者,而产生的报文即称数字签名
(3)接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较。如相等则说明报文确实来自所称的发送者。

代码如下,分析见注释

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif

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

#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define CERT_SUBJECT_NAME "TEST_SIGNER_NAME"
//函数申明
void HandleError(char *s);
HCRYPTPROV GetCryptProv();
void ByteToStr(
     DWORD cb, 
     void* pv, 
     LPSTR sz);

void main(void)
{
    //-------------------------------------------------------------------
    // 变量申明与初始化
    
     HCERTSTORE hCertStore = NULL; 
     HCRYPTPROV hCertProv = NULL; 
     HCRYPTKEY hKeySign = NULL; 
     PCCERT_CONTEXT pCertCtxSign = NULL; 

     BYTE *Encrypted = NULL; 
     DWORD EncryptedLen = 0; 
     BYTE *Decrypted= NULL; 
     DWORD DecryptedLen = 0; 
     CERT_NAME_BLOB certName = {0}; 
     certName.cbData = 0; 
     certName.pbData = NULL; 
     DWORD  cbNameEncoded;
     BYTE*  pbNameEncoded;

     //给CERT_NAME_BLOB结构certName赋值

    CERT_RDN_ATTR rgNameAttr[] = {
            "2.5.4.3",                             
            CERT_RDN_PRINTABLE_STRING,             
            strlen(CERT_SUBJECT_NAME),             
            (BYTE*)CERT_SUBJECT_NAME};             

    CERT_RDN rgRDN[] = {
             1,                 
             &rgNameAttr[0]};  


    CERT_NAME_INFO Name = {
               1,                 
               rgRDN};             
    
    //-------------------------------------------------------------------
    //    编码CERT_NAME_INFO结构,确定编码后的数据长度

    if(CryptEncodeObject(
        MY_ENCODING_TYPE,     // Encoding type
        X509_NAME,            // Structure type
        &Name,                // Address of CERT_NAME_INFO structure
        NULL,                 // pbEncoded
        &cbNameEncoded))      // pbEncoded size
    {
        printf("首次调用函数CryptEncodeObject成功. \n");
    }
    else
    {
        HandleError("首次调用函数CryptEncodeObject失败.\
          \n公私密钥对不能从密钥容器中导出. \n");
    }
    //-------------------------------------------------------------------
    //    分配内存

    if(!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded)))
        HandleError("pbNamencoded malloc operation failed.\n");

    //-------------------------------------------------------------------
    //  编码结构体

    if(CryptEncodeObject(
            MY_ENCODING_TYPE,    // Encoding type
            X509_NAME,           // Structure type
            &Name,               // Address of CERT_NAME_INFO structure
            pbNameEncoded,       // pbEncoded
            &cbNameEncoded))     // pbEncoded size
    {
        printf("此结构体已被编码. \n");
    }
    else
    {
        free(pbNameEncoded);
        HandleError("第二次调用函数CryptEncodeObject 失败.\n");
    }

    //给certName赋值
    certName.cbData = cbNameEncoded;
    certName.pbData = pbNameEncoded;
    

    //获取CSP句柄
    hCertProv = GetCryptProv() ;

     //产生签名密钥对   
     if (CryptGenKey(hCertProv, AT_SIGNATURE, CRYPT_EXPORTABLE, &hKeySign)) 
     { 
          printf("在服务证书容器中创建签名密钥成功!\n"); 
          
     } 
     else
     {
         HandleError("Protection::Initialise -不能在服务证书容器中创建签名密钥- \n"); 
          
     }    

     SYSTEMTIME cs; 
     GetSystemTime(&cs); 
     cs.wYear += 1; 


     //创建自签名证书
     if(pCertCtxSign = CertCreateSelfSignCertificate(
         hCertProv, //CSP句柄
         &certName, //证书客体名称数据结构指针
         0,         //标志位。默认行为,创建私钥信息,创建签名
         NULL,      //密钥信息结构
         NULL,      //签名算法,null表示默认算法SHA1RSA
         NULL,      //有效期起始时间 ,null表示取当前系统时间
         &cs,       //有效期终止时间,null表示起始时间加1年
         NULL))     //未设置扩展属性
     {
         printf("一个自签名证书已经被创建.\n");
     }     
     else
     { 
         HandleError("CertCreateSelfSignCertificate Error!");         
     } 
     free(certName.pbData); 


     //打开证书库
    if ((hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL , CERT_SYSTEM_STORE_CURRENT_USER , L"My"))) 
    { 
          printf("打开证书库成功.\n");
    } 
    else
    {
        HandleError("调用函数CertOpenStore 失败.\n");
    }

     //把证书加入证书库
     if(CertAddCertificateContextToStore(hCertStore, 
    pCertCtxSign,CERT_STORE_ADD_NEW,NULL)) 
     {           
          printf("将自签名证书加入到系统证书库成功.\n");
     }
     else
     {
          printf("将自签名证书添加到系统证书库中失败.\n");
     }

     //释放空间
     if (Encrypted) 
        free(Encrypted); 
     if (Decrypted) 
        free(Decrypted); 
     if (pCertCtxSign) 
        CertFreeCertificateContext(pCertCtxSign); 
     if (hKeySign) 
        CryptDestroyKey(hKeySign); 
     if (hCertStore) 
        CertCloseStore(hCertStore, 0); 
     if (hCertProv) 
        CryptReleaseContext(hCertProv, 0); 
    
} // End of main

//获取加密提供者句柄
HCRYPTPROV GetCryptProv()
{
    HCRYPTPROV hCryptProv;                      // 加密服务提供者句柄
    
    //获取加密提供者句柄
    if(CryptAcquireContext(
                &hCryptProv,         // 加密服务提供者句柄
                "ruanou",                // 密钥容器名
                MS_ENHANCED_PROV,    // 加密服务提供者    
                PROV_RSA_FULL,       // 加密服务提供者类型,可以提供加密和签名等功能
                0))                  // 标志
    {
        printf("加密服务提供者句柄获取成功!\n");
    }
    else
    {
    
        //重新建立一个新的密钥集
        if(!CryptAcquireContext(&hCryptProv, "ruanou", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET))
        {
           HandleError("重新建立一个新的密钥集出错!");
        }
 
    }
    return hCryptProv;
}

//--------------------------------------------------------------------
// ByteToStr:  转换BYTE类型数组为字符串
//参数:cb[in]  需要转换的BYTE数组的长度
//      pv[in]  需要转换的BYTE数组指针
//      sz[out] 字符串指针
void ByteToStr(
     DWORD cb, 
     void* pv, 
     LPSTR sz)
{
    BYTE* pb = (BYTE*) pv; 
    DWORD i;               
    int b;                 

    for (i = 0; i<cb; i++)
    {
        //pb的前4位转换为字符
        b = (*pb & 0xF0) >> 4;
        *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
        //pb的后4位转换为字符
        b = *pb & 0x0F;
        *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
        pb++;
    }
    *sz++ = 0;
}

//  HandleError:错误处理函数,打印错误信息,并退出程序
void HandleError(char *s)
{
    printf("程序执行发生错误!\n");
    printf("%s\n",s);
    printf("错误代码为: %x.\n",GetLastError());
    printf("程序终止执行!\n");
    exit(1);
}

 

$(document).ready(function(){dp.SyntaxHighlighter.HighlightAll('code');});
原文链接: http://blog.csdn.net/yincheng01/article/details/6845806

点赞
收藏
评论区
推荐文章
Stella981 Stella981
1年前
OpenSSL和Python实现RSA Key公钥加密私钥解密
基于非对称算法的RSAKey主要有两个用途,数字签名和验证(私钥签名,公钥验证),以及非对称加解密(公钥加密,私钥解密)。本文提供一个基于OpenSSL和Python进行非对称加解密的例子。1\.OpenSSL实现非对称加解密1.1生成私钥,并导出公钥生成2048bit的PEM格式的RSAKey:Key.pem$openssl
Wesley13 Wesley13
1年前
Java基础学习总结(16)——Java制作证书的工具keytool用法总结
一、keytool的概念  keytool是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务。在JDK 1.4以后的版本中都包含了这一工具,它的位置为%JAVA\_HOME%\\bin\\keytool.exe,如下图所示:
Wesley13 Wesley13
1年前
java实现非对称加密
对称加密:加密和解密的过程使用的是相同的密钥!这里写图片描述(https://oscimg.oschina.net/oscnet/42e81282a912d5abcf561e846c2b997914e.png)非对称加密与对称加密不同,非对称加密算法的加密和解密使用不同的两个密钥.这两个密钥就是我们经常听到的”公开密钥”(公钥
初识DevOps
基本概念和延伸的思考DevOps,是Development(开发)和Operations(运维)组成的复合词,一般译为“开发运维一体化”。看到这个概念,首先会产生几个问题:开发是什么,哪些环节是开发?运维是什么,哪些环节是运维?开发人员写好代码在本地调试,环境出问题了自己来调整,这是开发工作还是运维工作?系统故障后,运维人员发现是配置文件内容出错了就改成了正
SPDK QOS机制解析
本文关键词:intelspdkbdevqos序:intelspdk软件在存储领域应用广泛。因其可以高效管理linux系统的nvmessd盘,又支持vhostuser协议可以对接qemu虚拟机,在云计算领域通常被用来做本地盘云主机的存储管理软件。如此优秀的一款软件,有必要仔细分析其内部的实现机制,本篇文章主要介绍spdkqos机制。spdk
天翼云高可用虚拟IP(HAVIP)实践
(一)产品概述天翼云高可用虚拟IP(HighAvailabilityVirtualIPAddress,简称HAVIP)是一种可用独立创建和删除的私有网络IP地址资源。通过在VIPCIDR中申请一个私有网络IP地址,然后与高可用软件(如高可用软件Keepalived)配合使用,可用在VPC中搭建高可用的主备集群服务,提高VPC中服务的可用性。限制和说明
一个关于SDWAN单臂部署方案验证的实验
假设有这样一张网络,其中RTA和PCA表示某公司的A分支,通过中国电信CT路由器接入互联网ISP;RTB和PCB表示某公司的B分支,通过中国联通CU路由器接入互联网ISP。DNS(8.8.8.8)表示某互联网应用。为实现A分支私网192.168.2.0/24和B分支私网192.168.3.0/24的互通,现计划使用某厂商的SDWAN方案进打通两个内网,像下图
高性能API网关Kong介绍
本文关键词:高性能、API网关、Kong、微服务1.Introduction是随着微服务(Microservice)概念兴起的一种架构模式。原本一个庞大的单体应用(Allinone)业务系统被拆分成许多微服务(Microservice)系统进行独立的维护和部署,服务拆分带来的变化是API的规模成倍增长,API的管理难度也在日益增加,使用API网关发布和管
SPDK对接Ceph性能优化
关键词:SPDK、NVMeOF、Ceph、CPU负载均衡SPDK是intel公司主导开发的一套存储高性能开发套件,提供了一组工具和库,用于编写高性能、可扩展和用户态存储应用。它通过使用一些关键技术实现了高性能:1.将所有必需的驱动程序移到用户空间,以避免系统调用并且支持零拷贝访问2.IO的完成通过轮询硬件而不是依赖中断,以降低时延3.使用消息传递,以避免IO
3A网络 3A网络
5个月前
理解 virt、res、shr 之间的关系(linux 系统篇)
理解virt、res、shr之间的关系(linux系统篇)前言想必在linux上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?通常我们可以通过t
3A网络 3A网络
5个月前
开发一个不需要重写成 Hive QL 的大数据 SQL 引擎
开发一个不需要重写成HiveQL的大数据SQL引擎学习大数据技术的核心原理,掌握一些高效的思考和思维方式,构建自己的技术知识体系。明白了原理,有时甚至不需要学习,顺着原理就可以推导出各种实现细节。各种知识表象看杂乱无章,若只是学习