`
conkeyn
  • 浏览: 1528922 次
  • 性别: 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
分享到:
评论

相关推荐

    JAVA 使用数字证书加密解密文件

    本文将深入探讨如何使用Java语言结合RSA算法,通过数字证书实现文件的加密和解密操作。RSA是一种非对称加密算法,它的核心在于一对密钥:公钥和私钥。公钥可以公开给任何人,用于加密数据;而私钥必须保密,用于解密...

    公钥私钥加密解密数字证书数字签名详解.docx

    HTTPS 结合了加密解密和数字签名的技术,利用 SSL/TLS 协议实现了数据的加密传输,数字证书确保了公钥的真实性和可靠性,而数字签名则进一步保证了数据的完整性和来源的真实性。这些技术的综合应用为互联网的安全...

    bcprov-jdk16-146-RSA.jar RAS加解密公私钥

    RSA算法是一种非对称加密算法,它在信息安全领域扮演着重要的角色,特别是在数据加密、数字签名和密钥交换等方面。公私钥加解密是RSA的核心特性,它使用一对密钥,即公钥和私钥,来进行加密和解密操作。这种机制确保...

    C# .net版 RSA 公钥加密私钥解密 私钥加密公钥解密

    因此,如果需要加密大量数据,通常会采用一种称为“密钥交换”的方式,先用RSA加密一个对称密钥,然后使用这个对称密钥加密大量数据,这样可以提高效率。 - RSA加密过程是不可逆的,因此在使用前需确认加密和解密的...

    Object-C-在iOS上使用Object-C进行RSA算法的加密+解密实现.zip

    RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,广泛应用于数据安全领域,如数字签名、密钥交换等。本教程将详细讲解如何在iOS项目中使用Object-C实现RSA算法的加密和解密功能。 首先,了解RSA的基本原理至关...

    FileEncryption.rar C#文件加密解密

    在C#编程环境中,文件加密和解密是保护数据安全的重要技术。本文将详细探讨如何使用C#实现文件的加密和解密,以及涉及到的相关知识点。 1. **基础概念** - **加密**:加密是一种将明文转换为密文的过程,目的是...

    c语言写成的取x.509证书公钥

    在IT行业中,X.509证书是一种广泛用于身份验证的标准格式,特别是在网络安全和SSL/TLS协议中。这种证书包含了公钥基础设施(PKI)中的关键信息,如发行者的身份、持有者的身份以及公钥。C语言作为一种底层、高效的...

    Rsa加密解密.rar_RSA 加密解密_java rsa_rsa加密_rsa加密java_加密 解密

    对于大量数据,通常会结合使用RSA和对称加密算法(如AES),使用RSA加密对称密钥,然后用对称密钥加密大量数据。 在提供的压缩包文件中,"www.pudn.com.txt"可能包含了关于RSA加密解密的代码示例或相关资源,而"Rsa...

    C# RSA加密解密

    总结,C#中的RSA加密解密结合Winform界面,为用户提供了直观的操作方式来保护数据。开发者可以通过理解并运用这些概念,构建更复杂的安全系统,确保数据在传输和存储过程中的安全性。在实际项目中,还可以考虑使用...

    文件非对称加密解密工具(RSA).exe

    本工具是用于golang编写的,用于rsa非对称加密技术实现的对字符串的加密解密工具,可以对文件进行加密解密(txt、docx、xls文档等)。对文档加密会对文档同目录下生成一个后缀名加.hh的文档。 操作说明: 一、对字符...

    RSA加密解密的使用,含jsencrypt.js文件(uni-app也可用)

    RSA加密解密是一种广泛应用于网络安全中的非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman三位科学家在1977年提出,因此得名RSA。这种算法基于大数因子分解的困难性,为数据提供了一种安全的传输方式。 ...

    rsa.zip_RSA 加密解密_rsa

    RSA算法是一种非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman在1977年提出,是目前最广为应用的公钥加密算法。其核心特点是使用一对密钥,一个公开,任何人都可以获取,用于加密;另一个私有,只有接收...

    bcprov-jdk15on-1.47.jar Java 加密 解密 jar包

    3. **数字签名和证书处理**:Bouncy Castle能够生成和验证X.509证书,以及处理RSA、DSA、ECDSA等签名算法。 4. **SSL/TLS协议支持**:它提供了SSL和TLS协议的实现,有助于构建安全的网络通信。 5. **随机数生成器*...

    jsencrypt.min.js通过JSEncrypt分段加密解密

    JavaScript中的RSA加密是一种广泛用于前端安全传输数据的技术,特别是在与服务器进行敏感信息交互时,如登录凭证、支付信息等。`jsencrypt.min.js` 是一个轻量级的库,它实现了RSA加密算法,并且提供了方便的API供...

    security.js rsa加密解密

    4. 性能考虑:RSA加密和解密相对较慢,适用于少量数据的加密,对于大量数据,通常会结合对称加密算法(如AES)使用,先用RSA加密对称密钥,然后用该密钥加密大量数据。 5. 数字签名:RSA还可以用于生成数字签名,...

    加密证书和RSA加密解密

    加密证书和RSA加密解密是信息安全领域中的重要概念,它们在保护数据安全、验证网络通信双方身份以及确保信息完整性方面发挥着关键作用。在此,我们将深入探讨这些知识点,并结合一个名为"demo"的示例来进一步理解其...

    RSA加密解密工具,用于文件的加密和解密* RSA加密解密:私钥解密,公钥加密

    RSA算法是一种非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman在1977年提出,是目前广泛应用于网络安全领域的一种核心加密技术。它的主要特点是拥有两个密钥:公钥和私钥。公钥可以公开,用于加密信息;...

    RSA加密算法的JS文件jsencrypt.min.js

    实际应用中,通常结合非对称加密(如RSA)和对称加密(如AES)来提高性能和安全性。 在Web开发中,RSA加密常用于保护敏感信息,例如HTTPS通信中的预共享密钥交换,或者在前端加密用户密码以保护其在传输过程中不被...

Global site tag (gtag.js) - Google Analytics