数字信封是将对称密钥通过非对称加密(即:有公钥和私钥两个)的结果分发对称密钥的方法。

PKCS#7中将数字信封作为术语进行定义,而在正文中对进行了如下解释:数字信封包含被加密的内容和被加密的用于加密该内容的密钥。虽然经常使用接收方的公钥来加密“加密密钥”,但这并不是必须的,也可以使用发送方和接收方预共享的对称密钥来加密。当接收方收到数字信封时,先用私钥或预共享密钥解密,得到“加密密钥”,再用该密钥解密密文,获得原文。数字信封技术使用两层加密体系。

数字信封是一种综合利用了对称加密技术和非对称加密技术两者的优点进行信息安全传输的一种技术。数字信封既发挥了对称加密算法速度快、安全性好的优点,又发挥了非对称加密算法密钥管理方便的优点。

数字信封是公钥密码体制在实际中的一个应用,是用加密技术来保证只有规定的特定收信人才能阅读通信的内容。

在数字信封中,信息发送方采用对称密钥来加密信息内容,然后将此对称密钥用接收方的公开密钥来加密(这部分称数字信封)之后,将它和加密后的信息一起发送给接收方,接收方先用相应的私有密钥打开数字信封,得到对称密钥,然后使用对称密钥解开加密信息。这种技术的安全性相当高。数字信封主要包括数字信封打包和数字信封拆解,数字信封打包是使用对方的公钥将加密密钥进行加密的过程,只有对方的私钥才能将加密后的数据(通信密钥)还原;数字信封拆解是使用私钥将加密过的数据解密的过程。
数字信封的功能类似于普通信封,普通信封在法律的约束下保证只有收信人才能阅读信的内容;数字信封则采用密码技术保证了只有规定的接收人才能阅读信息的内容。数字信封中采用了对称密码体制和公钥密码体制。信息发送者首先利用随机产生的对称密码加密信息,再利用接收方的公钥加密对称密码,被公钥加密后的对称密码被称之为数字信封。在传递信息时,信息接收方若要解密信息,必须先用自己的私钥解密数字信封,得到对称密码,才能利用对称密码解密所得到的信息。这样就保证了数据传输的真实性和完整性。

在一些重要的电子商务交易中密钥必须经常更换,为了解决每次更换密钥的问题,结合对称加密技术和公开密钥技术的优点,它克服了秘密密钥加密中秘密密钥分发困难和公开密钥加密中加密时间长的问题,使用两个层次的加密来获得公开密钥技术的灵活性和秘密密钥技术高效性。信息发送方使用密码对信息进行加密,从而保证只有规定的收信人才能阅读信的内容。采用数字信封技术后,即使加密文件被他人非法截获,因为截获者无法得到发送方的通信密钥,故不可能对文件进行解密。

我们来用VC++实现数字信封打包与拆解,请见代码实现与注释讲解

