2016-12-29 544 views
1

我一直在努力研究C#的RSACryptoServiceProvider如何簽署數據,或找到任何有關如何簽署數據的文檔。手動簽名RSASSA-PKCS1-V1_5-SIGN與C#RSACryptoServiceProvider?

我試過按照指定的簽名方案here,但我似乎無法生成符合.NET實現的簽名。

RSACryptoServiceProvider如何生成一個簽名,或者爲什麼我的任何manualSignedDatas都不匹配下面示例代碼中的RSACryptoServiceProviderSignedData?

public void ManualSignatureTest(byte[] data, X509Certificate2 cert) 
    { 
     var sha256 = new SHA256CryptoServiceProvider(); 
     var rsa = (RSACryptoServiceProvider)cert.PrivateKey; 

     var RSACryptoServiceProviderSignedData = rsa.SignData(data, "SHA256"); 

     var manualSignedDataLittle = ManualSignDataSha256(data, rsa, true, false); 
     var manualSignedDataBig = ManualSignDataSha256(data, rsa, false, false); 

     //https://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider(v=vs.110).aspx 
     //the RSACryptoServiceProvider class reverses the order of an encrypted array of bytes after encryption and before decryption 
     var manualSignedDataReversedLittle = ManualSignDataSha256(data, rsa, true, true); 
     var manualSignedDataReversedBig = ManualSignDataSha256(data, rsa, false, true);    
    } 

    public byte[] ManualSignDataSha256(byte[] data, RSACryptoServiceProvider rsa, bool littleEndian, bool reverseArray) 
    { 
     //https://tools.ietf.org/html/rfc8017#section-8.2.1 
     //EM = EMSA-PKCS1-V1_5-ENCODE (M, k) 
     var emsaEncodedMessage = EmsaPkcs1V1_5Encode_SHA256(data, 245); 

     if (reverseArray) Array.Reverse(emsaEncodedMessage); 
     //m = OS2IP (EM) 
     var intMessageRepresentative = OS2IP(emsaEncodedMessage, littleEndian); 

     //s = RSASP1 (K, m) 
     var intSignatureRepresentative = RSASP1(rsa, intMessageRepresentative); 

     //S = I2OSP (s, k) 
     var signature = I2OSP(intSignatureRepresentative, 256, littleEndian); 

     return signature; 
    } 

    public byte[] HexToByte(string hex) 
    { 
     return Enumerable.Range(0, hex.Length/2).Select(x => Convert.ToByte(hex.Substring(x * 2, 2), 16)).ToArray(); 
    } 

    public byte[] EmsaPkcs1V1_5Encode_SHA256(byte[] message, int emLen) 
    { 
     var digest = new SHA256CryptoServiceProvider().ComputeHash(message); 
     var digestAlgorithm = HexToByte("3031300d060960864801650304020105000420"); 
     var digestInfo = digest.Concat(digestAlgorithm).ToArray(); 

     var paddingLength = emLen - digestInfo.Length - 3; 
     var paddingHexString = ""; 
     for (int i = 0; i < paddingLength; i++) 
     { 
      paddingHexString += "FF"; 
     } 

     return HexToByte("0001" + paddingHexString + "00").Concat(digestInfo).ToArray(); 
    } 

    public BigInteger OS2IP(byte[] data, bool isLittleEndian) 
    { 
     BigInteger bi = 0; 
     if (isLittleEndian) 
     { 
      for (int i = 0; i < data.Length; i++) 
      { 
       bi += BigInteger.Pow(256, i) * data[i]; 
      } 
     } 
     else 
     { 
      for (int i = 1; i <= data.Length; i++) 
      { 
       bi += BigInteger.Pow(256, i - 1) * data[data.Length - i]; 
      } 
     } 
     return bi; 
    } 

    public BigInteger RSASP1(RSACryptoServiceProvider rsa, BigInteger message) 
    { 
     var keyParameters = rsa.ExportParameters(true); 
     var n = new BigInteger(keyParameters.Modulus); 
     var d = new BigInteger(keyParameters.D); 
     return BigInteger.ModPow(message, d, n); 
     return default(BigInteger); 
    } 

    public byte[] I2OSP(BigInteger x, int xLen, bool makeLittleEndian) 
    { 
     byte[] result = new byte[xLen]; 
     int index = 0; 
     while ((x > 0) && (index < result.Length)) 
     { 
      result[index++] = (byte)(x % 256); 
      x /= 256; 
     } 
     if (!makeLittleEndian) 
      Array.Reverse(result); 
     return result; 
    } 
+0

