不幸的是,C#不提供任何简单的方法来做到这一点。但是,这将正确解码的X509公钥(确保为Base64首先解码x509key参数):
public static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509key)
{
byte[] SeqOID = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
MemoryStream ms = new MemoryStream(x509key);
BinaryReader reader = new BinaryReader(ms);
if (reader.ReadByte() == 0x30)
ReadASNLength(reader); //skip the size
else
return null;
int identifierSize = 0; //total length of Object Identifier section
if (reader.ReadByte() == 0x30)
identifierSize = ReadASNLength(reader);
else
return null;
if (reader.ReadByte() == 0x06) //is the next element an object identifier?
{
int oidLength = ReadASNLength(reader);
byte[] oidBytes = new byte[oidLength];
reader.Read(oidBytes, 0, oidBytes.Length);
if (oidBytes.SequenceEqual(SeqOID) == false) //is the object identifier rsaEncryption PKCS#1?
return null;
int remainingBytes = identifierSize - 2 - oidBytes.Length;
reader.ReadBytes(remainingBytes);
}
if (reader.ReadByte() == 0x03) //is the next element a bit string?
{
ReadASNLength(reader); //skip the size
reader.ReadByte(); //skip unused bits indicator
if (reader.ReadByte() == 0x30)
{
ReadASNLength(reader); //skip the size
if (reader.ReadByte() == 0x02) //is it an integer?
{
int modulusSize = ReadASNLength(reader);
byte[] modulus = new byte[modulusSize];
reader.Read(modulus, 0, modulus.Length);
if (modulus[0] == 0x00) //strip off the first byte if it's 0
{
byte[] tempModulus = new byte[modulus.Length - 1];
Array.Copy(modulus, 1, tempModulus, 0, modulus.Length - 1);
modulus = tempModulus;
}
if (reader.ReadByte() == 0x02) //is it an integer?
{
int exponentSize = ReadASNLength(reader);
byte[] exponent = new byte[exponentSize];
reader.Read(exponent, 0, exponent.Length);
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters();
RSAKeyInfo.Modulus = modulus;
RSAKeyInfo.Exponent = exponent;
RSA.ImportParameters(RSAKeyInfo);
return RSA;
}
}
}
}
return null;
}
public static int ReadASNLength(BinaryReader reader)
{
//Note: this method only reads lengths up to 4 bytes long as
//this is satisfactory for the majority of situations.
int length = reader.ReadByte();
if ((length & 0x00000080) == 0x00000080) //is the length greater than 1 byte
{
int count = length & 0x0000000f;
byte[] lengthBytes = new byte[4];
reader.Read(lengthBytes, 4 - count, count);
Array.Reverse(lengthBytes); //
length = BitConverter.ToInt32(lengthBytes, 0);
}
return length;
}
上面的代码是基于关闭的this question(这只是工作的一些关键尺寸)。上面的代码几乎适用于任何RSA密钥大小,并且已经用您提供的密钥以及2048位和4096位密钥进行了测试。
另一种解决方案是使用工具生成证书(XCA是一个好的方法),将证书导出到p12(PKCS12)文件,然后在Java和C#中加载证书以获取密钥。
在C#中,您可以使用X509Certificate2
类加载PKCS12文件。
X509Certificate2 cert = new X509Certificate2(certificateFile, certificatePassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
RSACryptoServiceProvider provider1 = (RSACryptoServiceProvider)cert.PublicKey.Key;
RSACryptoServiceProvider provider2 = (RSACryptoServiceProvider)cert.PrivateKey;
在Java中,您可以使用KeyStore
类加载PKCS12文件。
@gpa:未接受此答案。它不适合你吗?如果有问题,您能否提供一些解释? – Syon
对不起,我迟到了,但解决方案不适合我,因为公钥由java生成并在文件中序列化。 Dotnet应用程序将读取相同的公钥并构造其PublicKey ... – gpa
什么是生成特定的Java代码然后将公钥序列化为文件? (你可以将它添加到你的问题中)Dotnet读取Java序列化对象并不容易,但如果你将公钥保存为标准格式,那么应该可以在C#中重新构建它。 – Syon