#include <stdio.h>
#include <windows.h>#include <wincrypt.h>#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void HandleError(char *s);PCCERT_CONTEXT GetRecipientCert(HCERTSTORE hCertStore);void ByteToStr(DWORD cb, void* pv, LPSTR sz);BOOL DecryptMessage( BYTE *pbEncryptedBlob, DWORD cbEncryptedBlob,HCRYPTPROV hCryptProv,HCERTSTORE hStoreHandle);HCRYPTPROV GetCryptProv();void main()
{//--------------------------------------------------------------------// 变量申明与初始化BYTE* pbContent = (BYTE*) "Security is our business.";// 待加密消息                                             DWORD cbContent = strlen((char *)pbContent)+1;        // 消息长度                                             HCRYPTPROV hCryptProv;                                // CSP句柄HCERTSTORE hStoreHandle;                              //证书库句柄PCCERT_CONTEXT pRecipientCert;                        //接收证书PCCERT_CONTEXT RecipientCertArray[1];                 //接收证书列表DWORD EncryptAlgSize;CRYPT_ALGORITHM_IDENTIFIER EncryptAlgorithm;CRYPT_ENCRYPT_MESSAGE_PARA EncryptParams;DWORD EncryptParamsSize;BYTE*    pbEncryptedBlob;DWORD    cbEncryptedBlob;printf("即将从消息 %s 开始.\n",pbContent);printf("这个消息的长度是 %d 字节. \n", cbContent);//获取加密服务者句柄hCryptProv = GetCryptProv();//--------------------------------------------------------------------// 打开系统证书库.if(hStoreHandle = CertOpenSystemStore(hCryptProv, "MY")){printf(" MY 证书库已经打开. \n");}else{HandleError( "获取证书库句柄出错.");}//--------------------------------------------------------------------// 调用函数GetRecipientCert获取接收者证书if(pRecipientCert = GetRecipientCert(hStoreHandle)){printf("接收者的证书已经获取. \n");}else{printf("No certificate with a CERT_KEY_CONTEXT_PROP_ID \n");printf("property and an AT_KEYEXCHANGE private key available. \n");printf("While the message could be encrypted, in this case, \n");printf("it could not be decrypted in this program. \n");printf("For more information, see the documentation for \n");printf("CrypteEncryptMessage and CryptDecryptMessage.\n\n");HandleError( "No Certificate with AT_KEYEXCHANGE key in store.");}//--------------------------------------------------------------------// 创建接收证书列表.这里仅包含一个接收者证书RecipientCertArray[0] = pRecipientCert;//--------------------------------------------------------------------// 初始化算法结构.EncryptAlgSize = sizeof(EncryptAlgorithm);//--------------------------------------------------------------------// 初始化算法结构为0.memset(&EncryptAlgorithm, 0, EncryptAlgSize);//--------------------------------------------------------------------// 设置算法结构的必要的成员变量.EncryptAlgorithm.pszObjId = szOID_RSA_RC4;  //--------------------------------------------------------------------// 初始化CRYPT_ENCRYPT_MESSAGE_PARA 结构. EncryptParamsSize = sizeof(EncryptParams);memset(&EncryptParams, 0, EncryptParamsSize);EncryptParams.cbSize =  EncryptParamsSize;EncryptParams.dwMsgEncodingType = MY_ENCODING_TYPE;EncryptParams.hCryptProv = hCryptProv;EncryptParams.ContentEncryptionAlgorithm = EncryptAlgorithm;//--------------------------------------------------------------------// 调用 CryptEncryptMessage加密消息.//获取加密后数据长度if(CryptEncryptMessage(&EncryptParams,1,RecipientCertArray,//收件证书列表pbContent,cbContent,NULL,&cbEncryptedBlob)){printf("加密消息是 %d 字节. \n",cbEncryptedBlob);}else{HandleError( "获取加密后数据块长度失败.");}//--------------------------------------------------------------------// 分配内存空间.if(pbEncryptedBlob = (BYTE*)malloc(cbEncryptedBlob)){printf("已经为加密数据块分配了内存空间. \n");}else{HandleError("加密时内存分配出错.");}//--------------------------------------------------------------------// 加密消息if(CryptEncryptMessage(&EncryptParams,1,RecipientCertArray,pbContent,cbContent,pbEncryptedBlob,&cbEncryptedBlob)){printf( "加密成功. \n");}else{HandleError("加密失败.");}//--------------------------------------------------------------------// 调用DecryptMessage解密消息if(DecryptMessage( pbEncryptedBlob, cbEncryptedBlob,hCryptProv,hStoreHandle)){printf("解密成功. \n");}else{printf("解密失败. \n");}//--------------------------------------------------------------------//释放内存空间.CertFreeCertificateContext(pRecipientCert);if(CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG)){printf("MY证书库顺利关闭. \n");}else{printf("加密后证书库关闭 -- \n""但是不是所有证书或证书撤消列表都被释放. \n");}if(hCryptProv){CryptReleaseContext(hCryptProv,0);printf("CSP句柄已经释放. \n");}else{printf("CSP句柄为空. \n");}
} // End of main//--------------------------------------------------------------------
//  功能:解密用函数CryptDecryptMessage加密的消息.
//  参数
//        pbEncryptedBlob:待解密的消息
//        cbEncryptedBlob:待解密消息长度
//        hCryptProv:     CSP句柄
//        hStoreHandle:   已打开的证书库句柄
BOOL DecryptMessage( BYTE *pbEncryptedBlob, DWORD cbEncryptedBlob,HCRYPTPROV hCryptProv,HCERTSTORE hStoreHandle)
{//--------------------------------------------------------------------//申明与初始化变量DWORD cbDecryptedMessage;char* EncryptedString = (char*)malloc(sizeof(char) *(cbEncryptedBlob * 2 +1));HCERTSTORE CertStoreArray[] = {hStoreHandle};CRYPT_DECRYPT_MESSAGE_PARA  DecryptParams;DWORD  DecryptParamsSize = sizeof(DecryptParams);BYTE*  pbDecryptedMessage;LPSTR  DecryptedString;BOOL   fReturn = TRUE;ByteToStr(cbEncryptedBlob, pbEncryptedBlob, EncryptedString);//--------------------------------------------------------------------//打印转化后的密文.printf("加密后的字符串是: \n%s\n",EncryptedString);//--------------------------------------------------------------------//   初始化CRYPT_DECRYPT_MESSAGE_PARA结构.memset(&DecryptParams, 0, DecryptParamsSize);DecryptParams.cbSize = DecryptParamsSize;DecryptParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;DecryptParams.cCertStore = 1;DecryptParams.rghCertStore = CertStoreArray;//证书库列表//--------------------------------------------------------------------//  解密消息数据.//  先调用CryptDecryptMessage确定解密后数据长度.if(CryptDecryptMessage(&DecryptParams,pbEncryptedBlob,cbEncryptedBlob,NULL,&cbDecryptedMessage,NULL)){printf("解密后数据的长度是: %d.\n",cbDecryptedMessage);}else{HandleError( "获取解密后消息长度出错");}//--------------------------------------------------------------------// 分配空间if(pbDecryptedMessage = (BYTE*)malloc(cbDecryptedMessage)){printf("已经为解密消息分配了内存空间. \n");}else{HandleError("解密时内存分配出错");}//--------------------------------------------------------------------// 调用 CryptDecryptMessage 解密数据.if(CryptDecryptMessage(&DecryptParams,pbEncryptedBlob,cbEncryptedBlob,pbDecryptedMessage,&cbDecryptedMessage,NULL)){DecryptedString = (LPSTR) pbDecryptedMessage;printf("消息解密成功. \n");printf("被解密的字符串是: %s\n",DecryptedString);}else{printf("解密此消息出错 \n");printf("错误代码 %x \n",GetLastError());fReturn = FALSE;}//--------------------------------------------------------------------//释放内存空间free(pbEncryptedBlob);free(pbDecryptedMessage);return fReturn;
}  // End of DecryptMessage//--------------------------------------------------------------------
// 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;
}//--------------------------------------------------------------------
// 功能:遍历证书库中的证书,才,找到则返回此证书.
// 参数:hCertStore 证书库句柄PCCERT_CONTEXT GetRecipientCert( HCERTSTORE hCertStore)
{ //-------------------------------------------------------------------- // 申明与初始化变量PCCERT_CONTEXT pCertContext = NULL; BOOL fMore = TRUE; DWORD dwSize = 0; CRYPT_KEY_PROV_INFO* pKeyInfo = NULL; DWORD PropId = CERT_KEY_PROV_INFO_PROP_ID; //-------------------------------------------------------------------- // 寻找包含交换密钥对的证书while(fMore && (pCertContext= CertFindCertificateInStore( hCertStore, // 证书库句柄. 0,          // 编码类型. 0,          // dwFindFlags. 说明查询标准,这里没有使用CERT_FIND_PROPERTY, // 查询类型,决定进行何种类型的查询。这里使用证书的特定扩展属性&PropId,    // pvFindPara. 给出查询的特定值,这里为 扩展属性的标识符pCertContext))) //证书句柄,第一次调用时为NULL ,之后为上一次返回的指针{ //------------------------------------------------------------- //  获取证书属性:密钥对信息if(!(CertGetCertificateContextProperty( pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwSize))) { HandleError("获取密钥特性出错."); } //-------------------------------------------------------------- // 分配空间if(pKeyInfo) free(pKeyInfo); if(!(pKeyInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize))) { HandleError("为变量 pKeyInfo 分配内存出错."); } //-------------------------------------------------------------- // 获取密钥信息块. if(!(CertGetCertificateContextProperty( pCertContext, CERT_KEY_PROV_INFO_PROP_ID, pKeyInfo, &dwSize))) { HandleError("第二次调用此函数失败."); } //------------------------------------------- // 检查密钥信息块是否包含交换密钥对. if(pKeyInfo->dwKeySpec == AT_KEYEXCHANGE) { fMore = FALSE; } }    // End of while loop if(pKeyInfo) free(pKeyInfo); return (pCertContext);
} // End of GetRecipientCert //获取加密提供者句柄
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;
}//  HandleError:错误处理函数,打印错误信息,并退出程序
void HandleError(char *s)
{printf("程序执行发生错误!\n");printf("%s\n",s);printf("错误代码为: %x.\n",GetLastError());printf("程序终止执行!\n");exit(1);
}

