惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Schneier on Security
The Last Watchdog
The Last Watchdog
Cyberwarzone
Cyberwarzone
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cyber Attacks, Cyber Crime and Cyber Security
L
Lohrmann on Cybersecurity
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 司徒正美
The Cloudflare Blog
V
V2EX
博客园_首页
博客园 - 聂微东
Vercel News
Vercel News
人人都是产品经理
人人都是产品经理
G
GRAHAM CLULEY
T
Tenable Blog
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
L
LINUX DO - 最新话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
SecWiki News
SecWiki News
博客园 - 三生石上(FineUI控件)
S
Secure Thoughts
N
News | PayPal Newsroom
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
T
Troy Hunt's Blog
博客园 - 【当耐特】
Forbes - Security
Forbes - Security
H
Hacker News: Front Page
A
About on SuperTechFans
B
Blog RSS Feed
Engineering at Meta
Engineering at Meta
MongoDB | Blog
MongoDB | Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
D
DataBreaches.Net
P
Privacy & Cybersecurity Law Blog
Schneier on Security
Schneier on Security
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google DeepMind News
Google DeepMind News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Jina AI
Jina AI
D
Docker
P
Proofpoint News Feed

博客园 - 程序员海风

cef加载flash的办法 一个高性能的对象属性复制类,支持不同类型对象间复制,支持Nullable<T>类型属性 php检测php.ini是否配制正确 openwrt的路由器重置root密码 windows 7 + vs2010 sp1编译 x64位版qt4 解决SourceGrid在某些系统上无法用鼠标滚轮滚动的问题 判断一个点是否在多边形内部,射线法思路,C#实现 [转载]使用HttpWebRequest进行请求时发生错误:基础连接已关闭,发送时发生错误处理 让Dapper+SqlCE支持ntext数据类型和超过4000字符的存储 通过WMI - Win32_Processor - ProcessorId获取到的并不是CPU的序列号,也并不唯一 DataGridView中设置固定行高 csExWB Webbrowser禁止flash内容的显示 使用csExWB Webbrowser 控件获取HttpOnly的cookie 禁用IIS FTP默认的连接提示信息:“220-Microsoft FTP Service” 在ASP.NET的单次请求中使用Singleton模式 Windows7的KB2488113补丁很重要,解决Windows7下软件无响应的问题 OpenFileDialog和SaveFileDialog使用不当会有文件夹共享冲突的问题 Cache-Control:nocache 会导致ie浏览器无法保存正确的图片类型 安装阿里旺旺2008会导致IE Webcontrols在客户端显示不正常
C#使用RSA私钥加密公钥解密的改进,解决特定情况下解密后出现乱码的问题
程序员海风 · 2011-06-03 · via 博客园 - 程序员海风

最近需要对一些数据加密后进行HTTP传输,由于希望对方只能收到数据后解密,而无法知道加密方法以防止伪造,所以选择了一个通过BigInteger类,使用私钥加密,公钥解密的算法。

算法是网上找来的,链接如下:

 一开始使用得挺好,加密解密都正常,但当加密的数据超过了128byte,解密后偶尔会出现乱码,解密失败。

通过跟踪发现,这是算法的一个bug,是由于对BigInteger类不当使用产生的。 具体分析如下:

先看加密方法:

