RSACryptoServiceProvider.ImportParameters throws System.Security.Cryptography.CryptographicException: Bad Data
While upgrading a Windows Forms application from the .NET 1.1 framework to the .NET 3.5 framework, I have an issue with the RSACryptoServiceProvider
. In a database I have stored binary files which contains an encrypted signature (SHA1 hash) and I have a public key stored in the filesystem as a text document containing a hexadecimal string. I have no issues in reading the file from the filesystem and getting the public key coded in a certificate.
From the public key I get the modules and exponent field as part of the public key. I assign these values to a new instance of the RSAParameters
object. Next I create a new instance of the RSACryptoServiceProvider
class and call the ImportParameters
. In that call the 3.5 code throws an exception. Note that the 1.1 code has no issues at all.
Does anyone know if the byte arrays given to the properties of the RSAParameters needs to be converted, so I can use them in the 3.5 code also? I already tried to reversing the array or converting the byte array to BigInteger, but that is not solving my problems.
For reference the full stacktrace:
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)
Source code where it until the error: //------------------------------------------------------------------* // Verify certificates. * //------------------------------------------------------------------*
// 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 SHA1CryptoServiceProvi开发者_JS百科der();
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);
For more reference, the content of the VerifyCertificate method.
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;
}
Thanks for your help in advance.
Kind regards,
René
The exponent can have one prepended 0, but not two or more.
You are probably using an exponent of 65537 (99% of all RSA keypairs use that), so lv_RSAKeyInfo.Exponent
is {0, 0, 0, 0, 0, 1, 0, 1}
.
Remove the extra zeroes, and your code should work.
精彩评论