原文链接: http://blog.csdn.net/yincheng01/article/details/7080505

转载于:https://my.oschina.net/junwong/blog/48190

vc++网络安全编程范例(19)实现数字信封打包与拆解相关推荐

  1. VC++网络安全编程范例(1)--数字证书有效期验证

    数字证书就是互联网通讯中标志通讯各方身份信息的一系列数据,提供了一种在Internet上验证您身份的方式,其作用类似于司机的驾驶执照或日常生活中的身份证.它是由一个由权威机构-----CA机构,又称为 ...

  2. vc++网络安全编程范例(14)-openssl bio编程

    OpenSSL整个软件包大概可以分成三个主要的功能部分:密码算法库.SSL协议库以及应用程序.OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的. 作为一个基于密码学的安全开发包,OpenS ...

  3. VC++网络安全编程范例(2)-创建自签名证书

    数字证书采用公钥体制,即利用一对互相匹配的密钥进行加密.解密.每个用户自己设定一把特定的仅为本人所知的私有密钥(私钥),用它进行解密和签名:同时设定一把公共密钥(公钥)并由本人公开,为一组用户所共享, ...

  4. [转]密码技术-实现数字信封和数字签名

    密码技术-实现数字信封和数字签名 转载自:http://hi.baidu.com/king0332/item/ea9b19da597aec17e1f46f5b 数字信封是公钥密码体制在实际中的一个应用 ...

  5. 基于MATLAB与VC混合编程的数字均衡器设计

    1.概述 随着数字化技术的快速.深入发展,人们对数字化电子产品所产生的图像.图形以及声音等质量的要求越来越高.在实时数字处理过程中,与D/A和A/D转换相关的模拟信号重构过程是决定数字系统输出质量的关 ...

  6. VC数据库编程总结(二)

    一.访问数据库技术方法......................................................................................... ...

  7. VC++动态链接库编程(转载)

    注:以下为转载:2005-10  作者:宋宝华  出处:天极网  http://soft.yesky.com/lesson/318/2166818.shtml VC++动态链接库编程之非MFC DLL ...

  8. 密码学之数字信封 Digital_Envelope

    东华大学信息安全专业,大三(下),系统安全课程设计实验 实验五  安全数据传输实验 一.实验目的 掌握对称密码和公钥密码体制的原理,通过综合使用两种加解密方式,了解两种加解密方式的异同点及认证方式. ...

  9. shell编程范例之字符串操作[转]

    shell编程范例之字符串操作 下面是"在线新华字典"的解释: 字符串: 简称"串".有限字符的序列.数据元素为字符的线性表,是一种数据的逻辑结构.在计算机中可 ...

