How to get RSACryptoServiceProvider public and private key only in c#
I am running below code to get public and private key only, but it seems it outputs the whole XML format. I only need to output the keys as shown in Public and Private Key demo
static RSACryptoServiceProvider rsa;
private RSAParameters _privateKey;
private RSAParameters _publicKey;
public RSACrypto()
{
rsa = new RSACryptoServiceProvider(2048);
_privateKey = rsa.ExportParameters(true);
_publicKey = rsa.ExportParameters(false);
}
public string GetPublicKeyString()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _publicKey);
return sw.ToString();
}
public string GetPrivateKeyString()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _privateKey);
return sw.ToString();
}
c# asp.net rsa public-key-encryption
add a comment |
I am running below code to get public and private key only, but it seems it outputs the whole XML format. I only need to output the keys as shown in Public and Private Key demo
static RSACryptoServiceProvider rsa;
private RSAParameters _privateKey;
private RSAParameters _publicKey;
public RSACrypto()
{
rsa = new RSACryptoServiceProvider(2048);
_privateKey = rsa.ExportParameters(true);
_publicKey = rsa.ExportParameters(false);
}
public string GetPublicKeyString()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _publicKey);
return sw.ToString();
}
public string GetPrivateKeyString()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _privateKey);
return sw.ToString();
}
c# asp.net rsa public-key-encryption
See the second answer of this question. stackoverflow.com/questions/14047532/…
– NthDeveloper
Jan 1 at 20:47
@NthDeveloper: That answer has nothing to do with this question.
– James K Polk
Jan 1 at 21:49
1
You can use the Bouncycastle C# library which is the easiest solution or you can try to hand code the generation of ASN.1 objects yourself which is doable but much harder.
– James K Polk
Jan 1 at 21:52
In .NET Core 3.0 (preview 1) you can get the binary data with rsa.ExportSubjectPublicKeyInfo() and rsa.ExportRSAPrivateKey(), I’ll post an answer tomorrow.
– bartonjs
Jan 2 at 3:49
@JamesKPolk thank you, I used BouncyCastle C# library, please write it as an answer to close this thread.
– ARH
Jan 2 at 10:48
add a comment |
I am running below code to get public and private key only, but it seems it outputs the whole XML format. I only need to output the keys as shown in Public and Private Key demo
static RSACryptoServiceProvider rsa;
private RSAParameters _privateKey;
private RSAParameters _publicKey;
public RSACrypto()
{
rsa = new RSACryptoServiceProvider(2048);
_privateKey = rsa.ExportParameters(true);
_publicKey = rsa.ExportParameters(false);
}
public string GetPublicKeyString()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _publicKey);
return sw.ToString();
}
public string GetPrivateKeyString()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _privateKey);
return sw.ToString();
}
c# asp.net rsa public-key-encryption
I am running below code to get public and private key only, but it seems it outputs the whole XML format. I only need to output the keys as shown in Public and Private Key demo
static RSACryptoServiceProvider rsa;
private RSAParameters _privateKey;
private RSAParameters _publicKey;
public RSACrypto()
{
rsa = new RSACryptoServiceProvider(2048);
_privateKey = rsa.ExportParameters(true);
_publicKey = rsa.ExportParameters(false);
}
public string GetPublicKeyString()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _publicKey);
return sw.ToString();
}
public string GetPrivateKeyString()
{
var sw = new StringWriter();
var xs = new XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, _privateKey);
return sw.ToString();
}
c# asp.net rsa public-key-encryption
c# asp.net rsa public-key-encryption
asked Jan 1 at 18:28
ARHARH
5332932
5332932
See the second answer of this question. stackoverflow.com/questions/14047532/…
– NthDeveloper
Jan 1 at 20:47
@NthDeveloper: That answer has nothing to do with this question.
– James K Polk
Jan 1 at 21:49
1
You can use the Bouncycastle C# library which is the easiest solution or you can try to hand code the generation of ASN.1 objects yourself which is doable but much harder.
– James K Polk
Jan 1 at 21:52
In .NET Core 3.0 (preview 1) you can get the binary data with rsa.ExportSubjectPublicKeyInfo() and rsa.ExportRSAPrivateKey(), I’ll post an answer tomorrow.
– bartonjs
Jan 2 at 3:49
@JamesKPolk thank you, I used BouncyCastle C# library, please write it as an answer to close this thread.
– ARH
Jan 2 at 10:48
add a comment |
See the second answer of this question. stackoverflow.com/questions/14047532/…
– NthDeveloper
Jan 1 at 20:47
@NthDeveloper: That answer has nothing to do with this question.
– James K Polk
Jan 1 at 21:49
1
You can use the Bouncycastle C# library which is the easiest solution or you can try to hand code the generation of ASN.1 objects yourself which is doable but much harder.
– James K Polk
Jan 1 at 21:52
In .NET Core 3.0 (preview 1) you can get the binary data with rsa.ExportSubjectPublicKeyInfo() and rsa.ExportRSAPrivateKey(), I’ll post an answer tomorrow.
– bartonjs
Jan 2 at 3:49
@JamesKPolk thank you, I used BouncyCastle C# library, please write it as an answer to close this thread.
– ARH
Jan 2 at 10:48
See the second answer of this question. stackoverflow.com/questions/14047532/…
– NthDeveloper
Jan 1 at 20:47
See the second answer of this question. stackoverflow.com/questions/14047532/…
– NthDeveloper
Jan 1 at 20:47
@NthDeveloper: That answer has nothing to do with this question.
– James K Polk
Jan 1 at 21:49
@NthDeveloper: That answer has nothing to do with this question.
– James K Polk
Jan 1 at 21:49
1
1
You can use the Bouncycastle C# library which is the easiest solution or you can try to hand code the generation of ASN.1 objects yourself which is doable but much harder.
– James K Polk
Jan 1 at 21:52
You can use the Bouncycastle C# library which is the easiest solution or you can try to hand code the generation of ASN.1 objects yourself which is doable but much harder.
– James K Polk
Jan 1 at 21:52
In .NET Core 3.0 (preview 1) you can get the binary data with rsa.ExportSubjectPublicKeyInfo() and rsa.ExportRSAPrivateKey(), I’ll post an answer tomorrow.
– bartonjs
Jan 2 at 3:49
In .NET Core 3.0 (preview 1) you can get the binary data with rsa.ExportSubjectPublicKeyInfo() and rsa.ExportRSAPrivateKey(), I’ll post an answer tomorrow.
– bartonjs
Jan 2 at 3:49
@JamesKPolk thank you, I used BouncyCastle C# library, please write it as an answer to close this thread.
– ARH
Jan 2 at 10:48
@JamesKPolk thank you, I used BouncyCastle C# library, please write it as an answer to close this thread.
– ARH
Jan 2 at 10:48
add a comment |
2 Answers
2
active
oldest
votes
The Bouncycastle C# library has some helper classes that can make this relatively easy. It is not well documented unfortunately. Here is an example:
using System;
using System.IO;
using System.Security.Cryptography;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
namespace ExportToStandardFormats
{
class MainClass
{
public static void Main(string args)
{
var rsa = new RSACryptoServiceProvider(2048);
var rsaKeyPair = DotNetUtilities.GetRsaKeyPair(rsa);
var writer = new StringWriter();
var pemWriter = new PemWriter(writer);
pemWriter.WriteObject(rsaKeyPair.Public);
pemWriter.WriteObject(rsaKeyPair.Private);
Console.WriteLine(writer);
}
}
}
add a comment |
Starting in .NET Core 3.0, this is (largely) built-in.
Writing SubjectPublicKeyInfo and RSAPrivateKey
.NET Core 3.0 built-in API
The output of the builtin API is the binary representation, to make them PEM you need to output the header, footer, and base64:
private static string MakePem(byte ber, string header)
{
StringBuilder builder = new StringBuilder("-----BEGIN ");
builder.Append(header);
builder.AppendLine("-----");
string base64 = Convert.ToBase64String(ber);
int offset = 0;
const int LineLength = 64;
while (offset < base64.Length)
{
int lineEnd = Math.Min(offset + LineLength, base64.Length);
builder.AppendLine(base64.Substring(offset, lineEnd - offset));
offset = lineEnd;
}
builder.Append("-----END ");
builder.Append(header);
builder.AppendLine("-----");
return builder.ToString();
}
So to produce the strings:
string publicKey = MakePem(rsa.ExportSubjectPublicKeyInfo(), "PUBLIC KEY");
string privateKey = MakePem(rsa.ExportRSAPrivateKey(), "RSA PRIVATE KEY");
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 writer package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
To make the public key:
private static string ToSubjectPublicKeyInfo(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(false);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.PushSequence();
writer.WriteObjectIdentifier("1.2.840.113549.1.1.1");
writer.WriteNull();
writer.PopSequence();
AsnWriter innerWriter = new AsnWriter(AsnEncodingRules.DER);
innerWriter.PushSequence();
WriteRSAParameter(innerWriter, rsaParameters.Modulus);
WriteRSAParameter(innerWriter, rsaParameters.Exponent);
innerWriter.PopSequence();
writer.WriteBitString(innerWriter.Encode());
writer.PopSequence();
return MakePem(writer.Encode(), "PUBLIC KEY");
}
And to make the private key:
private static string ToRSAPrivateKey(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(true);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.WriteInteger(0);
WriteRSAParameter(writer, rsaParameters.Modulus);
WriteRSAParameter(writer, rsaParameters.Exponent);
WriteRSAParameter(writer, rsaParameters.D);
WriteRSAParameter(writer, rsaParameters.P);
WriteRSAParameter(writer, rsaParameters.Q);
WriteRSAParameter(writer, rsaParameters.DP);
WriteRSAParameter(writer, rsaParameters.DQ);
WriteRSAParameter(writer, rsaParameters.InverseQ);
writer.PopSequence();
return MakePem(writer.Encode(), "RSA PRIVATE KEY");
}
Reading them back
.NET Core 3.0 built-in API
Except that .NET Core 3.0 doesn't understand PEM encoding, so you have to do PEM->binary yourself:
private const string RsaPrivateKey = "RSA PRIVATE KEY";
private const string SubjectPublicKeyInfo = "PUBLIC KEY";
private static byte PemToBer(string pem, string header)
{
// Technically these should include a newline at the end,
// and either newline-or-beginning-of-data at the beginning.
string begin = $"-----BEGIN {header}-----";
string end = $"-----END {header}-----";
int beginIdx = pem.IndexOf(begin);
int base64Start = beginIdx + begin.Length;
int endIdx = pem.IndexOf(end, base64Start);
return Convert.FromBase64String(pem.Substring(base64Start, endIdx - base64Start));
}
Once that's done you can now load the keys:
using (RSA rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(PemToBer(pemPrivateKey, RsaPrivateKey), out _);
...
}
using (RSA rsa = RSA.Create())
{
rsa.ImportSubjectPublicKeyInfo(PemToBer(pemPublicKey, SubjectPublicKeyInfo), out _);
...
}
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 reader package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
For the public key:
private static RSA FromSubjectPublicKeyInfo(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, SubjectPublicKeyInfo), AsnEncodingRules.DER);
AsnReader spki = reader.ReadSequence();
reader.ThrowIfNotEmpty();
AsnReader algorithmId = spki.ReadSequence();
if (algorithmId.ReadObjectIdentifierAsString() != "1.2.840.113549.1.1.1")
{
throw new InvalidOperationException();
}
algorithmId.ReadNull();
algorithmId.ThrowIfNotEmpty();
AsnReader rsaPublicKey = spki.ReadSequence();
RSAParameters rsaParameters = new RSAParameters
{
Modulus = ReadNormalizedInteger(rsaPublicKey),
Exponent = ReadNormalizedInteger(rsaPublicKey),
};
rsaPublicKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
return span.ToArray();
}
And because the private key values have to have the correct size arrays, the private key one is just a little trickier:
private static RSA FromRSAPrivateKey(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, RsaPrivateKey), AsnEncodingRules.DER);
AsnReader rsaPrivateKey = reader.ReadSequence();
reader.ThrowIfNotEmpty();
if (!rsaPrivateKey.TryReadInt32(out int version) || version != 0)
{
throw new InvalidOperationException();
}
byte modulus = ReadNormalizedInteger(rsaPrivateKey);
int halfModulusLen = (modulus.Length + 1) / 2;
RSAParameters rsaParameters = new RSAParameters
{
Modulus = modulus,
Exponent = ReadNormalizedInteger(rsaPrivateKey),
D = ReadNormalizedInteger(rsaPrivateKey, modulus.Length),
P = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
Q = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DP = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
InverseQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
};
rsaPrivateKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader, int length)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
byte buf = new byte[length];
int skipSize = length - span.Length;
span.CopyTo(buf.AsSpan(skipSize));
return buf;
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53997902%2fhow-to-get-rsacryptoserviceprovider-public-and-private-key-only-in-c-sharp%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The Bouncycastle C# library has some helper classes that can make this relatively easy. It is not well documented unfortunately. Here is an example:
using System;
using System.IO;
using System.Security.Cryptography;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
namespace ExportToStandardFormats
{
class MainClass
{
public static void Main(string args)
{
var rsa = new RSACryptoServiceProvider(2048);
var rsaKeyPair = DotNetUtilities.GetRsaKeyPair(rsa);
var writer = new StringWriter();
var pemWriter = new PemWriter(writer);
pemWriter.WriteObject(rsaKeyPair.Public);
pemWriter.WriteObject(rsaKeyPair.Private);
Console.WriteLine(writer);
}
}
}
add a comment |
The Bouncycastle C# library has some helper classes that can make this relatively easy. It is not well documented unfortunately. Here is an example:
using System;
using System.IO;
using System.Security.Cryptography;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
namespace ExportToStandardFormats
{
class MainClass
{
public static void Main(string args)
{
var rsa = new RSACryptoServiceProvider(2048);
var rsaKeyPair = DotNetUtilities.GetRsaKeyPair(rsa);
var writer = new StringWriter();
var pemWriter = new PemWriter(writer);
pemWriter.WriteObject(rsaKeyPair.Public);
pemWriter.WriteObject(rsaKeyPair.Private);
Console.WriteLine(writer);
}
}
}
add a comment |
The Bouncycastle C# library has some helper classes that can make this relatively easy. It is not well documented unfortunately. Here is an example:
using System;
using System.IO;
using System.Security.Cryptography;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
namespace ExportToStandardFormats
{
class MainClass
{
public static void Main(string args)
{
var rsa = new RSACryptoServiceProvider(2048);
var rsaKeyPair = DotNetUtilities.GetRsaKeyPair(rsa);
var writer = new StringWriter();
var pemWriter = new PemWriter(writer);
pemWriter.WriteObject(rsaKeyPair.Public);
pemWriter.WriteObject(rsaKeyPair.Private);
Console.WriteLine(writer);
}
}
}
The Bouncycastle C# library has some helper classes that can make this relatively easy. It is not well documented unfortunately. Here is an example:
using System;
using System.IO;
using System.Security.Cryptography;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
namespace ExportToStandardFormats
{
class MainClass
{
public static void Main(string args)
{
var rsa = new RSACryptoServiceProvider(2048);
var rsaKeyPair = DotNetUtilities.GetRsaKeyPair(rsa);
var writer = new StringWriter();
var pemWriter = new PemWriter(writer);
pemWriter.WriteObject(rsaKeyPair.Public);
pemWriter.WriteObject(rsaKeyPair.Private);
Console.WriteLine(writer);
}
}
}
answered Jan 2 at 19:27
James K PolkJames K Polk
30.3k116897
30.3k116897
add a comment |
add a comment |
Starting in .NET Core 3.0, this is (largely) built-in.
Writing SubjectPublicKeyInfo and RSAPrivateKey
.NET Core 3.0 built-in API
The output of the builtin API is the binary representation, to make them PEM you need to output the header, footer, and base64:
private static string MakePem(byte ber, string header)
{
StringBuilder builder = new StringBuilder("-----BEGIN ");
builder.Append(header);
builder.AppendLine("-----");
string base64 = Convert.ToBase64String(ber);
int offset = 0;
const int LineLength = 64;
while (offset < base64.Length)
{
int lineEnd = Math.Min(offset + LineLength, base64.Length);
builder.AppendLine(base64.Substring(offset, lineEnd - offset));
offset = lineEnd;
}
builder.Append("-----END ");
builder.Append(header);
builder.AppendLine("-----");
return builder.ToString();
}
So to produce the strings:
string publicKey = MakePem(rsa.ExportSubjectPublicKeyInfo(), "PUBLIC KEY");
string privateKey = MakePem(rsa.ExportRSAPrivateKey(), "RSA PRIVATE KEY");
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 writer package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
To make the public key:
private static string ToSubjectPublicKeyInfo(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(false);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.PushSequence();
writer.WriteObjectIdentifier("1.2.840.113549.1.1.1");
writer.WriteNull();
writer.PopSequence();
AsnWriter innerWriter = new AsnWriter(AsnEncodingRules.DER);
innerWriter.PushSequence();
WriteRSAParameter(innerWriter, rsaParameters.Modulus);
WriteRSAParameter(innerWriter, rsaParameters.Exponent);
innerWriter.PopSequence();
writer.WriteBitString(innerWriter.Encode());
writer.PopSequence();
return MakePem(writer.Encode(), "PUBLIC KEY");
}
And to make the private key:
private static string ToRSAPrivateKey(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(true);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.WriteInteger(0);
WriteRSAParameter(writer, rsaParameters.Modulus);
WriteRSAParameter(writer, rsaParameters.Exponent);
WriteRSAParameter(writer, rsaParameters.D);
WriteRSAParameter(writer, rsaParameters.P);
WriteRSAParameter(writer, rsaParameters.Q);
WriteRSAParameter(writer, rsaParameters.DP);
WriteRSAParameter(writer, rsaParameters.DQ);
WriteRSAParameter(writer, rsaParameters.InverseQ);
writer.PopSequence();
return MakePem(writer.Encode(), "RSA PRIVATE KEY");
}
Reading them back
.NET Core 3.0 built-in API
Except that .NET Core 3.0 doesn't understand PEM encoding, so you have to do PEM->binary yourself:
private const string RsaPrivateKey = "RSA PRIVATE KEY";
private const string SubjectPublicKeyInfo = "PUBLIC KEY";
private static byte PemToBer(string pem, string header)
{
// Technically these should include a newline at the end,
// and either newline-or-beginning-of-data at the beginning.
string begin = $"-----BEGIN {header}-----";
string end = $"-----END {header}-----";
int beginIdx = pem.IndexOf(begin);
int base64Start = beginIdx + begin.Length;
int endIdx = pem.IndexOf(end, base64Start);
return Convert.FromBase64String(pem.Substring(base64Start, endIdx - base64Start));
}
Once that's done you can now load the keys:
using (RSA rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(PemToBer(pemPrivateKey, RsaPrivateKey), out _);
...
}
using (RSA rsa = RSA.Create())
{
rsa.ImportSubjectPublicKeyInfo(PemToBer(pemPublicKey, SubjectPublicKeyInfo), out _);
...
}
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 reader package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
For the public key:
private static RSA FromSubjectPublicKeyInfo(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, SubjectPublicKeyInfo), AsnEncodingRules.DER);
AsnReader spki = reader.ReadSequence();
reader.ThrowIfNotEmpty();
AsnReader algorithmId = spki.ReadSequence();
if (algorithmId.ReadObjectIdentifierAsString() != "1.2.840.113549.1.1.1")
{
throw new InvalidOperationException();
}
algorithmId.ReadNull();
algorithmId.ThrowIfNotEmpty();
AsnReader rsaPublicKey = spki.ReadSequence();
RSAParameters rsaParameters = new RSAParameters
{
Modulus = ReadNormalizedInteger(rsaPublicKey),
Exponent = ReadNormalizedInteger(rsaPublicKey),
};
rsaPublicKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
return span.ToArray();
}
And because the private key values have to have the correct size arrays, the private key one is just a little trickier:
private static RSA FromRSAPrivateKey(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, RsaPrivateKey), AsnEncodingRules.DER);
AsnReader rsaPrivateKey = reader.ReadSequence();
reader.ThrowIfNotEmpty();
if (!rsaPrivateKey.TryReadInt32(out int version) || version != 0)
{
throw new InvalidOperationException();
}
byte modulus = ReadNormalizedInteger(rsaPrivateKey);
int halfModulusLen = (modulus.Length + 1) / 2;
RSAParameters rsaParameters = new RSAParameters
{
Modulus = modulus,
Exponent = ReadNormalizedInteger(rsaPrivateKey),
D = ReadNormalizedInteger(rsaPrivateKey, modulus.Length),
P = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
Q = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DP = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
InverseQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
};
rsaPrivateKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader, int length)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
byte buf = new byte[length];
int skipSize = length - span.Length;
span.CopyTo(buf.AsSpan(skipSize));
return buf;
}
add a comment |
Starting in .NET Core 3.0, this is (largely) built-in.
Writing SubjectPublicKeyInfo and RSAPrivateKey
.NET Core 3.0 built-in API
The output of the builtin API is the binary representation, to make them PEM you need to output the header, footer, and base64:
private static string MakePem(byte ber, string header)
{
StringBuilder builder = new StringBuilder("-----BEGIN ");
builder.Append(header);
builder.AppendLine("-----");
string base64 = Convert.ToBase64String(ber);
int offset = 0;
const int LineLength = 64;
while (offset < base64.Length)
{
int lineEnd = Math.Min(offset + LineLength, base64.Length);
builder.AppendLine(base64.Substring(offset, lineEnd - offset));
offset = lineEnd;
}
builder.Append("-----END ");
builder.Append(header);
builder.AppendLine("-----");
return builder.ToString();
}
So to produce the strings:
string publicKey = MakePem(rsa.ExportSubjectPublicKeyInfo(), "PUBLIC KEY");
string privateKey = MakePem(rsa.ExportRSAPrivateKey(), "RSA PRIVATE KEY");
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 writer package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
To make the public key:
private static string ToSubjectPublicKeyInfo(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(false);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.PushSequence();
writer.WriteObjectIdentifier("1.2.840.113549.1.1.1");
writer.WriteNull();
writer.PopSequence();
AsnWriter innerWriter = new AsnWriter(AsnEncodingRules.DER);
innerWriter.PushSequence();
WriteRSAParameter(innerWriter, rsaParameters.Modulus);
WriteRSAParameter(innerWriter, rsaParameters.Exponent);
innerWriter.PopSequence();
writer.WriteBitString(innerWriter.Encode());
writer.PopSequence();
return MakePem(writer.Encode(), "PUBLIC KEY");
}
And to make the private key:
private static string ToRSAPrivateKey(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(true);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.WriteInteger(0);
WriteRSAParameter(writer, rsaParameters.Modulus);
WriteRSAParameter(writer, rsaParameters.Exponent);
WriteRSAParameter(writer, rsaParameters.D);
WriteRSAParameter(writer, rsaParameters.P);
WriteRSAParameter(writer, rsaParameters.Q);
WriteRSAParameter(writer, rsaParameters.DP);
WriteRSAParameter(writer, rsaParameters.DQ);
WriteRSAParameter(writer, rsaParameters.InverseQ);
writer.PopSequence();
return MakePem(writer.Encode(), "RSA PRIVATE KEY");
}
Reading them back
.NET Core 3.0 built-in API
Except that .NET Core 3.0 doesn't understand PEM encoding, so you have to do PEM->binary yourself:
private const string RsaPrivateKey = "RSA PRIVATE KEY";
private const string SubjectPublicKeyInfo = "PUBLIC KEY";
private static byte PemToBer(string pem, string header)
{
// Technically these should include a newline at the end,
// and either newline-or-beginning-of-data at the beginning.
string begin = $"-----BEGIN {header}-----";
string end = $"-----END {header}-----";
int beginIdx = pem.IndexOf(begin);
int base64Start = beginIdx + begin.Length;
int endIdx = pem.IndexOf(end, base64Start);
return Convert.FromBase64String(pem.Substring(base64Start, endIdx - base64Start));
}
Once that's done you can now load the keys:
using (RSA rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(PemToBer(pemPrivateKey, RsaPrivateKey), out _);
...
}
using (RSA rsa = RSA.Create())
{
rsa.ImportSubjectPublicKeyInfo(PemToBer(pemPublicKey, SubjectPublicKeyInfo), out _);
...
}
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 reader package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
For the public key:
private static RSA FromSubjectPublicKeyInfo(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, SubjectPublicKeyInfo), AsnEncodingRules.DER);
AsnReader spki = reader.ReadSequence();
reader.ThrowIfNotEmpty();
AsnReader algorithmId = spki.ReadSequence();
if (algorithmId.ReadObjectIdentifierAsString() != "1.2.840.113549.1.1.1")
{
throw new InvalidOperationException();
}
algorithmId.ReadNull();
algorithmId.ThrowIfNotEmpty();
AsnReader rsaPublicKey = spki.ReadSequence();
RSAParameters rsaParameters = new RSAParameters
{
Modulus = ReadNormalizedInteger(rsaPublicKey),
Exponent = ReadNormalizedInteger(rsaPublicKey),
};
rsaPublicKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
return span.ToArray();
}
And because the private key values have to have the correct size arrays, the private key one is just a little trickier:
private static RSA FromRSAPrivateKey(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, RsaPrivateKey), AsnEncodingRules.DER);
AsnReader rsaPrivateKey = reader.ReadSequence();
reader.ThrowIfNotEmpty();
if (!rsaPrivateKey.TryReadInt32(out int version) || version != 0)
{
throw new InvalidOperationException();
}
byte modulus = ReadNormalizedInteger(rsaPrivateKey);
int halfModulusLen = (modulus.Length + 1) / 2;
RSAParameters rsaParameters = new RSAParameters
{
Modulus = modulus,
Exponent = ReadNormalizedInteger(rsaPrivateKey),
D = ReadNormalizedInteger(rsaPrivateKey, modulus.Length),
P = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
Q = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DP = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
InverseQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
};
rsaPrivateKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader, int length)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
byte buf = new byte[length];
int skipSize = length - span.Length;
span.CopyTo(buf.AsSpan(skipSize));
return buf;
}
add a comment |
Starting in .NET Core 3.0, this is (largely) built-in.
Writing SubjectPublicKeyInfo and RSAPrivateKey
.NET Core 3.0 built-in API
The output of the builtin API is the binary representation, to make them PEM you need to output the header, footer, and base64:
private static string MakePem(byte ber, string header)
{
StringBuilder builder = new StringBuilder("-----BEGIN ");
builder.Append(header);
builder.AppendLine("-----");
string base64 = Convert.ToBase64String(ber);
int offset = 0;
const int LineLength = 64;
while (offset < base64.Length)
{
int lineEnd = Math.Min(offset + LineLength, base64.Length);
builder.AppendLine(base64.Substring(offset, lineEnd - offset));
offset = lineEnd;
}
builder.Append("-----END ");
builder.Append(header);
builder.AppendLine("-----");
return builder.ToString();
}
So to produce the strings:
string publicKey = MakePem(rsa.ExportSubjectPublicKeyInfo(), "PUBLIC KEY");
string privateKey = MakePem(rsa.ExportRSAPrivateKey(), "RSA PRIVATE KEY");
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 writer package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
To make the public key:
private static string ToSubjectPublicKeyInfo(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(false);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.PushSequence();
writer.WriteObjectIdentifier("1.2.840.113549.1.1.1");
writer.WriteNull();
writer.PopSequence();
AsnWriter innerWriter = new AsnWriter(AsnEncodingRules.DER);
innerWriter.PushSequence();
WriteRSAParameter(innerWriter, rsaParameters.Modulus);
WriteRSAParameter(innerWriter, rsaParameters.Exponent);
innerWriter.PopSequence();
writer.WriteBitString(innerWriter.Encode());
writer.PopSequence();
return MakePem(writer.Encode(), "PUBLIC KEY");
}
And to make the private key:
private static string ToRSAPrivateKey(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(true);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.WriteInteger(0);
WriteRSAParameter(writer, rsaParameters.Modulus);
WriteRSAParameter(writer, rsaParameters.Exponent);
WriteRSAParameter(writer, rsaParameters.D);
WriteRSAParameter(writer, rsaParameters.P);
WriteRSAParameter(writer, rsaParameters.Q);
WriteRSAParameter(writer, rsaParameters.DP);
WriteRSAParameter(writer, rsaParameters.DQ);
WriteRSAParameter(writer, rsaParameters.InverseQ);
writer.PopSequence();
return MakePem(writer.Encode(), "RSA PRIVATE KEY");
}
Reading them back
.NET Core 3.0 built-in API
Except that .NET Core 3.0 doesn't understand PEM encoding, so you have to do PEM->binary yourself:
private const string RsaPrivateKey = "RSA PRIVATE KEY";
private const string SubjectPublicKeyInfo = "PUBLIC KEY";
private static byte PemToBer(string pem, string header)
{
// Technically these should include a newline at the end,
// and either newline-or-beginning-of-data at the beginning.
string begin = $"-----BEGIN {header}-----";
string end = $"-----END {header}-----";
int beginIdx = pem.IndexOf(begin);
int base64Start = beginIdx + begin.Length;
int endIdx = pem.IndexOf(end, base64Start);
return Convert.FromBase64String(pem.Substring(base64Start, endIdx - base64Start));
}
Once that's done you can now load the keys:
using (RSA rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(PemToBer(pemPrivateKey, RsaPrivateKey), out _);
...
}
using (RSA rsa = RSA.Create())
{
rsa.ImportSubjectPublicKeyInfo(PemToBer(pemPublicKey, SubjectPublicKeyInfo), out _);
...
}
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 reader package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
For the public key:
private static RSA FromSubjectPublicKeyInfo(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, SubjectPublicKeyInfo), AsnEncodingRules.DER);
AsnReader spki = reader.ReadSequence();
reader.ThrowIfNotEmpty();
AsnReader algorithmId = spki.ReadSequence();
if (algorithmId.ReadObjectIdentifierAsString() != "1.2.840.113549.1.1.1")
{
throw new InvalidOperationException();
}
algorithmId.ReadNull();
algorithmId.ThrowIfNotEmpty();
AsnReader rsaPublicKey = spki.ReadSequence();
RSAParameters rsaParameters = new RSAParameters
{
Modulus = ReadNormalizedInteger(rsaPublicKey),
Exponent = ReadNormalizedInteger(rsaPublicKey),
};
rsaPublicKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
return span.ToArray();
}
And because the private key values have to have the correct size arrays, the private key one is just a little trickier:
private static RSA FromRSAPrivateKey(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, RsaPrivateKey), AsnEncodingRules.DER);
AsnReader rsaPrivateKey = reader.ReadSequence();
reader.ThrowIfNotEmpty();
if (!rsaPrivateKey.TryReadInt32(out int version) || version != 0)
{
throw new InvalidOperationException();
}
byte modulus = ReadNormalizedInteger(rsaPrivateKey);
int halfModulusLen = (modulus.Length + 1) / 2;
RSAParameters rsaParameters = new RSAParameters
{
Modulus = modulus,
Exponent = ReadNormalizedInteger(rsaPrivateKey),
D = ReadNormalizedInteger(rsaPrivateKey, modulus.Length),
P = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
Q = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DP = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
InverseQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
};
rsaPrivateKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader, int length)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
byte buf = new byte[length];
int skipSize = length - span.Length;
span.CopyTo(buf.AsSpan(skipSize));
return buf;
}
Starting in .NET Core 3.0, this is (largely) built-in.
Writing SubjectPublicKeyInfo and RSAPrivateKey
.NET Core 3.0 built-in API
The output of the builtin API is the binary representation, to make them PEM you need to output the header, footer, and base64:
private static string MakePem(byte ber, string header)
{
StringBuilder builder = new StringBuilder("-----BEGIN ");
builder.Append(header);
builder.AppendLine("-----");
string base64 = Convert.ToBase64String(ber);
int offset = 0;
const int LineLength = 64;
while (offset < base64.Length)
{
int lineEnd = Math.Min(offset + LineLength, base64.Length);
builder.AppendLine(base64.Substring(offset, lineEnd - offset));
offset = lineEnd;
}
builder.Append("-----END ");
builder.Append(header);
builder.AppendLine("-----");
return builder.ToString();
}
So to produce the strings:
string publicKey = MakePem(rsa.ExportSubjectPublicKeyInfo(), "PUBLIC KEY");
string privateKey = MakePem(rsa.ExportRSAPrivateKey(), "RSA PRIVATE KEY");
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 writer package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
To make the public key:
private static string ToSubjectPublicKeyInfo(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(false);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.PushSequence();
writer.WriteObjectIdentifier("1.2.840.113549.1.1.1");
writer.WriteNull();
writer.PopSequence();
AsnWriter innerWriter = new AsnWriter(AsnEncodingRules.DER);
innerWriter.PushSequence();
WriteRSAParameter(innerWriter, rsaParameters.Modulus);
WriteRSAParameter(innerWriter, rsaParameters.Exponent);
innerWriter.PopSequence();
writer.WriteBitString(innerWriter.Encode());
writer.PopSequence();
return MakePem(writer.Encode(), "PUBLIC KEY");
}
And to make the private key:
private static string ToRSAPrivateKey(RSA rsa)
{
RSAParameters rsaParameters = rsa.ExportParameters(true);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.WriteInteger(0);
WriteRSAParameter(writer, rsaParameters.Modulus);
WriteRSAParameter(writer, rsaParameters.Exponent);
WriteRSAParameter(writer, rsaParameters.D);
WriteRSAParameter(writer, rsaParameters.P);
WriteRSAParameter(writer, rsaParameters.Q);
WriteRSAParameter(writer, rsaParameters.DP);
WriteRSAParameter(writer, rsaParameters.DQ);
WriteRSAParameter(writer, rsaParameters.InverseQ);
writer.PopSequence();
return MakePem(writer.Encode(), "RSA PRIVATE KEY");
}
Reading them back
.NET Core 3.0 built-in API
Except that .NET Core 3.0 doesn't understand PEM encoding, so you have to do PEM->binary yourself:
private const string RsaPrivateKey = "RSA PRIVATE KEY";
private const string SubjectPublicKeyInfo = "PUBLIC KEY";
private static byte PemToBer(string pem, string header)
{
// Technically these should include a newline at the end,
// and either newline-or-beginning-of-data at the beginning.
string begin = $"-----BEGIN {header}-----";
string end = $"-----END {header}-----";
int beginIdx = pem.IndexOf(begin);
int base64Start = beginIdx + begin.Length;
int endIdx = pem.IndexOf(end, base64Start);
return Convert.FromBase64String(pem.Substring(base64Start, endIdx - base64Start));
}
Once that's done you can now load the keys:
using (RSA rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(PemToBer(pemPrivateKey, RsaPrivateKey), out _);
...
}
using (RSA rsa = RSA.Create())
{
rsa.ImportSubjectPublicKeyInfo(PemToBer(pemPublicKey, SubjectPublicKeyInfo), out _);
...
}
Semi-manually
If you can't use .NET Core 3.0, but you can use pre-release NuGet packages, you can make use of the prototype ASN.1 reader package (which is the same code that's used internally in .NET Core 3.0; it's just that the API surface isn't finalized).
For the public key:
private static RSA FromSubjectPublicKeyInfo(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, SubjectPublicKeyInfo), AsnEncodingRules.DER);
AsnReader spki = reader.ReadSequence();
reader.ThrowIfNotEmpty();
AsnReader algorithmId = spki.ReadSequence();
if (algorithmId.ReadObjectIdentifierAsString() != "1.2.840.113549.1.1.1")
{
throw new InvalidOperationException();
}
algorithmId.ReadNull();
algorithmId.ThrowIfNotEmpty();
AsnReader rsaPublicKey = spki.ReadSequence();
RSAParameters rsaParameters = new RSAParameters
{
Modulus = ReadNormalizedInteger(rsaPublicKey),
Exponent = ReadNormalizedInteger(rsaPublicKey),
};
rsaPublicKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
return span.ToArray();
}
And because the private key values have to have the correct size arrays, the private key one is just a little trickier:
private static RSA FromRSAPrivateKey(string pem)
{
AsnReader reader = new AsnReader(PemToBer(pem, RsaPrivateKey), AsnEncodingRules.DER);
AsnReader rsaPrivateKey = reader.ReadSequence();
reader.ThrowIfNotEmpty();
if (!rsaPrivateKey.TryReadInt32(out int version) || version != 0)
{
throw new InvalidOperationException();
}
byte modulus = ReadNormalizedInteger(rsaPrivateKey);
int halfModulusLen = (modulus.Length + 1) / 2;
RSAParameters rsaParameters = new RSAParameters
{
Modulus = modulus,
Exponent = ReadNormalizedInteger(rsaPrivateKey),
D = ReadNormalizedInteger(rsaPrivateKey, modulus.Length),
P = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
Q = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DP = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
DQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
InverseQ = ReadNormalizedInteger(rsaPrivateKey, halfModulusLen),
};
rsaPrivateKey.ThrowIfNotEmpty();
RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
private static byte ReadNormalizedInteger(AsnReader reader, int length)
{
ReadOnlyMemory<byte> memory = reader.ReadIntegerBytes();
ReadOnlySpan<byte> span = memory.Span;
if (span[0] == 0)
{
span = span.Slice(1);
}
byte buf = new byte[length];
int skipSize = length - span.Length;
span.CopyTo(buf.AsSpan(skipSize));
return buf;
}
edited Jan 2 at 18:57
answered Jan 2 at 18:14
bartonjsbartonjs
13.9k12658
13.9k12658
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53997902%2fhow-to-get-rsacryptoserviceprovider-public-and-private-key-only-in-c-sharp%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown

See the second answer of this question. stackoverflow.com/questions/14047532/…
– NthDeveloper
Jan 1 at 20:47
@NthDeveloper: That answer has nothing to do with this question.
– James K Polk
Jan 1 at 21:49
1
You can use the Bouncycastle C# library which is the easiest solution or you can try to hand code the generation of ASN.1 objects yourself which is doable but much harder.
– James K Polk
Jan 1 at 21:52
In .NET Core 3.0 (preview 1) you can get the binary data with rsa.ExportSubjectPublicKeyInfo() and rsa.ExportRSAPrivateKey(), I’ll post an answer tomorrow.
– bartonjs
Jan 2 at 3:49
@JamesKPolk thank you, I used BouncyCastle C# library, please write it as an answer to close this thread.
– ARH
Jan 2 at 10:48