.NET导入openssl生成的公钥之BEGIN RSA PUBLIC KEY
.NET导入openssl生成的公钥之BEGIN RSA PUBLIC KEY
我得到了一个公钥,形式如下
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMroxz3qtok…….
……
-----END RSA PUBLIC KEY-----
相要用C#程序,将它导入并加密数据传给opensll应用程序解密。在网上找到很多方法,其中opensslkey.cs文件的实现最完善,但它只能解析-----BEGIN PUBLIC KEY-----打头的公钥。而且内容的长度也不同,看来它是解不开了。在搜索的过程中,发现Jeffrey Walton有文章Cryptographic Interoperability: Keys,讲的是密钥的编解码。从以下地址可以获得
http://www.codeproject.com/KB/security/CryptoInteropKeys.aspx
多从他附带的代码中,搞清楚了密钥的格式。分析了一下我的钥格式,发现其实公钥格式很简单。如下:
//* +- SEQUENCE // RSAPrivateKey
//* +- INTEGER(N) // N
//* +- INTEGER(E) // E
上面我们看到的就是这个公钥中的全部内容了,比-----BEGIN PUBLIC KEY-----打头的要少很多内容。就是因为太简单了,才给我造成了很大的麻烦!上面的格式其实是一个ASN标准编码,Jeffrey Walton提供的源码中有一个类AsnParser很容易就能解析出来。于是,我在Jeffrey Walton写的类AsnKeyParser中加了一个函数ParsePkcsRSAPublicKey。
internal RSAParameters ParsePkcsRSAPublicKey()
{
//* +- SEQUENCE // RSAPrivateKey
//* +- INTEGER(N) // N
//* +- INTEGER(E) // E
RSAParameters parameters = new RSAParameters();
// Sanity Check
int length = 0;
// Checkpoint
int position = parser.CurrentPosition();
// Ignore Sequence - PublicKeyInfo
length = parser.NextSequence();
if (length != parser.RemainingBytes())
{
StringBuilder sb = new StringBuilder("Incorrect Sequence Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture),
parser.RemainingBytes().ToString(CultureInfo.InvariantCulture));
throw new BerDecodeException(sb.ToString(), position);
}
// Checkpoint
position = parser.CurrentPosition();
int remaining = parser.RemainingBytes();
parameters.Modulus = TrimLeadingZero(parser.NextInteger());
parameters.Exponent = TrimLeadingZero(parser.NextInteger());
Debug.Assert(0 == parser.RemainingBytes());
return parameters;
}
注意加红的两行就是公钥的全部。
由于AsnKeyParser只有一个构造函数,并且只接受文件名,并从文件中读取数据。但它并不认识PEM格式,所以PEM的解析还是放在外面。看一下原来的构造函数:
internal AsnKeyParser(String pathname)
{
using (BinaryReader reader = new BinaryReader(
new FileStream(pathname, FileMode.Open, FileAccess.Read)))
{
FileInfo info = new FileInfo(pathname);
parser = new AsnParser(reader.ReadBytes((int)info.Length));
}
}
可以看出来,从文件读取数据之后,直接把二进制数据传给了AsnParser。而AsnParser当然不能解析Base64解码后的数据。我又给它加了一个构造函数
internal AsnKeyParser(AsnParser parser)
{
this.parser = parser;
}
看出来了吧,就是要在外面做完Base64解码之后再传给AsnKeyParser。
最后再写了一个从文件加载,及调用AsnKeyParser的函数,就大功告成了!
private static RSAParameters LoadRsaPublicKey()
{
string s = File.ReadAllText("pub.pem"); // 从文件读取
StringBuilder build = new StringBuilder(s);
// 去掉头尾
build.Replace("-----BEGIN RSA PUBLIC KEY-----", "");
build.Replace("-----END RSA PUBLIC KEY-----", "");
s = build.ToString().Trim();
byte[] binKey = System.Convert.FromBase64String(s); // Base64解码
AsnParser parser = new AsnParser(binKey); // 现在已经是AsnParser能认识的数据了
AsnKeyParser keyParser = new AsnKeyParser(parser); // 就刚加的构造孙数
RSAParameters publicKey = keyParser.ParsePkcsRSAPublicKey(); // 还是用刚加的解析函数
return publicKey; // 公钥已经得到,可以尽情的用RSACryptoServiceProvider了。
}
为了测试得到的密钥正不正常,我用openssl生成了一对密钥。再用我的程序来加载密钥,并测试加密与解密,来最后解密出来的结果,是否与加密前一至。
生成的密钥如下你也可以自己生成
pub.pem
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMroxz3qtok9aa777ssNfVKHgGI8BPrGexhS2PE+2xZGffakR2QbS5vw
CidhVzrpzRJJuaZqktBrcVC7as1TsP2mY8RgWPNOvHisDDZp+H5c2+UwVQ6bV1tk
MXx1RSDryOO4mmeONJE8aJcGG+9KWkoZEQL5XIzrzy3NeYNYu5J1AgMBAAE=
-----END RSA PUBLIC KEY-----
pri.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDK6Mc96raJPWmu++7LDX1Sh4BiPAT6xnsYUtjxPtsWRn32pEdk
G0ub8AonYVc66c0SSbmmapLQa3FQu2rNU7D9pmPEYFjzTrx4rAw2afh+XNvlMFUO
m1dbZDF8dUUg68jjuJpnjjSRPGiXBhvvSlpKGREC+VyM688tzXmDWLuSdQIDAQAB
AoGBAMfr6sO6yvcVp1ddqr4uIFh8YaZodI+RmB8zIcUwpTShZ+Lnod+kdS7Dp319
jzDgw8lNErpBLz5jXlapEmYUG8FNOLK/z45oVVSlLZquuQowcR3JoDtb/yKvOPdQ
EavCsvoQT7lIn4oCUAWZP/yyQQA2TDjyVmUF9gQctbbuwPkBAkEA9L0FC91Pa3dd
Ry1sD0rhcrLAsFZX0gzd3ozgAQGM/p2dY1AN0pOF15mJgaHRP2UImqb0qtmsroSd
BwEsZulwcQJBANQ/BMFnfcvxh7IvrxvA8Mh/Edb8RJcKxuutLjABj4Ah8nIdGb5S
XHhCQ3JIA2x6ydygY6ldqLvsYAQiuOY2hEUCQQDlV3QxKBTSmiq5FqGauwsFlujm
1iK53gDUGqOXjcJ4n27rsAsj98aGwYSQC/mwNJeZhTbmG9GsQO19sOXREpShAkEA
sKx4b+mO3GoEE33/3DFh/PNRTUyWZ8hPxzRUIx/ZbMZVQ0oX+MYkNPKrpABv4Sfg
ymc0LnJJF4zua+LfWLp+pQJAXFa8xvDdLcQ4PhG4pDqUuvklbUkyl36GrfU9CkIK
GbnoDXw7W5SJ0qb258JxIx4cNsDIC+CU0r7Ejmo5g3RMew==
-----END RSA PRIVATE KEY-----
把它们放在bin\Debug目录下
又实现了一个解析密钥的函数
internal RSAParameters ParsePkcsRSAPrivateKey()
{
//*+- SEQUENCE // RSAPrivateKey
//* +- INTEGER(0) // Version - 0 (v1998)
//* +- INTEGER(N)
//* +- INTEGER(E)
//* +- INTEGER(D)
//* +- INTEGER(P)
//* +- INTEGER(Q)
//* +- INTEGER(DP)
//* +- INTEGER(DQ)
//* +- INTEGER(Inv Q)
RSAParameters parameters = new RSAParameters();
// Current value
byte[] value = null;
// Checkpoint
int position = parser.CurrentPosition();
// Sanity Check
int length = 0;
// Ignore Sequence - PrivateKeyInfo
length = parser.NextSequence();
if (length != parser.RemainingBytes())
{
StringBuilder sb = new StringBuilder("Incorrect Sequence Size. ");
sb.AppendFormat("Specified: {0}, Remaining: {1}",
length.ToString(CultureInfo.InvariantCulture), parser.RemainingBytes().ToString(CultureInfo.InvariantCulture));
throw new BerDecodeException(sb.ToString(), position);
}
// Checkpoint
position = parser.CurrentPosition();
// Version
value = parser.NextInteger();
if (0x00 != value[0])
{
StringBuilder sb = new StringBuilder("Incorrect RSAPrivateKey Version. ");
BigInteger v = new BigInteger(value);
sb.AppendFormat("Expected: 0, Specified: {0}", v.ToString(10));
throw new BerDecodeException(sb.ToString(), position);
}
parameters.Modulus = TrimLeadingZero(parser.NextInteger());
parameters.Exponent = TrimLeadingZero(parser.NextInteger());
parameters.D = TrimLeadingZero(parser.NextInteger());
parameters.P = TrimLeadingZero(parser.NextInteger());
parameters.Q = TrimLeadingZero(parser.NextInteger());
parameters.DP = TrimLeadingZero(parser.NextInteger());
parameters.DQ = TrimLeadingZero(parser.NextInteger());
parameters.InverseQ = TrimLeadingZero(parser.NextInteger());
Debug.Assert(0 == parser.RemainingBytes());
return parameters;
}
密钥比公钥复杂的多,但也是通常所见到的格式的一小部份。
加载密钥的函数
private static RSAParameters LoadRsaPrivateKey()
{
string s = File.ReadAllText("pri.pem");
StringBuilder build = new StringBuilder(s);
build.Replace("-----BEGIN RSA PRIVATE KEY-----", "");
build.Replace("-----END RSA PRIVATE KEY-----", "");
s = build.ToString().Trim();
byte[] binKey = Convert.FromBase64String(s);
AsnParser parser = new AsnParser(binKey);
AsnKeyParser keyParser = new AsnKeyParser(parser);
RSAParameters privateKey = keyParser.ParsePkcsRSAPrivateKey();
return privateKey;
}
与加载公钥差不多
最后还有一点测试代码
private static void TestRsaKeys() // 测试的入口
{
RSAParameters publicKey = LoadRsaPublicKey();
RSAParameters privateKey = LoadRsaPrivateKey();
string s = TryEncrypt(publicKey); // 测试加密
System.Console.Out.WriteLine(s);
s = TryDecrypt(privateKey, s); // 测试解密
System.Console.Out.WriteLine(s);
}
private static string TryEncrypt(RSAParameters publicKey)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(publicKey);
string test = "用来测试加密的串";
byte[] bytes = Encoding.Unicode.GetBytes(test);
byte[] encryptedBytes = rsa.Encrypt(bytes, false);
string outString = Convert.ToBase64String(encryptedBytes);
return outString;
}
private static string TryDecrypt(RSAParameters privateKey, string src)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(privateKey);
byte[] bytes = Convert.FromBase64String(src);
byte[] decryptBytes = rsa.Decrypt(bytes, false);
string outString = Encoding.Unicode.GetString(decryptBytes);
return outString;
}
经过测试已经证明我的解码是成功的。感谢Jeffrey Walton!
值得一提的是AsnKeyParser中的ParseRSAPublicKey是可以直接解析-----BEGIN PUBLIC KEY-----打头的公钥。通常openssl生成的私钥都是-----BEGIN RSA PRIVATE KEY----- 打头的,所以还是要用我写的ParsePkcsRSAPrivateKey函数。
.NET导入openssl生成的公钥之BEGIN RSA PUBLIC KEY的更多相关文章
- yum 安装提示公钥安装失败,Public key for .x86_64.rpm is not instal 手动导入公钥方案
Linux 中yum 安装google-chrome-stable时,报错如下,提示公钥安装失败,原因是 GPG公钥获取失败,无法连接获取到 https://dl-ssl.google.com/lin ...
- Java中使用OpenSSL生成的RSA公私钥
RSA是什么:RSA公钥加密算法是1977年由Ron Rivest.Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的.RSA取名来自开发他们三者的名字.RSA是目前最有影响力的 ...
- 关于ssh-keygen 生成的key以“BEGIN OPENSSH PRIVATE KEY”开头
现在使用命令 ssh-keygen -t rsa 生成ssh,默认是以新的格式生成,id_rsa的第一行变成了"BEGIN OPENSSH PRIVATE KEY" 而不在是&q ...
- 使用OpenSSL生成证书
使用OpenSSL生成证书 下载安装openssl,进入/bin/下面,执行命令(把ssl目录下的openssl.cnf 拷贝到bin目录下)1.首先要生成服务器端的私钥(key文件):openssl ...
- 生成ssh公钥
部分内容参考:http://git.mydoc.io/?t=154712 1.在电脑桌面上右键,选择git Base here 2.生成ssh公钥 ssh-keygen -t rsa -C" ...
- Putty使用公钥认证时,报错:Disconnected: No supported authentication methods available(server sent:public key) 问题的解决
Putty使用公钥认证时,按照常规方法设置,一直报错:Disconnected: No supported authentication methods available (server sent: ...
- rsa字符串格式公钥转换python rsa库可识别的公钥形式
在爬虫分析的时候,经常在网页上看到如下格式的rsa公钥: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21 ...
- 在iOS中使用OpenSSL的Public Key 进行加密
这几天一直潜心于iOS开发,刚好把遇到的问题都记录一下.这次遇到的问题就是如果根据得到的Public Key在iOS 客户端对用户名和密码进行加密. Public Key如下: -----BEGIN ...
- 如何使用openssl生成RSA公钥和私钥对
在ubuntu上要使用openssl的话需要先进行安装,命令如下: sudo apt-get install openssl 安装完成就可以使用openssl了. 首先需要进入openssl的交互 ...
随机推荐
- source insight 注册码
分享一下google来的 呵呵 Source Insight,一个无比强大的工具.一个很好的查看代码的工具.到它的官网上去看一下,就知道,世界上基本上所有的大的软件公司,都在用这个工具.习惯了这个工具 ...
- nginx下面部署fast-cgi和C++【原】
1.cgi文件的代码 #include "fcgi_stdio.h" #include <stdlib.h> #include <stdio.h> int ...
- lhgdialog 与后台交互的对话框
官网:http://www.lhgdialog.com/ 1. 调用打开dialog的按钮 <span class="txtdec fs10 open"> <a ...
- 《JS高程》基本类型和引用类型的值学习笔记
ECMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值. 创建方式类似:创建一个变量并为其赋值. (1)基本类型值和引用类型值比较 基本类型值 引用类型值 简单的数据段 可能由 ...
- Debian 入门安装与配置1
Debian 入门安装与配置1 最近安装了多个发行版本的Linux,包括Ubuntu.Fedora.Centos和Debian,发现只有Debian在界面和稳定性等综合特性上表现最优,自己也最喜欢,所 ...
- Java Web学习(1): 客户端请求、服务器响应及其HTTP状态码
一JSP客户端请求 当浏览器请求一个网页时,它会向网络服务器发送一系列不能被直接读取的信息,因为这些信息是作为HTTP信 息头的一部分来传送的.我们可以查阅HTTP协议来获得更多的信息. 下表列出了浏 ...
- (6)java的内存泄露问题
一:什么是内存泄露--->Java的一个最显著的优势是内存管理.你只需要简单的创建对象而不需要负责释放空间,因为Java的垃圾回收器会负责内存的回收.然而,情况并不是这样简单,内存泄露还是经常会 ...
- caffe: test code for PETA dataset
test code for PETA datasets .... #ifdef WITH_PYTHON_LAYER #include "boost/python.hpp" name ...
- What are the main disadvantages of Java Server Faces 2.0?
http://stackoverflow.com/questions/3623911/what-are-the-main-disadvantages-of-java-server-faces-2-0/ ...
- Memory Barriers ,cache-coherency
http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.07.23a.pdf Shared-Memory Synchroniza ...