最新文章

  1. java无法编译_Java静态方法无法编译
  2. uboot启动过程中关闭Caches
  3. mongodb备份恢复,数据导入导出
  4. Puppet基础应用
  5. Python外(5)-for-enumerate()-zip()
  6. mysql truncate table命令使用总结
  7. build.gradle配置参数详解
  8. 晚上睡觉的时候应该把wifi关掉吗?
  9. python单词的含义-Python常用英文单词有哪些?
  10. diskgenius做win10系统迁移
  11. 数码相机图像处理原理
  12. jadx动态调试安卓apk
  13. 树形表实现 bootstrap-table + treegrid
  14. 极路由 openwrt 使用 SyncY 实现百度云同步
  15. PUTTY 中文教程
  16. Ubuntu安装nvidia显卡驱动和CUDA CUDNN autoinstall
  17. 【爬虫】查看代理IP是否有效
  18. 从喜剧明星到NBA詹皇,盘点此届超级碗期间的加密广告
  19. 国外LEAD赚钱,做个网站真的很简单
  20. Python3 读取本地、网络摄像头流

热门文章

  1. awd-php,awd平台搭建
  2. FPGA采集IT6802视频HDMI输出,提供两套工程源码和技术支持
  3. datax,datax-web使用
  4. 大型工业设施的辐射噪声控制方法概论
  5. storm2.1.0搭建教程
  6. 学Linux云计算技术有意义吗?linux学习入门
  7. matlab 改变信号频率,使用插值和重定位来改变八度和matlab中的信号频率
  8. gor goreplay 流量重放 流量复制 dial i/o timeout
  9. 从ReadView深入理解MySql MVCC原理
  10. Yolov5如何更换EIOU / alpha IOU / SIoU?