`
conkeyn
  • 浏览: 1545257 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

使用X.509数字证书加密解密实务(三)-- 使用RSA证书结合对称加密技术加密长数据

阅读更多

 

上一章节讨论了如何使用RSA证书加密数据,文中提到:“DotnetRSA实现有个特点,它必须要在明文中添加一些随机数,所以明文不能把128字节占满,实际测试,明文最多为117字节,留下的空间用来填充随机数”。也就是说对于1024位密钥的RSA来说,一次只能加密128字节的数据,对于DotnetRSA实现更是只能加密117个字节的数据。

这就引出一个问题,超过128字节(或者说超过117字节)的数据怎么加密?

有个办法,就是把数据明文拆分为合适大小的数据块之后逐块加密,解密时逐块的解密再拼接。事实上,DES(包括TripleDES)算法采用的就是这个办法,DES算法每次把数据明文拆分为8字节为单位的数据块,一次加密一个数据块,下一个数据块使用密钥和前一个数据块的加密结果再进行加密,如此逐块的进行加密,解密时也一样,逐块解密再拼接为明文。Dotnet提供的DES算法实现的DESCryptoServiceProvider(或TripleDESCryptoServiceProvider)类把这些拆分、加密、解密、拼接的过程都在内部实现,不需要开发人员自己去处理,对于开发人员可以认为DES可以直接一次性的加密长数据。

既然DES可以这么做,为什么RSA算法不这么做,直接在实现RSA算法的RSACryptoServiceProvider类中自动分拆加密解密拼接长数据呢?

先来看一下对称算法(以DES为代表)和非对称算法(以RSA为代表)的各自特点。

l   对称算法:

加密方和解密方使用同一个密钥,必然有个密钥传送过程,密钥的保密性有较大风险。

算法相对简单,加密解密速度很快。

l   非对称算法:

加密方使用密钥对中的公钥,解密方使用密钥对中的私钥。

算法复杂,加解密速度慢。RSA算法之所以不这么做,是因为RSA算法的复杂性导致的加密解密的速度很慢,不提倡使用RSA加密长数据,所以dotnetRSA实现也没有这么做。当然开发者可以自己写代码实现拆分加密解密拼接的过程,实现用RSA加密长数据的功能。但是这不是个好办法,比较现实的方法是:不对称加密技术结合对称加密技术加密长数据。

具体思路是这样:

加密方生成对称加密的密钥key(包括keyIV),然后对称算法使用这个key去加密长数据,之后再用解密方提供的非对称算法的公钥publickey加密刚才生成的对称密钥key,最后把加密后的长数据和加密后的对称密钥key拼接在一起发送给解密方。

解密方接收到后,首先分解数据,把加密后的对称密钥key和加密后的长数据两部分分解开。之后使用非对称算法的私钥解密,获得对称密钥key。最后用对称密钥key解密加密的长数据。

下面以前面章节生成的RSA的证书结合TripleDES算法为例描述不对称加密技术结合对称加密技术加密长数据的具体实现过程。

 

Figure 13. RSA结合TripleDES算法加密解密过程

 

RSA证书

由解密方申请X.509RSA证书,或者使用前面“使用makecert工具获得”章节生成的MyTestCert。解密方要把自己的RSA证书导出为cer类型的只含有公钥的证书分发给所有可能需要给自己发送加密消息的加密方。

System.Security.Cryptography. TripleDESCryptoServiceProvider类是dotnet中实现TripleDES算法的主要的类。

TripleDES算法keyIV

TripleDESCryptoServiceProvider类只有一个构造方法TripleDESCryptoServiceProvider(),这个方法把一些属性初始化:

KeySize(加密密钥长度,以位为单位)= 19224字节)

BlockSize(加密处理的数据块大小,以位为单位)= 648字节)

FeedbackSize(加密数据块后返回的数据大小,以位为单位)= 648字节)

TripleDESCryptoServiceProvider构造方法同时会初始化一组随机的keyIV

默认的TripleDESCryptoServiceProviderkey24字节(也可以生成16字节的key),IV8字节,加密数据块为8字节。

生成keyIV的代码很简单:

TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();

byte[] keyArray = tDESalg.Key;

byte[] IVArray = tDESalg.IV;

RSA公钥加密TripleDES算法的keyIV

RSA公钥

加密方获得的是解密方提供的只含有公钥的cer证书,要通过读取cer证书文件来获得RSA公钥(当然,也可以把证书加载到证书储存区,然后到证书储存区读取证书获得公钥)。

//从只包含公钥的证书文件载入证书

X509Certificate2 myX509Certificate2 = new X509Certificate2(@"..\..\..\MyTestCert.cer");

//从证书中获得含公钥的RSACryptoServiceProvider

RSACryptoServiceProvider publickeyProvider = (RSACryptoServiceProvider)myX509Certificate2.PublicKey.Key;

加密keyIV

KeyIV都是是以byte[]形式存在,要把它们两个连接在一起后加密,就要考虑到解密后怎么把它们两个能够准确的分割开。

Byte[]就是字节数组, keyIVTripleDESCryptoServiceProvider类随机生成的,每个字节可以是任意值,如果直接把keyIVbyte[]直接连在一起,加密解密后,拆分它们时,根据keyIV本身的内容就无法分割,没有区分两部分内容的标识。当然可以通过keyIV本身的长度去拆分,但是key的长度也不是完全确定的,DES算法的key8位,TripleDES算法的key16位或24位的,所以通过长度拆分也不是好办法。

一般的做法是在keyIV直接增加一个分隔符,两部分数据通过分隔符连接起来,以后拆分的时候根据分隔符来拆分分隔符两边的不同部分就行了。

问题又来了,既然两边的内容是随机生成的,可能是任何值,如何保证两边的内容不跟分隔符相同呢,如果碰巧要两边的内容出现跟分隔符相同的部分就麻烦了,拆分出来的数据肯定不对了。

可以对需要连接的内容做一个变换,把它们转换成另一种编码,而分隔符采用这种编码中不可能有的字符就行了。

一般的选择是base64编码,这种编码只含有64个字符,就是:大写的A-Z、小写的a-z、数字0-9'+' '/'。进一步了解base64编码,请参考:http://www.cnblogs.com/chnking/archive/2007/08/12/852669.html

keyIV分别就行base64编码,然后设置一个分隔符(比如“ßà”这样的base64中不可能有的字符),把它们连接后再进行加密。

//使用RSA公钥加密TripleDES算法的keyIV

string keyandIV = Convert.ToBase64String(keyArray) + separator + Convert.ToBase64String(IVArray);

//RSA公钥加密TripleDES算法的keyIV

byte[] keyandIVBytesEncrypted = publickeyProvider.Encrypt(encoding.GetBytes(keyandIV),false);

//加密后的keyIV再转为base64的字符串

string keyandIVStrEncrypted = Convert.ToBase64String(keyandIVBytesEncrypted);

//建立一个MemoryStream,这里面存放加密后的数据流

MemoryStream mStream = new MemoryStream();

// 使用MemoryStream keyIV新建一个CryptoStream 对象

CryptoStream cStream = new CryptoStream(mStream,

    new TripleDESCryptoServiceProvider().CreateEncryptor(keyArray, IVArray),

    CryptoStreamMode.Write);

//将明文字符串转成指定代码页的byte[]

byte[] plainTextArray = encoding.GetBytes(plaintext);

// 将加密后的字节流写入到MemoryStream

cStream.Write(plainTextArray, 0, plainTextArray.Length);

//把缓冲区中的最后状态更新到MemoryStream,并清除cStream的缓存区

cStream.FlushFinalBlock();

// 把加密后的数据流转成Base64的字符串

string longDataStrEncrypted = Convert.ToBase64String(mStream.ToArray());

// 关闭两个streams.

cStream.Close();

mStream.Close();

待加密的数据可能有两种形式,一种是二进制的数据,本身就是一组字节流,这样的数据可以跳过这一步,直接进入加密步骤。还有一种情况是字符串数据,字符串中同样的字符使用不同的代码页会生成不同的字节码,所以从字符串到字节流的转换是需要指定使用何种编码的。在解密之后,要从字节流转换到字符串就要使用相同的代码页解码,否则就会出现乱码。

实际上凡是在byte[]类型跟string类型直接进行转换时,都需要指定代码页,因为每种代码页对相同字符的编码是不一样的,就是说同一个字符在不同的代码页中是对应到不同的二进制码。

在本例的加密解密过程中有大量的byte[]类型跟string类型之间的转换,所以在例子中使用了预先定义了一个Encoding类型的对象encodingutf-8代码页的,本例中所有涉及byte[]类型跟string类型之间的转换都采用同一个Encoding,保证都是用同样的代码页进行转换。

跟连接keyIV的情况一样,加密后的对称密钥和加密后的长数据也需要连接起来,同样是通过一样的分隔符连接。

//把加密的长数据用分隔符同加密后的DES的密钥连接为一个字符串

string resultEncryptedStr = longDataStrEncrypted + separator + keyandIVStrEncrypted;

//加密的数据跟加密后的keyIV连接后的base64字符串再被转成byte[]以便传送

byte[]resultEncryptedBytes = encoding.GetBytes(resultEncryptedStr);

 加密过程数据存在形式变化:

 

 

Figure 14. RSA结合DES加密解密大数据数据存在形式变化过程--加密过程

上面是加密过程,下面是解密过程。

 

解密过程中需要多次使用到分拆字符串功能,写个分拆字符串的方法:

/// <summary>

/// 根据分隔符,将分隔符两边的字符串分开

/// </summary>

/// <param name="value">带分隔符的字符串</param>

/// <param name="separator">分隔符</param>

/// <returns></returns>

private static string[] splitByString(string value, string separator)

{

int separatorPos = value.IndexOf(separator);

    string[] returnValue = new string[2];

    returnValue[0] = value.Substring(0, separatorPos);

    returnValue[1] = value.Substring(separatorPos + separator.Length);

    return returnValue;

}

解密方使用上面的方法把收到的数据分拆为加密的长数据和加密的对称密钥两部分

//分拆加密的长数据和加密的对称密钥

string[] EncryptedDataArray = splitByString(encoding.GetString(cryptographic), separator);

//加密的长数据

string longDataStrEncrypted = EncryptedDataArray[0];

//加密的对称密钥

string keyandIVStrEncrypted = EncryptedDataArray[1];

TripleDES算法的keyIV

RSA公钥

解密方获可以从自己的pfx证书文件来获得RSA私钥(当然,也可以把证书加载到证书储存区,然后到证书储存区读取证书获得私钥钥)。载入含有私钥的证书时,需要提供私钥保护密码。

//从证书文件载入证书,如果含有私钥的,需要提供保存证书时设置的密码

X509Certificate2 myX509Certificate2 = new X509Certificate2(@"..\..\..\MyTestCert.pfx", "password");

//从证书中获得含私钥的RSACryptoServiceProvider

RSACryptoServiceProvider privatekeyProvider = (RSACryptoServiceProvider)myX509Certificate2.PrivateKey;

解密keyIV

//加密的对称密钥base64字符串转成byte[]

byte[] keyandIVBytesEncrypted = Convert.FromBase64String(keyandIVStrEncrypted);

//解密加密的对称密钥并转成字符串

string keyandIV = encoding.GetString((publickeyProvider.Decrypt(keyandIVBytesEncrypted, false)));

//拆分keyIV

string[] keyIVArray = splitByString(keyandIV, separator);

//keybase64字符串复原为byte[]的原始形式

byte[] keyArray = Convert.FromBase64String(keyIVArray[0]);

//IVbase64字符串复原为byte[]的原始形式

byte[] IVArray = Convert.FromBase64String(keyIVArray[1]);

byte[] longDataBytesEncrypted = Convert.FromBase64String(longDataStrEncrypted);

// 建立一个MemoryStream,这里面存放加密后的数据流

MemoryStream msDecrypt = new MemoryStream(longDataBytesEncrypted);

// 使用MemoryStream keyIV新建一个CryptoStream 对象

CryptoStream csDecrypt = new CryptoStream(msDecrypt,

    new TripleDESCryptoServiceProvider().CreateDecryptor(keyArray, IVArray),

    CryptoStreamMode.Read);

// 根据密文byte[]的长度(可能比加密前的明文长),新建一个存放解密后明文的byte[]

byte[] DecryptDataArray = new byte[longDataBytesEncrypted.Length];

// 把解密后的数据读入到DecryptDataArray

csDecrypt.Read(DecryptDataArray, 0, DecryptDataArray.Length);

msDecrypt.Close();

csDecrypt.Close();

//解密后的长数据byte[]转成字符串

string resultSrt = encoding.GetString(DecryptDataArray);

//去掉字符串后的"\0"字符

int offset = resultSrt.IndexOf("\0");

string longData = resultSrt.Substring(0, offset);

最后获得长数据的明文,有一点需要注意。

DES加密是以8字节为一个数据块,如果明文的长度不是8字节的整数倍,DES会在明文后面添加值为0的字节凑足8字节的数据块,然后加密。这样的数据解密后,添加的”\0”仍然存在,需要去掉。 

解密过程数据存在形式变化:

 

Figure 15. RSA结合DES加密解密大数据数据存在形式变化过程-- 解密过程

 

源代码下载 

 

 

“参考:

.NET中管理数字证书(Digital Certificate的一些类

创建X509证书,并获取证书密钥的一点研究

  • 大小: 52.6 KB
  • 大小: 49.6 KB
  • 大小: 64.7 KB
分享到:
评论

相关推荐

    cmd-bat-批处理-脚本-Progress bar 1.zip

    cmd-bat-批处理-脚本-Progress bar 1.zip

    小红书2024年度Java编程开发面试题及参考答案-超详细解析

    该资源是小红书 2024 年度Java 编程开发面试题,内容非常详细,适合应届毕业生和准备寻求更高发展的Java工程师,希望给你们带来帮助。

    RISC-V指令集五级流水线CPU设计与验证:基于Verilog的实现及应用 CPU设计

    内容概要:本文详细介绍了基于RISC-V指令集的五级流水线CPU设计及其验证过程。首先,文章阐述了RISC-V指令集的特点及其在CPU设计中的优势,接着深入解析了每个流水线阶段(取指、解码、执行、访存、写回)的Verilog源代码实现。此外,提供了汇编验证代码用于测试CPU的功能,并附带详细的说明文档和PPT,确保设计的完整性和易理解性。最后,在Vivado平台上进行了全面的仿真和实际硬件测试,验证了设计的正确性和性能。 适合人群:从事嵌入式系统设计、CPU架构研究及相关领域的工程师和技术人员。 使用场景及目标:①理解和掌握RISC-V指令集在五级流水线CPU设计中的应用;②学习Verilog语言在CPU硬件设计中的具体实现方法;③通过汇编验证代码测试CPU功能,确保设计的可靠性。 其他说明:本文不仅提供了完整的Verilog源代码和汇编验证代码,还包括详细的说明文档和PPT,有助于读者更好地理解和实践CPU设计过程。

    基于51单片机与HC-05蓝牙模块的Android手机通信程序

    本程序实现了51单片机与手机之间的字符及数字通信功能,且代码中配有详尽的注释说明。关于通信原理的详细阐述,可在我的其他相关文章中查阅。

    cmd-bat-批处理-脚本-run dialogue.zip

    cmd-bat-批处理-脚本-run dialogue.zip

    多智能体编队技术中48智能体点对点转换的分布式模型预测控制及应用 多智能体系统

    内容概要:本文详细介绍了多智能体编队技术,特别是针对4智能体和8智能体的点对点转换分布式模型预测控制。首先概述了多智能体编队的概念及其广泛应用,如无人驾驶、无人机编队等。接着深入探讨了分布式模型预测控制的方法论,强调每个智能体依据自身模型和邻近智能体信息进行预测并制定控制策略,从而提升系统灵活性和鲁棒性。随后阐述了点对点转换的具体机制,即智能体间通过高效的信息交换实现状态间的平滑过渡。最后展示了简化的Python代码示例来解释这一过程,并提供了相关领域的权威参考文献。 适合人群:对多智能体系统、分布式控制系统感兴趣的科研人员和技术开发者。 使用场景及目标:适用于希望深入了解多智能体编队控制理论的研究者以及从事无人驾驶、无人机编队等相关项目的技术人员。目标在于掌握分布式模型预测控制的基本原理及其在实际工程中的应用。 其他说明:文中提供的代码仅为概念验证性质,实际部署时还需考虑更多因素如网络延迟、数据同步等。此外,附带的参考文献为读者进一步学习提供了宝贵的资料来源。

    2023年系统分析师真题及解析

    2023年系统分析师真题及解析

    IMG_20250521_201207.jpg

    IMG_20250521_201207.jpg

    基于鲸鱼算法的光伏风电选址定容优化及其经济性评估 多目标优化

    内容概要:本文探讨了利用鲸鱼算法(Whale Optimization Algorithm)对光伏和风电项目的选址和定容进行优化的方法。鲸鱼算法是一种新颖的智能算法,它模仿座头鲸的捕食行为,具有较少的参数调整需求和强大的寻优能力。文中详细介绍了该算法的核心机制,如气泡网攻击策略,并展示了如何将其应用于新能源项目的选址定容问题中。具体来说,通过定义合适的目标函数来衡量不同方案的表现,包括网损、节点电压偏差和投资成本等因素。此外,还讨论了如何通过调整权重系数来平衡各个目标之间的关系,从而获得最佳解决方案。最终,通过对实验结果的分析,证明了鲸鱼算法在处理此类多维度优化问题上的优越性能。 适合人群:从事新能源规划、电力系统工程及相关领域的研究人员和技术人员。 使用场景及目标:适用于需要对光伏和风电项目进行科学合理的选址和定容决策的情境下,旨在提高能源利用效率的同时降低成本,确保电网稳定性和可靠性。 其他说明:文中提供了具体的Python代码示例,帮助读者更好地理解和实现鲸鱼算法的应用。同时强调了在实际操作过程中应注意的一些关键因素,如数据预处理方法的选择以及参数设置的影响等。

    工业自动化领域威纶通A2触摸屏程序标准精美模板及其应用

    内容概要:本文详细介绍了威纶通标准精美模板,一套专为A2触摸屏程序开发提供的可直接套用的界面模板。模板涵盖了多个实用功能界面,如配方管理、报警记录、操作记录、登录、设备使用说明、参数设置、系统设置、权限设置、趋势显示、电机设置、IO监控、工位用时、文档设置和维修界面。每个界面均经过精心设计,确保界面清新整洁,不带复杂的宏指令,便于操作和维护。此外,模板还支持XY曲线、树状图、数据统计等功能,能够灵活配置和调用。这套模板不仅适用于快速开发,也为新手和在校生提供了宝贵的学习资源。 适用人群:工业自动化领域的开发人员、工程师、新手和在校学生。 使用场景及目标:① 开发人员可以通过直接套用或复制模板,快速完成A2触摸屏程序开发;② 新手和在校生可以利用模板学习触摸屏程序的设计和实现,掌握工业自动化领域的关键技能。 其他说明:模板中的功能和界面设计充分考虑了工业自动化的需求,确保了系统的稳定性和实用性。

    一种三元锂电池析锂特性以及检测方法研究.zip

    一种三元锂电池析锂特性以及检测方法研究.zip

    大规模无线传感 器网络中稀疏信号的数据收集策略.pdf

    大规模无线传感 器网络中稀疏信号的数据收集策略.pdf

    cmd-bat-批处理-脚本-One_Click_StockPrice.zip

    cmd-bat-批处理-脚本-One_Click_StockPrice.zip

    cmd-bat-批处理-脚本-installed-package-contents.zip

    cmd-bat-批处理-脚本-installed-package-contents.zip

    2025年网络媒体项目解决方案.docx

    2025年网络媒体项目解决方案.docx

    实证数据-2010-2023年上市公司-管理层情感语调数据-社科经管.rar

    该数据集为2010-2023年中国A股上市公司管理层情感语调的年度面板数据,覆盖45,320条样本,数据源自年报及半年报的"管理层讨论与分析"部分。通过构建中文金融情感词典(融合《知网情感分析用词典》与L&M金融词汇表),采用文本分析方法计算情感语调指标,包括:正面/负面词汇数量、文本相似度、情感语调1((积极词-消极词)/总词数)和情感语调2((积极词-消极词)/(积极词+消极词))。同时包含盈利预测偏差、审计意见类型等衍生指标,可用于研究信息披露质量、市场反应及代理问题。该数据复刻了《管理世界》《财经研究》等期刊的变量构建方法,被应用于分析语调操纵对债券市场的影响,学术常用度与稀缺度较高。

    cmd-bat-批处理-脚本-green.zip

    cmd-bat-批处理-脚本-green.zip

    心脏病发作数据集.rar

    数据文档 背景描述 心脏病是全球主要的健康威胁之一,也是导致死亡的主要原因。及早识别心脏病风险因素和预测可能的心脏问题对于预防和治疗至关重要。该数据集收集了与心脏健康相关的多种生理指标和实验室检查结果,旨在帮助开发能够区分心脏病阳性和阴性患者的预测模型。 通过分析这些数据,医疗专业人员和研究人员可以更好地理解不同因素(如年龄、性别、血压、血糖和心肌标志物)对心脏病发展的影响,从而制定更精准的诊断和治疗方案。 数据说明 字段 说明 Age 患者年龄 Gender 性别(1=男性,0=女性) Heart rate 心率(每分钟心跳次数) Systolic blood pressure 收缩压(毫米汞柱) Diastolic blood pressure 舒张压(毫米汞柱) Blood sugar 血糖水平(毫克/分升) CK-MB 肌酸激酶同工酶水平(心肌损伤标志物) Troponin 肌钙蛋白水平(心肌损伤特异性标志物) Result 诊断结果(positive=患有心脏病,negative=未患心脏病) 问题描述 该数据集适用于多种分析和预测场景,可以帮助解决以下问题: 心脏病风险预测: 基于生理指标和生化标志物预测个体患心脏病的风险。 关键指标识别: 确定对心脏病诊断最有预测价值的生理和生化指标。 人口统计学分析: 研究年龄和性别与心脏病发生率之间的

    中国传统节日小年介绍.pptx

    中国传统节日小年介绍.pptx

Global site tag (gtag.js) - Google Analytics