valid - remarks c#
La salida de clave pública C#RSA no es correcta (1)
Actualmente estoy intentando generar y enviar una clave RSA pública utilizando C #. Debe ser una clave larga de 2048 bits en formato PEM. Lo he hecho con éxito usando el comando OpenSSL con lo siguiente (algunos resultados son más cortos):
$ 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-----
El siguiente código es el que uso para generar una clave pública usando 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)
{
}
El ExportPublicKeyToPEMFormat se puede encontrar en este hilo: https://stackoverflow.com/a/25591659/2383179
Mi salida en C # se ve así:
-----BEGIN PUBLIC KEY-----
MIIBKwIBAAKCAQEAzMoaInPQ7nAXGWUY2EEtBcPY/Zvfcqf3Uxr7mFrQaxMjdXYi
DVSPh9XBWJlEhQ9ZGyBMpkWwtkrlDw11g/7pj+u7KTa5nH1ZB8vCrY3TC+YnFXPQ
Nv5dCzW0Lz+HD04rir2+K++XQCroy7G68uE9dtkbqa1U7IEWOvejbX+sgzo5ISHA
vCz2DFBInqYNJWfkM8OvLnRYYQ4f8MbmvDEMyaEYPGfQybXAs5eFksqm9pwR0xh4
Oxg/DkDas93lNIf+g00IesHvHuavRm2GX8jAXhrAoZY7nWQZpqS5kwx1kjSwtYEg
Vq4mHcaKIalMAoILSV9ttgqiJ5KVuKIvQJ7wRwIDAQABAgMBAAECAwEAAQIDAQAB
AgMBAAECAwEAAQIDAQAB
-----END PUBLIC KEY-----
La salida correcta utilizando OpenSSL se ve así:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy1MoBtENHBhYLgwP5Hw/
xRGaBPHonApChBPBYD6fiq/QoLXARmyMoOjXHsKrrwysYIujXADM2LZ0MlFvPbBu
lvciWnZwp9CUQPwsZ8xnmBWlHyruxTxNSvV+E/6+2gMOn3I4bmOSIaLx2Y7nCuae
nREvD7Mn0vgFnP7yaN8/9va4q8LoMKlceE5fSYl2QIfC5ZxUtkblbycEWZHLVOkv
+4Iz0ibD8KGo0PaiZl0jmn9yYXFy747xmwVun+Z4czO8Nu+OOVxsQF4hu1pKvTUx
9yHH/vk5Wr0I09VFyt3BT/RkecJbAAWB9/e572T+hhmmJ08wCs29oFa2Cdik9yyE
2QIDAQAB
-----END PUBLIC KEY-----
Obviamente, hay algo diferente con los formatos entre las dos claves públicas.
La clave OpenSSL siempre comienza con "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA"
Mi clave comienza con "MIIBKwIBAAKCAQEA"
Desafortunadamente, el código en la respuesta a la que hizo referencia no es realmente correcto: exporta un formato PEM de clave privada , pero con solo los campos de clave pública establecidos correctamente, esto no es lo mismo que exportar una clave pública RSA en formato estándar.
En realidad escribí el código en la otra respuesta a esa pregunta, y en ese momento escribí un modo para exportar la clave pública en el formato estándar, pero no lo incluí en esa respuesta porque no era necesario. Aquí está:
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]);
}
}
}