-
Notifications
You must be signed in to change notification settings - Fork 0
/
RsaKeyConverter.cs
100 lines (85 loc) · 3.27 KB
/
RsaKeyConverter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
namespace XmlPemConverter;
public static class RsaKeyConverter
{
public static string XmlToPem(string xml)
{
using var rsa = RSA.Create();
rsa.FromXmlString(xml);
AsymmetricCipherKeyPair? keyPair = rsa.GetKeyPair(); // try get private and public key pair
if (keyPair != null) // if XML RSA key contains private key
{
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
return FormatPem(privateKeyInfo.GetEncoded().ToBase64(), "RSA PRIVATE KEY");
}
RsaKeyParameters? publicKey = rsa.GetPublicKey(); // try get public key
if (publicKey is null) throw new InvalidKeyException("Invalid RSA Xml Key");
SubjectPublicKeyInfo publicKeyInfo =
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
return FormatPem(publicKeyInfo.GetEncoded().ToBase64(), "PUBLIC KEY");
}
public static string PemToXml(string pem)
{
if (pem.StartsWith("-----BEGIN RSA PRIVATE KEY-----")
|| pem.StartsWith("-----BEGIN PRIVATE KEY-----"))
{
return GetXmlRsaKey(pem, obj =>
{
if ((obj as RsaPrivateCrtKeyParameters) != null)
return DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)obj);
var keyPair = (AsymmetricCipherKeyPair)obj;
return DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)keyPair.Private);
}, rsa => rsa.ToXmlString(true));
}
if (pem.StartsWith("-----BEGIN PUBLIC KEY-----"))
{
return GetXmlRsaKey(pem, obj =>
{
var publicKey = (RsaKeyParameters)obj;
return DotNetUtilities.ToRSA(publicKey);
}, rsa => rsa.ToXmlString(false));
}
throw new InvalidKeyException("Unsupported PEM format...");
}
private static string GetXmlRsaKey(string pem, Func<object, RSA> getRsa, Func<RSA, string> getKey)
{
using var ms = new MemoryStream();
using var sw = new StreamWriter(ms);
using var sr = new StreamReader(ms);
sw.Write(pem);
sw.Flush();
ms.Position = 0;
var pr = new PemReader(sr);
object keyPair = pr.ReadObject();
using RSA rsa = getRsa(keyPair);
string xml = getKey(rsa);
return xml;
}
private static string FormatPem(string pem, string keyType)
{
var sb = new StringBuilder();
sb.Append($"-----BEGIN {keyType}-----\n");
var line = 1;
const int width = 64;
while ((line - 1) * width < pem.Length)
{
int startIndex = (line - 1) * width;
int len = line * width > pem.Length
? pem.Length - startIndex
: width;
sb.Append($"{pem.Substring(startIndex, len)}\n");
line++;
}
sb.Append($"-----END {keyType}-----\n");
return sb.ToString();
}
}