private string EncryptString(string source, BigInteger d, BigInteger n)
        {
            
int len = source.Length;
            
int len1 = 0;
            
int blockLen = 0;
            
if ((len % 128== 0)
                len1 
= len / 128;
            
else
                len1 
= len / 128 + 1;
            
string block = "";
            
string temp = "";
            
for (int i = 0; i < len1; i++)
            {
                
if (len >= 128)
                    blockLen 
= 128;
                
else
                    blockLen 
= len;
                block 
= source.Substring(i * 128, blockLen);
                
byte[] oText = System.Text.Encoding.Default.GetBytes(block);
                BigInteger biText 
= new BigInteger(oText);
                BigInteger biEnText 
= biText.modPow(d, n);
                
string temp1 = biEnText.ToHexString();
                temp 
+= temp1;
                len 
-= blockLen;
            }
            
return temp;
        }

由于RSA算法单次加密只能支持128byte的数据,如果数据长度超过128byte,就会被分割为几段进行加密,最后把加密结果转换为16进制字符串,并连接起来输出结果。

一般情况下,128byte的数据,加密后输出的hex字符串应该是256byte,所以对应的解密方法为:把加密后的hex字符串按256byte进行拆分,分别解密,最后得到原文。方法如下:

private string DecryptString(string source, BigInteger e, BigInteger n)
        {
            
int len = source.Length;
            
int len1 = 0;
            
int blockLen = 0;
            
if ((len % 256== 0)
                len1 
= len / 256;
            
else
                len1 
= len / 256 + 1;
            
string block = "";
            
string temp = "";
            
for (int i = 0; i < len1; i++)
            {
                
if (len >= 256)
                    blockLen 
= 256;
                
else
                    blockLen 
= len;
                block 
= source.Substring(i * 256, blockLen);
                BigInteger biText 
= new BigInteger(block, 16);
                BigInteger biEnText 
= biText.modPow(e, n);
                
string temp1 = System.Text.Encoding.Default.GetString(biEnText.getBytes());
                temp 
+= temp1;
                len 
-= blockLen;
            }
            
return temp;
        }

 这个算法一般来讲是没问题的,但问题就在于,对于128byte的数据,BigInteger类输出的加密后的hex字符串,并不一定是256byte。所以,解密的时候按照256byte进行拆分,就会出现字符串拆分不正确,最终导致解密失败,解密出来的结果是乱码。

我们来看看BigInteger类的ToHexString()方法,其实现如下:

public string ToHexString()
        {
            
string result = data[dataLength - 1].ToString("X");for (int i = dataLength - 2; i >= 0; i--)
            {
                result 
+= data[i].ToString("X8");
            }
return result;
        }

 对于128byte的BigInteger,此方法返回的结果并不一定是256byte。

简单的解决办法,就是把这个方法的第一行,ToString("X")改为ToString("X8"),修改后的方法如下:

public string ToHexString()
        {
            
string result = data[dataLength - 1].ToString("X8");for (int i = dataLength - 2; i >= 0; i--)
            {
                result 
+= data[i].ToString("X8");
            }
return result;
        }

这样改虽然可以解决问题,但属于治标不治本的方法,因为这样改,也不能保证输出的字符串就是256byte, 最靠谱的方法是改进加密方法和解密方法。

加密方法的改进:

由于加密后的结果是通过输入16进制字符串进行保存的,输入的结果不可能包含@字符,因此我们可以用@符号来分割每128byte数据的加密结果,解密的时候按照@符号进行分割就不会出错。

改进后的加密方法如下:

private string EncryptString(string source, BigInteger d, BigInteger n)
        {
            
int len = source.Length;
            
int len1 = 0;
            
int blockLen = 0;
            
if ((len % 128== 0)
                len1 
= len / 128;
            
else
                len1 
= len / 128 + 1;
            
string block = "";
            StringBuilder result 
= new StringBuilder();
            
for (int i = 0; i < len1; i++)
            {
                
if (len >= 128)
                    blockLen 
= 128;
                
else
                    blockLen 
= len;
                block 
= source.Substring(i * 128, blockLen);
                
byte[] oText = System.Text.Encoding.Default.GetBytes(block);
                BigInteger biText 
= new BigInteger(oText);
                BigInteger biEnText 
= biText.modPow(d, n);
                
string temp = biEnText.ToHexString();
                result.Append(temp).Append(
"@");
                len 
-= blockLen;
            }
            
return result.ToString().TrimEnd('@');
        }

 改进后的解密方法如下:

private string DecryptString(string source, BigInteger e, BigInteger n)
        {
            StringBuilder result 
= new StringBuilder();
            
string[] strarr1 = source.Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries);
            
for (int i = 0; i < strarr1.Length; i++)
            {
                
string block = strarr1[i];
                BigInteger biText 
= new BigInteger(block, 16);
                BigInteger biEnText 
= biText.modPow(e, n);
                
string temp = System.Text.Encoding.Default.GetString(biEnText.getBytes());
                result.Append(temp);
            }
            
return result.ToString();
        }

相关链接:

[1]RSA私钥加密公钥解密算法。

http://blog.csdn.net/zhilunchen/archive/2008/09/17/2943158.aspx

[2]BigInteger大整数运算类。

http://www.codeproject.com/KB/cs/biginteger.aspx

文章关键词:C#,RSA,私钥加密公钥解密,BigInteger类,乱码

 ----------END----------