我有一个看起来像这样的私钥:
-----BEGIN RSA PRIVATE KEY----- 一些私钥数据 -----END RSA PRIVA
我需要在我的 C# 项目中使用此密钥,但我找不到任何示例如何以这种格式使用密钥。谢谢
我有一个看起来像这样的私钥:
-----BEGIN RSA PRIVATE KEY----- 一些私钥数据 -----END RSA PRIVA
我需要在我的 C# 项目中使用此密钥,但我找不到任何示例如何以这种格式使用密钥。谢谢
private RSACryptoServiceProvider CreateRsaProviderFromPrivateKey(string privateKey)
{
var privateKeyBits = System.Convert.FromBase64String(privateKey);
var RSA = new RSACryptoServiceProvider();
var RSAparams = new RSAParameters();
using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits)))
{
byte bt = 0;
ushort twobytes = 0;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130)
binr.ReadByte();
else if (twobytes == 0x8230)
binr.ReadInt16();
else
throw new Exception("Unexpected value read binr.ReadUInt16()");
twobytes = binr.ReadUInt16();
if (twobytes != 0x0102)
throw new Exception("Unexpected version");
bt = binr.ReadByte();
if (bt != 0x00)
throw new Exception("Unexpected value read binr.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);
return RSA;
}
private int GetIntegerSize(BinaryReader binr)
{
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02)
return 0;
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);
return count;
}
所有主要的 .NET/C# 加密库(如 BouncyCastle 或 SecureBlackbox [商业])都应支持这种格式,以及加载密钥的操作(加密/解密/签名/验证)。
虽然在较早的帖子中,当我在今年早些时候遇到同样的挑战时,我还是会用我自己的答案来回答这个问题。我编写了一个用于处理 PEM 密钥、加密、解密、签名和签名验证的库。它附带了一个完整的示例解决方案(Load-Encrypt-Decrypt-Save),因此您应该能够立即开始运行。
https://github.com/jrnker/CSharp-easy-RSA-PEM
干杯,克里斯托弗
下面我写的关于数字签名的文章在 c# 中给出了一个解决方案(不需要额外的库)。该代码显示了如何将 PEM 格式的 RSA 私钥转换为 .NET RSACryptoServiceProvider 类使用的 XML 格式。
使用 Atlando 加密货币地理服务,您的身份将在注册后存储在您的浏览器中。在每次请求时,与我们签订的合同都会通过此身份使用您的私钥进行签名和加密。这篇文章解释了它是如何工作的。
下面的代码通过比较原始版本和签名版本在 C#(RSACryptoServiceProvider 类)中提供了身份验证过程的实现。模数来自 PEM 格式的 RSA 公钥(指数 AQAB)。
private static bool Verify(string original, string signature, string modulus)
{
SHA256Managed sha = new SHA256Managed();
byte[] bytes = Encoding.UTF8.GetBytes(original);
byte[] hash = sha.ComputeHash(bytes);
sha.Clear();
byte[] signed = new byte[signature.Length/2];
for (int i = 0; i < signature.Length; i += 2)
{
signed[i/2] = Convert.ToByte(Convert.ToInt32(signature.Substring(i, 2), 16));
}
string key = "<RSAKeyValue><Modulus>" + modulus + "</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(key);
RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(rsa);
RSADeformatter.SetHashAlgorithm("SHA256");
return RSADeformatter.VerifySignature(hash, signed);
}
}
public static string Modulus(string pem)
{
byte[] x509der = Convert.FromBase64String(pem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", ""));
byte[] seqOID = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
MemoryStream ms = new MemoryStream(x509der);
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) return null; //is the object identifier rsaEncryption PKCS#1?
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.ToXmlString(false).Replace("<RSAKeyValue><Modulus>", "").Replace("</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>", "");
}
}
}
}
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;
}
首先,您需要使用Bouncy Castle库将私钥转换为 RSA 参数的形式。然后您需要将 RSA 参数作为私钥传递给 RSA 算法。最后,您使用JWT库对令牌进行编码和签名。
public string GenerateJWTToken(string rsaPrivateKey)
{
var rsaParams = GetRsaParameters(rsaPrivateKey);
var encoder = GetRS256JWTEncoder(rsaParams);
// create the payload according to your need
var payload = new Dictionary<string, object>
{
{ "iss", ""},
{ "sub", "" },
// and other key-values
};
var token = encoder.Encode(payload, new byte[0]);
return token;
}
private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
{
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(rsaParams);
var algorithm = new RS256Algorithm(csp, csp);
var serializer = new JsonNetSerializer();
var urlEncoder = new JwtBase64UrlEncoder();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder;
}
private static RSAParameters GetRsaParameters(string rsaPrivateKey)
{
var byteArray = Encoding.ASCII.GetBytes(rsaPrivateKey);
using (var ms = new MemoryStream(byteArray))
{
using (var sr = new StreamReader(ms))
{
// use Bouncy Castle to convert the private key to RSA parameters
var pemReader = new PemReader(sr);
var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
return DotNetUtilities.ToRSAParameters(keyPair.Private as RsaPrivateCrtKeyParameters);
}
}
}
ps:RSA 私钥的格式如下:
-----开始 RSA 私钥-----
{base64 格式值}
-----结束 RSA 私钥-----