Reputation: 2937
There is an odd design issue in RSACryptoServiceProvider:
While it is possible to sign very large files using RSACryptoServiceProvider.SignData:
public byte[] SignData(
Stream inputStream,
Object halg
)
, there is no way to actually validate the large file without reading the file entirely into a memory buffer. The only available method is:
public bool VerifyData(
byte[] buffer,
Object halg,
byte[] signature
)
which forces the caller to read the entire file into memory (possible yielding an OutOfMemoryException in the calling code).
I looked into extending the RSACryptoServiceProvider since internally the VerifyData method could be very easily overloaded to support streams. However the class is sealed and internally the method uses a bunch of internal methods that I can't access.
Did anyone run into this issue? Any easy solution to the problem?
BTW - for MS the fix would be a 6 line copy & paste with a single var type change...
Upvotes: 2
Views: 1960
Reputation: 2937
This code does the trick:
public byte[] SignData(RSACryptoServiceProvider rsaEncryptor, Stream stream, Object halg)
{
HashAlgorithm hash = (HashAlgorithm) CryptoConfig.CreateFromName((string) halg); /*Utils.ObjToHashAlgorithm(halg)*/
byte[] hashVal = hash.ComputeHash(stream);
return rsaEncryptor.SignHash(hashVal, (string) halg);
}
public bool VerifyData(RSACryptoServiceProvider rsaEncryptor, Stream stream, Object halg, byte[] signature)
{
HashAlgorithm hash = (HashAlgorithm) CryptoConfig.CreateFromName((string) halg); /*Utils.ObjToHashAlgorithm(halg)*/
byte[] hashVal = hash.ComputeHash(stream);
return rsaEncryptor.VerifyHash(hashVal, (string) halg, signature);
}
and calling it is done by:
byte[] signature = SignData(rsa2, stream, "SHA256");
//here we write the signature to a file
and
if (VerifyData(rsaEncryptor, stream, "SHA256", File.ReadAllBytes(signatureFilePath)))
{
Console.WriteLine("Verification completed successfully for file {0}", filePath);
return true;
}
else
{
throw new CryptographicException("verification failed for file {0}", filePath);
}
Upvotes: 2