.netcore中使用openssl的公钥私钥进行加解密
这篇博文分享的是C#中使用OpenSSL的公钥加密/私钥解密一文中的解决方法在.netcore中的改进。之前的博文针对的是.NETFramework,加解密用的是RSACryptoServiceProvider。虽然在corefx(.NETCoreFramework)中也有RSACryptoServiceProvider,但它目前只支持Windows,不能跨平台。
之前的newRSACryptoServiceProvider();代码在mac上运行,会报下面的错误:
System.PlatformNotSupportedException:Operationisnotsupportedonthisplatform.
atSystem.Security.Cryptography.RSACryptoServiceProvider..ctor()
要解决这个问题,需要改用System.Security.Cryptography.RSA.Create()工厂方法,使用它之后,在Windows上创建的是System.Security.Cryptography.RSACng的实例,在Mac与Linux上创建的是System.Security.Cryptography.RSAOpenSsl的实例,它们都继承自System.Security.Cryptography.RSA抽象类。
使用了RSA.Create()之后,带来了一个问题,RSA中没有RSACryptoServiceProvider中的以下2个签名的加解密方法。
publicbyte[]Encrypt(byte[]rgb,boolfOAEP);
publicbyte[]Decrypt(byte[]rgb,boolfOAEP);
只有
publicabstractbyte[]Encrypt(byte[]data,RSAEncryptionPaddingpadding);
publicabstractbyte[]Decrypt(byte[]data,RSAEncryptionPaddingpadding);
调用时它们时需要传递RSAEncryptionPadding类型的参数值:
但对于openssl生成的公钥私钥不知道选择哪种RSAEncryptionPadding,只能采取笨方法——一个一个试试,试出来的结果是RSAEncryptionPadding.Pkcs1。
openssl的公钥与私钥是在Mac上通过下面的2个命令生成的:
opensslgenrsa-outrsa_1024_priv.pem102
opensslrsa-pubout-inrsa_1024_priv.pem-outrsa_1024_pub.peml
(注:一定要用openssl命令,用ssh-keygen-trsa命令生成的公钥私钥是不行的)
修改这两个地方(RSA.Create与RSAEncryptionPadding.Pkcs1)之后,就可以在.netcore上使用openssl的公钥私钥进行加解密了,以下是测试时所用的完整代码(.netcore控制台程序)。经测试,在Windows,macOS,LinuxUbuntu上都能成功进行加解密。
Program.cs
复制代码
usingSystem;
usingSystem.IO;
usingSystem.Security.Cryptography;
usingSystem.Text;
namespaceTryRsa
{
publicclassProgram
{
//opensslgenrsa-outrsa_1024_priv.pem1024
privatestaticreadonlystring_privateKey=@"MIICXgIBAAKBgQC0xP5HcfThSQr43bAMoopbzcCyZWE0xfUeTA4Nx4PrXEfDvybJ
EIjbU/rgANAty1yp7g20J7+wVMPCusxftl/d0rPQiCLjeZ3HtlRKld+9htAZtHFZ
osV29h/hNE9JkxzGXstaSeXIUIWquMZQ8XyscIHhqoOmjXaCv58CSRAlAQIDAQAB
AoGBAJtDgCwZYv2FYVk0ABw6F6CWbuZLUVykks69AG0xasti7Xjh3AximUnZLefs
iuJqg2KpRzfv1CM+Cw5cp2GmIVvRqq0GlRZGxJ38AqH9oyUa2m3TojxWapY47zye
PYEjWwRTGlxUBkdujdcYj6/dojNkm4azsDXl9W5YaXiPfbgJAkEA4rlhSPXlohDk
FoyfX0v2OIdaTOcVpinv1jjbSzZ8KZACggjiNUVrSFV3Y4oWom93K5JLXf2mV0Sy
80mPR5jOdwJBAMwciAk8xyQKpMUGNhFX2jKboAYY1SJCfuUnyXHAPWeHp5xCL2UH
tjryJp/Vx8TgsFTGyWSyIE9R8hSup+32rkcCQBe+EAkC7yQ0np4Z5cql+sfarMMm
4+Z9t8b4N0a+EuyLTyfs5Dtt5JkzkggTeuFRyOoALPJP0K6M3CyMBHwb7WsCQQCi
TM2fCsUO06fRQu8bO1A1janhLz3K0DU24jw8RzCMckHE7pvhKhCtLn+n+MWwtzl/
L9JUT4+BgxeLepXtkolhAkEA2V7er7fnwww.baiyuewang.netEuL0+kKIjmOm5F3kvMIDh9YC1JwLGSvu
1fnzxK34QwSdxgQRF1dfIKJw73lClQpHZfQxL/2XRG8IoA==".Replace("\n","");
//opensslrsa-pubout-inrsa_1024_priv.pem-outrsa_1024_pub.pem
privatestaticreadonlystring_publicKey=@"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0xP5HcfThSQr43bAMoopbzcCy
ZWE0xfUeTA4Nx4PrXEfDvybJEIjbU/rgANAty1yp7g20J7+wVMPCusxftl/d0rPQ
iCLjeZ3HtlRKld+9htAZtHFZosV29h/hNE9JkxzGXstaSeXIUIWquMZQ8XyscIHh
qoOmjXaCv58CSRAlAQIDAQAB".Replace("\n","");
publicstaticvoidMain(string[]args)
{
varplainText="cnblogs.com";
//Encrypt
RSArsa=CreateRsaFromPublicKey(_publicKey);
varplainTextBytes=Encoding.UTF8.GetBytes(plainText);
varcipherBytes=rsa.Encrypt(plainTextBytes,RSAEncryptionPadding.Pkcs1);
varcipher=Convert.ToBasewww.wang027.com64String(cipherBytes);
Console.WriteLine($"{nameof(cipher)}:{cipher}");
//Decrypt
rsa=CreateRsaFromPrivateKey(_privateKey);
cipherBytes=System.Convert.FromBase64String(cipher);
plainTextBytes=rsa.Decrypt(cipherBytes,RSAEncryptionPadding.Pkcs1);
plainText=Encoding.UTF8.GetString(plainTextBytes);
Console.WriteLine($"{nameof(plainText)}:{plainText}");
}privatestaticRSACreateRsaFromPrivateKey(stringprivateKey)
{
varprivateKeyBits=System.Convert.FromBase64String(privateKey);
varrsa=RSA.Create();
varRSAparams=newRSAParameters();
using(varbinr=newBinaryReader(newMemoryStream(privateKeyBits)))
{
bytebt=0;
ushorttwobytes=0;
twobytes=binr.ReadUInt16();
if(twobytes==0x8130)
binr.ReadByte();
elseif(twobytes==0x8230)
binr.ReadInt16();
else
thrownewException("Unexpectedvaluereadbinr.ReadUInt16()");
twobytes=binr.ReadUInt16();
if(twobytes!=0x0102)
thrownewException("Unexpectedversion");
bt=binr.ReadByte();
if(bt!=0x00)
thrownewException("Unexpectedvaluereadbinr.ReadByte()");
RSAparams.Modulus=binr.ReadBytes(GetIntegerSize(binr));
RSAparams.Exponent=binr.ReadBytes(GetIntegerSize(binr));
RSAparams.D=binr.ReadBytes(GetIntegerSize(binr));
RSAparams.P=binr.ReadBytes(GetIntegerSize(binr));
RSAparams.Q=binr.ReadBytes(GetIntegerSize(binr));
RSAparams.DP=binr.ReadBytes(GetIntegerSize(binr));
RSAparams.DQ=binr.ReadBytes(GetIntegerSize(binr));
RSAparams.InverseQ=binr.ReadBytes(GetIntegerSize(binr));
}
rsa.ImportParameters(RSAparams);
returnrsa;
}
privatestaticintGetIntegerSize(BinaryReaderbinr)
{
bytebt=0;
bytelowbyte=0x00;
bytehighbyte=0x00;
intcount=0;
bt=binr.ReadByte();
if(bt!=0x02)
return0;
bt=binr.ReadByte();
if(bt==0x81)
count=binr.ReadByte();
else
if(bt==0x82)
{
highbyte=binr.ReadByte();
lowbyte=binr.ReadByte();
byte[]modint={lowbyte,highbyte,0x00,0x00};
count=BitConverter.ToInt32(modint,0);
}
else
{
count=bt;
}
while(binr.ReadByte()==0x00)
{
count-=1;
}
binr.BaseStream.Seek(-1,SeekOrigin.Current);
returncount;
}
privatestaticRSACreateRsaFromPublicKey(stringpublicKeyString)
{
byte[]SeqOID={0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00};
byte[]x509key;
byte[]seq=newbyte[15];
intx509size;
x509key=Convert.FromBase64String(publicKeyString);
x509size=x509key.Length;
using(varmem=newMemoryStream(x509key))
{
using(varbinr=newBinaryReader(mem))
{
bytebt=0;
ushorttwobytes=0;
twobytes=binr.ReadUInt16();
if(twobytes==0x8130)
binr.ReadByte();
elseif(twobytes==0x8230)
binr.ReadInt16();
else
returnnull;
seq=binr.ReadBytes(15);
if(!CompareBytearrays(seq,SeqOID))
returnnull;
twobytes=binr.ReadUInt16();
if(twobytes==0x8103)
binr.ReadByte();
elseif(twobytes==0x8203)
binr.ReadInt16();
else
returnnull;
bt=binr.ReadByte();
if(bt!=0x00)
returnnull;
twobytes=binr.ReadUInt16();
if(twobytes==0x8130)
binr.ReadByte();
elseif(twobytes==0x8230)
binr.ReadInt16();
else
returnnull;
twobytes=binr.ReadUInt16();
bytelowbyte=0x00;
bytehighbyte=0x00;
if(twobytes==0x8102)
lowbyte=binr.ReadByte();
elseif(twobytes==0x8202)
{
highbyte=binr.ReadByte();
lowbyte=binr.ReadByte();
}
else
returnnull;
byte[]modint={lowbyte,highbyte,0x00,0x00};
intmodsize=BitConverter.ToInt32(modint,0);
intfirstbyte=binr.PeekChar();
if(firstbyte==0x00)
{
binr.ReadByte();
modsize-=1;
}
byte[]modulus=binr.ReadBytes(modsize);
if(binr.ReadByte()!=0x02)
returnnull;
intexpbytes=(int)binr.ReadByte();
byte[]exponent=binr.ReadBytes(expbytes);
varrsa=RSA.Create();
varrsaKeyInfo=newRSAParameters
{
Modulus=modulus,
Exponent=exponent
};
rsa.ImportParameters(rsaKeyInfo);
returnrsa;
}
}
}
privatestaticboolCompareBytearrays(byte[]a,byte[]b)
{
if(a.Length!=b.Length)
returnfalse;
inti=0;
foreach(bytecina)
{
if(c!=b[i])
returnfalse;
i++;
}
returntrue;
}
}
}
复制代码
project.json
复制代码
{
"version":"1.0.0-",
"buildOptions":{
"emitEntryPoint":true
},
"dependencies":{
"Microsoft.NETCore.App":{
"type":"platform",
"version":"1.1.0-preview1-001100-00"
},
"System.Security.Cryptography.Algorithms":"4.3.0-preview1-24530-04"
},
"frameworks":{
"netcoreapp1.1":{
"imports":"dnxcore50"
}
}
}
|
|