2015-02-09 67 views
12

我目前正在嘗試使用C#生成併發送公共RSA密鑰。它應該是PEM格式的2048位長密鑰。我已經成功做了使用OpenSSL命令如下(一些輸出被縮短):C#RSA公鑰輸出不正確

$ 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#生成公鑰:

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

我在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----- 

顯然也有一些是與兩個公共密鑰之間的格式不同。

總是starst與 「MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA」

我的鑰匙啓動與 「MIIBKwIBAAKCAQEA」

+0

公鑰總是會不同,因爲它是基於一個新的和隨機生成的* P *和* q *。 – 2015-02-09 10:21:23

回答

30

不幸的是,OpenSSL的關鍵,在你引用的答案的代碼是不是真的正確的 - 它導出專用密鑰PEM格式,但只有公鑰字段正確設置,這與以標準格式導出RSA公鑰不同。

我其實寫了other answer這個問題的代碼,當時寫了一個導出公鑰的標準格式的模式,但沒有包含在那個答案中,因爲它不是必需的。它使用對方的回答提供的相同的輔助方法,所以我在這裏排除他們爲了簡潔:

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