我正在尝试将一段Java代码移植到.NET中,该代码采用Base64编码的字符串,将其转换为字节数组,然后使用其制作X.509证书以获取RSA的模数和指数加密。 这是我要转换的Java代码:
byte[] externalPublicKey = Base64.decode("base 64 encoded string");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(externalPublicKey);
Key publicKey = keyFactory.generatePublic(publicKeySpec);
RSAPublicKey pbrtk = (java.security.interfaces.RSAPublicKey) publicKey;
BigInteger modulus = pbrtk.getModulus();
BigInteger pubExp = pbrtk.getPublicExponent();
我一直在尝试找出将其转换为.NET的最佳方法。到目前为止,我已经提出了这个建议:
byte[] bytes = Convert.FromBase64String("base 64 encoded string");
X509Certificate2 x509 = new X509Certificate2(bytes);
RSA rsa = (RSA)x509.PrivateKey;
RSAParameters rsaParams = rsa.ExportParameters(false);
byte[] modulus = rsaParams.Modulus;
byte[] exponent = rsaParams.Exponent;
在我看来这应该可以工作,但是当我使用Java代码中以base 64编码的字符串生成X509证书时,它将引发CryptographicException。我收到的确切消息是:
找不到请求的对象。
Java的X.509实现只是与.NET不兼容,还是我从Java转换为.NET时做错了什么?
答案 0 :(得分:0)
在.NET Core 3.0及更高版本中,有一种ImportSubjectPublicKeyInfo方法可以直接导入此类密钥。
代码如下:
var bytes = Convert.FromBase64String("encoded key");
var rsa = RSA.Create();
rsa.ImportSubjectPublicKeyInfo(bytes, out _);
var rsaParams = rsa.ExportParameters(false);
答案 1 :(得分:-1)
例如
var subjectPublicKeyInfo = new SubjectPublicKeyInfo(your bytes);
var publicKey = subjectPublicKeyInfo.GetPublicKey();
using (var rsa = new RSACryptoServiceProvider())
{
RSAParameters parameters = new RSAParameters()
{
Modulus = publicKey.Item1,
Exponent = publicKey.Item2
};
rsa.ImportParameters(parameters);
/*
do something
*/
}
SubjectPublicKeyInfo类和DER
类
/// <summary>
/// DER解析
/// </summary>
public class DER : IDisposable
{
private bool disposedValue;
private BinaryReader reader;
public DER(byte[] bytes)
{
MemoryStream stream = new MemoryStream(bytes);
reader = new BinaryReader(stream);
}
public bool CanRead => reader.BaseStream.Position < reader.BaseStream.Length;
private ValueType ReadType()
{
return (ValueType)reader.ReadByte();
}
private int ReadLength()
{
int length = reader.ReadByte();
//检查第7位是否是1,如果是,则指示该内容长度大于127字节,则此字节6-0为实际的内容占用的字节
if ((length & 0b10000000) == 0b10000000)
{
//获取长度字节的长度
int count = length & 0b01111111;
byte[] bytes = new byte[count];
//指向内容的长度
reader.Read(bytes, 0, bytes.Length);
//翻转顺序
Array.Reverse(bytes);
length = LengthBytesToInt(bytes);
}
return length;
}
/// <summary>
/// 根据文档显示,长度不应该超过 256^126 ,即两个字节
/// </summary>
/// <param name="lengthBytes"></param>
/// <returns></returns>
private int LengthBytesToInt(byte[] lengthBytes)
{
if (lengthBytes.Length > 2)
throw new ArgumentOutOfRangeException($"length {lengthBytes.Length} too big.");
int value = 0;
for (int i = 0; i < lengthBytes.Length; i++)
{
value = (value << 8) | lengthBytes[i];
}
return value;
}
public ValueTuple<ValueType, byte[]> ReadValue()
{
ValueType type = ReadType();
byte[] value = new byte[ReadLength()];
reader.Read(value, 0, value.Length);
ValueTuple<ValueType, byte[]> wrapper = new ValueTuple<ValueType, byte[]>(type, value);
return wrapper;
}
public enum ValueType
{
BOOLEAN = 0x01,
INTEGER = 0x02,
BIT_STRING = 0x03,
OCTET_STRING = 0x04,
NULL = 0x05,
OBJECT_IDENTIFIER = 0x06,
UTF8String = 0x0c,
PrintableString = 0x13,
TeletexString = 0x14,
IA5String = 0x16,
BMPString = 0x1e,
SEQUENCE = 0x30,
SET = 0x31
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
reader.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
/// <summary>
/// 兼容 Java X.509 SubjectPublicKeyInfo DER
/// </summary>
public class SubjectPublicKeyInfo
{
private DER der;
private readonly byte[] RSA_OID = new byte[] { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
public SubjectPublicKeyInfo(byte[] derBytes)
{
der = new DER(derBytes);
}
/// <summary>
/// 获取公钥
/// </summary>
/// <returns>modulus and exponent 返回模数和指数</returns>
public ValueTuple<byte[], byte[]> GetPublicKey()
{
//获取主序列
var wrapper1 = der.ReadValue();
if (wrapper1.Item1 != DER.ValueType.SEQUENCE)
{
throw new InvalidDataException();
}
var sequence1 = new DER(wrapper1.Item2);
var wrapper2 = sequence1.ReadValue();
//检查第一个结构体是否存在
if (wrapper2.Item1 != DER.ValueType.SEQUENCE)
{
throw new InvalidDataException();
}
var sequence2 = new DER(wrapper2.Item2);
var wrapper3 = sequence2.ReadValue();
if (wrapper3.Item1 != DER.ValueType.OBJECT_IDENTIFIER)
{
throw new InvalidDataException();
}
if (Enumerable.SequenceEqual(wrapper3.Item2, RSA_OID) == false)
{
throw new InvalidDataException();
}
var wrapper4 = sequence1.ReadValue();
if (wrapper4.Item2.First() != 0x00)
{
throw new InvalidDataException();
}
//这里有个不明意义的0x00
var sequence3 = new DER(wrapper4.Item2.Skip(1).ToArray());
var wrapper5 = sequence3.ReadValue();
if (wrapper5.Item1 != DER.ValueType.SEQUENCE)
{
throw new InvalidDataException();
}
var sequence4 = new DER(wrapper5.Item2);
var wrapper6 = sequence4.ReadValue();
if (wrapper6.Item1 != DER.ValueType.INTEGER)
{
throw new InvalidDataException();
}
var integer1 = wrapper6.Item2.First() == 0x00 ? wrapper6.Item2.Skip(1).ToArray() : wrapper6.Item2;
var wrapper7 = sequence4.ReadValue();
if (wrapper7.Item1 != DER.ValueType.INTEGER)
{
throw new InvalidDataException();
}
var integer2 = wrapper7.Item2;
return new ValueTuple<byte[], byte[]>(integer1, integer2);
}
}