2015-02-09 14 views
12

Ich versuche derzeit, einen öffentlichen RSA-Schlüssel mit C# zu erzeugen und zu senden. Es sollte ein 2048 Bit langer Schlüssel im PEM-Format sein. Ich habe erfolgreich so mit OpenSSL-Befehl mit dem folgenden (einigem Ausgang verkürzt) getan:C# RSA Public Key Ausgabe nicht korrekt

$ 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----- 

Der folgende Code ist, was ich verwende, um einen öffentlichen Schlüssel mit C# generieren:

// 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) 
{ 
} 

Die ExportPublicKeyToPEMFormat kann aus diesem Thread zu finden: https://stackoverflow.com/a/25591659/2383179

in C# My Ausgabe wie folgt aussieht:

-----BEGIN PUBLIC KEY----- 
MIIBKwIBAAKCAQEAzMoaInPQ7nAXGWUY2EEtBcPY/Zvfcqf3Uxr7mFrQaxMjdXYi 
DVSPh9XBWJlEhQ9ZGyBMpkWwtkrlDw11g/7pj+u7KTa5nH1ZB8vCrY3TC+YnFXPQ 
Nv5dCzW0Lz+HD04rir2+K++XQCroy7G68uE9dtkbqa1U7IEWOvejbX+sgzo5ISHA 
vCz2DFBInqYNJWfkM8OvLnRYYQ4f8MbmvDEMyaEYPGfQybXAs5eFksqm9pwR0xh4 
Oxg/DkDas93lNIf+g00IesHvHuavRm2GX8jAXhrAoZY7nWQZpqS5kwx1kjSwtYEg 
Vq4mHcaKIalMAoILSV9ttgqiJ5KVuKIvQJ7wRwIDAQABAgMBAAECAwEAAQIDAQAB 
AgMBAAECAwEAAQIDAQAB 
-----END PUBLIC KEY----- 

Die richtige Ausgabe OpenSSL sieht wie folgt aus:

-----BEGIN PUBLIC KEY----- 
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy1MoBtENHBhYLgwP5Hw/ 
xRGaBPHonApChBPBYD6fiq/QoLXARmyMoOjXHsKrrwysYIujXADM2LZ0MlFvPbBu 
lvciWnZwp9CUQPwsZ8xnmBWlHyruxTxNSvV+E/6+2gMOn3I4bmOSIaLx2Y7nCuae 
nREvD7Mn0vgFnP7yaN8/9va4q8LoMKlceE5fSYl2QIfC5ZxUtkblbycEWZHLVOkv 
+4Iz0ibD8KGo0PaiZl0jmn9yYXFy747xmwVun+Z4czO8Nu+OOVxsQF4hu1pKvTUx 
9yHH/vk5Wr0I09VFyt3BT/RkecJbAAWB9/e572T+hhmmJ08wCs29oFa2Cdik9yyE 
2QIDAQAB 
-----END PUBLIC KEY----- 

Offensichtlich gibt es etwas anderes mit den Formaten zwischen den beiden öffentlichen Schlüssel.

Der OpenSSL-Schlüssel immer starst mit "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA"

Mein Schlüssel beginnt mit "MIIBKwIBAAKCAQEA"

+0

Der öffentliche Schlüssel wird immer anders aussehen, denn es basiert auf einem neu und zufällig generierten * p * und * q *. –

Antwort

30

Leider ist der Code in der Antwort, die Sie verweisen nicht wirklich richtig - es exportiert ein privates Schlüssel-PEM-Format, aber mit nur den öffentlichen Schlüsselfeldern, die korrekt festgelegt sind, ist das nicht dasselbe wie das Exportieren eines öffentlichen RSA-Schlüssels in Standardformat.

Ich schrieb den Code in der other answer zu dieser Frage, und zu der Zeit schrieb einen Modus zum Exportieren des öffentlichen Schlüssels im Standardformat, aber nicht in dieser Antwort enthalten, da es nicht erforderlich war. Es nutzt die gleichen Methoden Helfer in der anderen Antwort zur Verfügung gestellt, so habe ich sie hier aus Gründen der Kürze ausgeschlossen:

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]); 
     } 
    } 
} 
Verwandte Themen