2011-04-01 151 views
3

将Windows Forms应用程序从.NET 1.1框架升级到.NET 3.5框架时,我遇到了RSACryptoServiceProvider问题。在数据库中,我存储了包含加密签名(SHA1哈希)的二进制文件,并且我有一个存储在文件系统中的公钥作为包含十六进制字符串的文本文档。在从文件系统读取文件并获取证书中的公钥时,我没有任何问题。RSACryptoServiceProvider.ImportParameters抛出System.Security.Cryptography.CryptographicException:错误数据

从公钥中我得到模块和指数字段作为公钥的一部分。我将这些值分配给RSAParameters对象的新实例。接下来,我创建一个RSACryptoServiceProvider类的新实例并调用ImportParameters。在那个调用中,3.5代码抛出一个异常。请注意,1.1代码完全没有问题。

有没有人知道给予RSAParameters属性的字节数组是否需要转换,所以我可以在3.5代码中使用它们呢?我已经尝试了颠倒数组或将字节数组转换为BigInteger,但这并不能解决我的问题。

作为参考完整堆栈跟踪:

System.Security.Cryptography.CryptographicException: Bad Data. 

    at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr) 
    at System.Security.Cryptography.Utils._ImportKey(SafeProvHandle hCSP, Int32 keyNumber, CspProviderFlags flags, Object cspObject, SafeKeyHandle& hKey) 
    at System.Security.Cryptography.RSACryptoServiceProvider.ImportParameters(RSAParameters parameters) 

源代码,其中,直到该错误: // ---------------------- -------------------------------------------- * //验证证书。 * // ---------------------------------------------- -------------------- *

  // verify the CA certificate (output = public key van CA) 
      byte[] lv_PkCA = VerifyCertificate(byte[], in_PkEUR); 

      // verify the VU certificate (output = public key van VU) 
      byte[] lv_PkVU = VerifyCertificate(byte[], lv_PkCA); 


      //------------------------------------------------------------------ 
      // Verify the signatures 
      //------------------------------------------------------------------ 

      // calculate hash with the SHA1 algorithm 
      SHA1 lv_HashAlgoritm = new SHA1CryptoServiceProvider(); 

      byte[] lv_Modulus = new byte[128]; 
      byte[] lv_Exponent = new byte[8]; 
      Buffer.BlockCopy(lv_PkVU, lv_PkVU.Length - 128 - 8, lv_Modulus , 0, lv_Modulus.Length); 
      Buffer.BlockCopy(lv_PkVU, lv_PkVU.Length - 8  , lv_Exponent, 0, lv_Exponent.Length); 

      // init RSA parameters 
      RSAParameters lv_RSAKeyInfo = new RSAParameters(); 
      lv_RSAKeyInfo.Modulus = lv_Modulus; 
      lv_RSAKeyInfo.Exponent = lv_Exponent; 

      // init RSA algoritme 
      RSACryptoServiceProvider lv_RSA = new RSACryptoServiceProvider(); 
      lv_RSA.ImportParameters(lv_RSAKeyInfo); 

有关更多参考,请参阅VerifyCertificate方法的内容。

private byte[] VerifyCertificate(
    byte[] in_Certificate, 
    byte[] in_PublicKey) 
{ 
    byte[] lv_CHR  = new byte[8]; 
    byte[] lv_Modulus = new byte[128]; 
    byte[] lv_Exponent = new byte[8]; 
    Buffer.BlockCopy(in_PublicKey, in_PublicKey.Length - 128 - 8 - 8, lv_CHR  , 0, lv_CHR.Length); 
    Buffer.BlockCopy(in_PublicKey, in_PublicKey.Length - 128 - 8 , lv_Modulus , 0, lv_Modulus.Length); 
    Buffer.BlockCopy(in_PublicKey, in_PublicKey.Length - 8   , lv_Exponent, 0, lv_Exponent.Length); 

    byte[] lv_Signature = new byte[128]; 
    byte[] lv_Cn  = new byte[58]; 
    byte[] lv_CAR  = new byte[8]; 
    Buffer.BlockCopy(in_Certificate, 0, lv_Signature, 0, lv_Signature.Length); 
    Buffer.BlockCopy(in_Certificate, 128, lv_Cn  , 0, lv_Cn.Length); 
    Buffer.BlockCopy(in_Certificate, 186, lv_CAR  , 0, lv_CAR.Length); 

    for (int lv_Index = 0; lv_Index < lv_CAR.Length; lv_Index++) 
    { 
     if (lv_CAR[lv_Index] != lv_CHR[lv_Index]) 
      throw new Exception("Validation error: CAR not in public key."); 
    } 

    BigInteger lv_BiModulus = new BigInteger(lv_Modulus); 
    BigInteger lv_BiExponent = new BigInteger(lv_Exponent); 
    BigInteger lv_BiSignature = new BigInteger(lv_Signature); 
    byte[] lv_Sr = lv_BiSignature.modPow(lv_BiExponent, lv_BiModulus).getBytes(lv_Signature.Length); 

    if (lv_Sr.Length != 128) 
     throw new Exception("The certificate coult not be validated: size of signature should be 128 bytes."); 
    if ((lv_Sr[0] != (byte)0x6A) || 
     (lv_Sr[127] != (byte)0xBC)) 
     throw new Exception("The certificate coult not be validated: invalid format."); 

    byte[] lv_Cr = new byte[106]; 
    byte[] lv_H = new byte[20]; 
    Buffer.BlockCopy(lv_Sr, 1, lv_Cr, 0, lv_Cr.Length); 
    Buffer.BlockCopy(lv_Sr, 107, lv_H , 0, lv_H.Length); 

    byte[] lv_C = new byte[164]; 
    Buffer.BlockCopy(lv_Cr, 0, lv_C, 0, lv_Cr.Length); 
    Buffer.BlockCopy(lv_Cn, 0, lv_C, 106, lv_Cn.Length); 

    // bereken de Hash van de public key 
    SHA1CryptoServiceProvider lv_SHA1 = new SHA1CryptoServiceProvider(); 
    byte[] lv_Hash = lv_SHA1.ComputeHash(lv_C); 

    // vergelijk de berekende hash met de hash in het certificaat 
    if (lv_Hash.Length != lv_H.Length) 
     throw new Exception("The certificate coult not be verified: hash length invalid."); 
    for (int lv_Index = 0; lv_Index < lv_Hash.Length; lv_Index++) 
    { 
     if (lv_Hash[lv_Index] != lv_H[lv_Index]) 
      throw new DiantaException("The certificate coult not be verified: hash not invalid."); 
    } 

    return lv_C; 
} 

感谢您的帮助提前。

亲切的问候,

+0

请张贴您的代码 – Predator 2011-04-03 04:54:18

+0

完成后,请指教。 – 2011-04-04 07:01:48

+0

嗨,我打算提供帮助,但你的问题超出了我的专业知识。对不起,关于那个:( – Predator 2011-04-04 16:35:59

回答

2

的指数可以有一个前置0,而不是两个或更多。

您可能使用的指数为65537(99%的RSA密钥对使用该指数),因此lv_RSAKeyInfo.Exponent{0, 0, 0, 0, 0, 1, 0, 1}

删除多余的零,你的代码应该工作。

+0

我听说'3'也被使用过很多 – 2011-04-04 19:35:25

+1

@BlueRaja:'3'在几年前被普遍使用,但它在某些应用中有一些弱点,所以今天我几乎没有看到任何东西但'65537'。 – 2011-04-04 19:53:36

+0

谢谢,这可以帮助我! – 2011-04-05 07:18:53