C#調用在哪裏?你沒有把它與PSS錯誤地進行比較?我沒有看到任何示例輸入,輸出或您嘗試過的東西(例如以十六進制打印中間值並驗證它們)。 –

回答

0

你有......相當多的錯誤。對於初學者,您的EmsaPkcs1V1_5Encode_SHA256函數會向後生成digestInfo變量(您使用digestAlgorithm作爲後綴,當它應該是前綴時)。您還應該在RSASP1中使用OS2IP,因爲您向後調用了BigInteger ctor。

要點:

  • 的BigInteger需要一個little-endian字節[]。
  • RSAParameters使用big-endian byte [] s。
  • OS2IP得多與
    • 插入填充字節,如果需要更容易地寫入(字節[0]> = 0x80的)
    • 反向陣列
    • X =新的BigInteger(字節)
  • MSDN關於RSACryptoServiceProvider的評論是「倒退的」......是倒退的。 CryptEncrypt/CryptDecrypt是向後的(小端),RSACryptoServiceProvider解開它以匹配每個人所期望的線路。 (該評論是關於RSACSP數據與Windows CAPI直接互操作的)。

這裏有一個適合你的例子。字節[]值爲十六進制,BigInteger值(OS2IP輸出)爲十進制。使用上面的項目符號和RFC 3447,您應該能夠匹配它。

Generated Key: 
    n: 
    C2311FC5FA31D333A409BB4CE95B20D21CFCE3753871725653A28425AF6DE97DF 
    2020B23633F458DF12A63627121BFF4E23CE5787E077898057861D1AE60AC2F 
    e: 010001 
    d: 
    0D916719EB103E24768AA3868D2B6BD0A26BDCEC9CC3F86C25ADCE33DFDCFB1A4 
    D503E073D7FF5FD748E43F8DF02A60ED73053143E591E708DF72C2793E22B69 
    p: F7EF37E67FA6685AC1788B01CF38DA20CA4BDE5D8B01A71BD28C65B409C36E4D 
    q: C88257603FB8A5E25E9DDB553A73B647A3ECA6E9ABC6C440DBC705F82ED4DA6B 
    dp: 72E79E0BA85B51FFC5AC7D17F096D398E0C87A9CF5C0655722A448BA40D01EFD 
    dq: 4C0CABC954C1DB211DD3EFB1C6C6C6972B8481D65511C1B3FBE7E3CABB307E5B 
    iq: B94CB9F83D4C145BE43EA96509FF187176F72E9B82F91B8BC49121FB6B9990F0 



    data: 01010203 
    hash (SHA256): 
    9184ABD2BB318731D717E972057240EAE26CCA202A8D35DBE9D2176F526886A0 
    EMSA_PKCS1_V1_5_ENCODE: T= 
    3031300D0609608648016503040201050004209184ABD2BB318731D717E9720572 
    40EAE26CCA202A8D35DBE9D2176F526886A0 
    EMSA_PKCS1_V1_5_ENCODE: EM= 
    0001FFFFFFFFFFFFFFFFFFFF003031300D060960864801650304020105000420918 
    4ABD2BB318731D717E972057240EAE26CCA202A8D35DBE9D2176F526886A0 
    OS2IP: x= 
    4091738259870177337516485429975660299381480466173929813897514081197 
    4001006075637088431241046394626562124424487751622623819494959348458 
    9402025699608224 
    RSASP1: n= 
    1017065459787822195711481708900267786564376023809569193509899981293 
    9461386629891828226910128922059886444866797206179548218910539391071 
    517068232388857867311 
    RSASP1: d= 
    7106127440023861077197422440841549345679963704508929821447170322634 
    5108395833416072981045532865581744327586076884716186753729887110610 
    3233084086814911337 
    RSASP1: s= 
    4575492210354332473521217556428951379558271601925254480118287259959 
    6454886403001827141625402256685452319478955175598933868230853388418 
    44638909194871101390 
    I2OSP: X= 
    575C8A4109ED6EA2A7086338D150A5BB8205142E778547B50CC6019868070243BF4 
    9DE7C60390160E392FACA18F4A05D3A7A88A4DE86DD99F030EB4AA755D7CE 


rsa.SignHash: 
    575C8A4109ED6EA2A7086338D150A5BB8205142E778547B50CC6019868070243B 
    F49DE7C60390160E392FACA18F4A05D3A7A88A4DE86DD99F030EB4AA755D7CE 
Manual: 
    575C8A4109ED6EA2A7086338D150A5BB8205142E778547B50CC6019868070243B 
    F49DE7C60390160E392FACA18F4A05D3A7A88A4DE86DD99F030EB4AA755D7CE