在将Windows窗体应用程序从.NET 1.1框架升级到.NET 3.5框架时,我遇到了RSACryptoServiceProvider
的问题。在数据库中,我存储了包含加密签名(SHA1哈希)的二进制文件,并且我将一个公钥存储在文件系统中,作为包含十六进制字符串的文本文档。从文件系统读取文件并将公钥编码到证书中时,我没有任何问题。
从公钥我得到模块和指数字段作为公钥的一部分。我将这些值分配给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 :(得分:2)
指数可以有一个前置0,但不能有两个或更多。
您可能使用65537的指数(99%的RSA密钥对使用该指数),因此lv_RSAKeyInfo.Exponent
为{0, 0, 0, 0, 0, 1, 0, 1}
。
删除多余的零,您的代码应该可以正常工作。