问题描述
我目前正在尝试使用 C# 生成和发送公共 RSA 密钥.它应该是 PEM 格式的 2048 位长密钥.我已经使用 OpenSSL 命令成功地做到了这一点(一些输出被缩短了):
I am currently trying to generate and send a public RSA key using C#. It should be a 2048 bit long key in PEM format. I have successfully done so using OpenSSL command with the following (some output are shortened):
$ openssl genrsa 2048
Generating RSA private key, 2048 bit long modulus
............................................................+++
............................................................+++
e is 65537 (0x10001)
$ openssl rsa -pubout
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAy1MoBtENHBhYLgwP5Hw/xRGaBPHonApChBPBYD6fiq/QoLXA
RmyMoOjXHsKrrwysYIujXADM2LZ0MlFvPbBulvciWnZwp9CUQPwsZ8xnmBWlHyru
xTxNSvV+E/6+2gMOn3I4bmOSIaLx2Y7nCuaenREvD7Mn0vgFnP7yaN8/9va4q8Lo
...
...
y5jiKQKBgGAe9DlkYvR6Edr/gzd6HaF4btQZf6idGdmsYRYc2EMHdRM2NVqlvyLc
MR6rYEuViqLN5XWK6ITOlTPrgAuU6Rl4ZpRlS1ZrfjiUS6dzD/jtJJvsYByC7ZoU
NxIzB0r1hj0TIoedu6NqfRyJ6Fx09U5W81xx77T1EBSg4OCH7eyl
-----END RSA PRIVATE KEY-----
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy1MoBtENHBhYLgwP5Hw/
xRGaBPHonApChBPBYD6fiq/QoLXARmyMoOjXHsKrrwysYIujXADM2LZ0MlFvPbBu
lvciWnZwp9CUQPwsZ8xnmBWlHyruxTxNSvV+E/6+2gMOn3I4bmOSIaLx2Y7nCuae
nREvD7Mn0vgFnP7yaN8/9va4q8LoMKlceE5fSYl2QIfC5ZxUtkblbycEWZHLVOkv
+4Iz0ibD8KGo0PaiZl0jmn9yYXFy747xmwVun+Z4czO8Nu+OOVxsQF4hu1pKvTUx
9yHH/vk5Wr0I09VFyt3BT/RkecJbAAWB9/e572T+hhmmJ08wCs29oFa2Cdik9yyE
2QIDAQAB
-----END PUBLIC KEY-----
以下代码是我使用 C# 生成公钥的代码:
The following code is what I use to generate a public key using C#:
// Variables
CspParameters cspParams = null;
RSACryptoServiceProvider rsaProvider = null;
StreamWriter publicKeyFile = null;
string publicKey = "";
try
{
// Create a new key pair on target CSP
cspParams = new CspParameters();
cspParams.ProviderType = 1; // PROV_RSA_FULL
cspParams.Flags = CspProviderFlags.CreateEphemeralKey;
rsaProvider = new RSACryptoServiceProvider(2048, cspParams);
// Export public key
result = ExportPublicKeyToPEMFormat(rsaProvider);
}
catch (Exception ex)
{
}
ExportPublicKeyToPEMFormat 可以从这个线程中找到:https://stackoverflow.com/a/25591659/2383179
The ExportPublicKeyToPEMFormat can be found from this thread: https://stackoverflow.com/a/25591659/2383179
我在 C# 中的输出如下所示:
-----BEGIN PUBLIC KEY-----
MIIBKwIBAAKCAQEAzMoaInPQ7nAXGWUY2EEtBcPY/Zvfcqf3Uxr7mFrQaxMjdXYi
DVSPh9XBWJlEhQ9ZGyBMpkWwtkrlDw11g/7pj+u7KTa5nH1ZB8vCrY3TC+YnFXPQ
Nv5dCzW0Lz+HD04rir2+K++XQCroy7G68uE9dtkbqa1U7IEWOvejbX+sgzo5ISHA
vCz2DFBInqYNJWfkM8OvLnRYYQ4f8MbmvDEMyaEYPGfQybXAs5eFksqm9pwR0xh4
Oxg/DkDas93lNIf+g00IesHvHuavRm2GX8jAXhrAoZY7nWQZpqS5kwx1kjSwtYEg
Vq4mHcaKIalMAoILSV9ttgqiJ5KVuKIvQJ7wRwIDAQABAgMBAAECAwEAAQIDAQAB
AgMBAAECAwEAAQIDAQAB
-----END PUBLIC KEY-----
使用 OpenSSL 的正确输出如下所示:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy1MoBtENHBhYLgwP5Hw/
xRGaBPHonApChBPBYD6fiq/QoLXARmyMoOjXHsKrrwysYIujXADM2LZ0MlFvPbBu
lvciWnZwp9CUQPwsZ8xnmBWlHyruxTxNSvV+E/6+2gMOn3I4bmOSIaLx2Y7nCuae
nREvD7Mn0vgFnP7yaN8/9va4q8LoMKlceE5fSYl2QIfC5ZxUtkblbycEWZHLVOkv
+4Iz0ibD8KGo0PaiZl0jmn9yYXFy747xmwVun+Z4czO8Nu+OOVxsQF4hu1pKvTUx
9yHH/vk5Wr0I09VFyt3BT/RkecJbAAWB9/e572T+hhmmJ08wCs29oFa2Cdik9yyE
2QIDAQAB
-----END PUBLIC KEY-----
显然,两个公钥之间的格式有所不同.
Obviously there is something different with the formats between the two public key.
OpenSSL 密钥总是以开头MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA"
The OpenSSL key always starst with "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA"
我的密钥以开头MIIBKwIBAAKCAQEA"
My key starts with "MIIBKwIBAAKCAQEA"
推荐答案
不幸的是,您引用的答案中的代码并不真正正确 - 它导出一个私有密钥 PEM 格式,但只有公钥字段设置正确,这与以标准格式导出 RSA 公钥不同.
Unfortunately, the code in the answer you referenced isn't really correct - it exports a private key PEM format, but with only the public key fields correctly set, this is not the same as exporting an RSA public key in standard format.
我实际上在该问题的其他答案中编写了代码,并且当时编写了一种用于导出标准格式的公钥,但没有将其包含在该答案中,因为它不是必需的.这是:
I actually wrote the code in the other answer to that question, and at the time wrote a mode for exporting the public key in the standard format, but didn't include it in that answer as it wasn't required. Here it is:
private static void ExportPublicKey(RSACryptoServiceProvider csp, TextWriter outputStream)
{
var parameters = csp.ExportParameters(false);
using (var stream = new MemoryStream())
{
var writer = new BinaryWriter(stream);
writer.Write((byte)0x30); // SEQUENCE
using (var innerStream = new MemoryStream())
{
var innerWriter = new BinaryWriter(innerStream);
innerWriter.Write((byte)0x30); // SEQUENCE
EncodeLength(innerWriter, 13);
innerWriter.Write((byte)0x06); // OBJECT IDENTIFIER
var rsaEncryptionOid = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
EncodeLength(innerWriter, rsaEncryptionOid.Length);
innerWriter.Write(rsaEncryptionOid);
innerWriter.Write((byte)0x05); // NULL
EncodeLength(innerWriter, 0);
innerWriter.Write((byte)0x03); // BIT STRING
using (var bitStringStream = new MemoryStream())
{
var bitStringWriter = new BinaryWriter(bitStringStream);
bitStringWriter.Write((byte)0x00); // # of unused bits
bitStringWriter.Write((byte)0x30); // SEQUENCE
using (var paramsStream = new MemoryStream())
{
var paramsWriter = new BinaryWriter(paramsStream);
EncodeIntegerBigEndian(paramsWriter, parameters.Modulus); // Modulus
EncodeIntegerBigEndian(paramsWriter, parameters.Exponent); // Exponent
var paramsLength = (int)paramsStream.Length;
EncodeLength(bitStringWriter, paramsLength);
bitStringWriter.Write(paramsStream.GetBuffer(), 0, paramsLength);
}
var bitStringLength = (int)bitStringStream.Length;
EncodeLength(innerWriter, bitStringLength);
innerWriter.Write(bitStringStream.GetBuffer(), 0, bitStringLength);
}
var length = (int)innerStream.Length;
EncodeLength(writer, length);
writer.Write(innerStream.GetBuffer(), 0, length);
}
var base64 = Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length).ToCharArray();
outputStream.WriteLine("-----BEGIN PUBLIC KEY-----");
for (var i = 0; i < base64.Length; i += 64)
{
outputStream.WriteLine(base64, i, Math.Min(64, base64.Length - i));
}
outputStream.WriteLine("-----END PUBLIC KEY-----");
}
}
private static void EncodeLength(BinaryWriter stream, int length)
{
if (length < 0) throw new ArgumentOutOfRangeException("length", "Length must be non-negative");
if (length < 0x80)
{
// Short form
stream.Write((byte)length);
}
else
{
// Long form
var temp = length;
var bytesRequired = 0;
while (temp > 0)
{
temp >>= 8;
bytesRequired++;
}
stream.Write((byte)(bytesRequired | 0x80));
for (var i = bytesRequired - 1; i >= 0; i--)
{
stream.Write((byte)(length >> (8 * i) & 0xff));
}
}
}
private static void EncodeIntegerBigEndian(BinaryWriter stream, byte[] value, bool forceUnsigned = true)
{
stream.Write((byte)0x02); // INTEGER
var prefixZeros = 0;
for (var i = 0; i < value.Length; i++)
{
if (value[i] != 0) break;
prefixZeros++;
}
if (value.Length - prefixZeros == 0)
{
EncodeLength(stream, 1);
stream.Write((byte)0);
}
else
{
if (forceUnsigned && value[prefixZeros] > 0x7f)
{
// Add a prefix zero to force unsigned if the MSB is 1
EncodeLength(stream, value.Length - prefixZeros + 1);
stream.Write((byte)0);
}
else
{
EncodeLength(stream, value.Length - prefixZeros);
}
for (var i = prefixZeros; i < value.Length; i++)
{
stream.Write(value[i]);
}
}
}
这篇关于C# RSA 公钥输出不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!