I'm using the example given in this MSDN article about the DSACryptoServiceProvider
class. The problem is that I get a different signature each time I run the code.
I tried OpenSSL and didn't get this problem but I need to work with System.Security.Cryptography this time.
This is some source code:
this is the hashed value to be signed
byte[] HashValue =
{
59, 4, 248, 102, 77, 97, 142, 201,
210, 12, 224, 93, 25, 41, 100, 197,
213, 134, 130, 135
};
and this is where the problem lies
// The value to hold the signed value.
byte[] SignedHashValue1 = DSASignHash(HashValue, privateKeyInfo, "SHA1");
byte[] SignedHashValue2 = DSASignHash(HashValue, privateKeyInfo, "SHA1");
I used the debugger to figure out the SignedHashValue1
doesn't equal SignedHashValue2
Code from article:
using System;
using System.Security.Cryptography;
public class DSACSPSample
{
public static void Main()
{
try
{
DSAParameters privateKeyInfo;
DSAParameters publicKeyInfo;
// Create a new instance of DSACryptoServiceProvider to generate
// a new key pair.
using (DSACryptoServiceProvider DSA = new DSACryptoServiceProvider())
{
privateKeyInfo = DSA.ExportParameters(true);
publicKeyInfo = DSA.ExportParameters(false);
}
// The hash value to sign.
byte[] HashValue =
{
59, 4, 248, 102, 77, 97, 142, 201,
210, 12, 224, 93, 25, 41, 100, 197,
213, 134, 130, 135
};
// The value to hold the signed value.
byte[] SignedHashValue = DSASignHash(HashValue, privateKeyInfo, "SHA1");
// Verify the hash and display the results.
bool verified = DSAVerifyHash(HashValue, SignedHashValue, publicKeyInfo, "SHA1");
if (verified)
{
Console.WriteLine("The hash value was verified.");
}
else
{
Console.WriteLine("The hash value was not verified.");
}
}
catch (ArgumentNullException e)
{
Console.WriteLine(e.Message);
}
}
public static byte[] DSASignHash(byte[] HashToSign, DSAParameters DSAKeyInfo,
string HashAlg)
{
byte[] sig = null;
try
{
// Create a new instance of DSACryptoServiceProvider.
using (DSACryptoServiceProvider DSA = new DSACryptoServiceProvider())
{
// Import the key information.
DSA.ImportParameters(DSAKeyInfo);
// Create an DSASignatureFormatter object and pass it the
// DSACryptoServiceProvider to transfer the private key.
DSASignatureFormatter DSAFormatter = new DSASignatureFormatter(DSA);
// Set the hash algorithm to the passed value.
DSAFormatter.SetHashAlgorithm(HashAlg);
// Create a signature for HashValue and return it.
sig = DSAFormatter.CreateSignature(HashToSign);
}
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
return sig;
}
public static bool DSAVerifyHash(byte[] HashValue, byte[] SignedHashValue,
DSAParameters DSAKeyInfo, string HashAlg)
{
bool verified = false;
try
{
// Create a new instance of DSACryptoServiceProvider.
using (DSACryptoServiceProvider DSA = new DSACryptoServiceProvider())
{
// Import the key information.
DSA.ImportParameters(DSAKeyInfo);
// Create an DSASignatureDeformatter object and pass it the
// DSACryptoServiceProvider to transfer the private key.
DSASignatureDeformatter DSADeformatter = new DSASignatureDeformatter(DSA);
// Set the hash algorithm to the passed value.
DSADeformatter.SetHashAlgorithm(HashAlg);
// Verify signature and return the result.
verified = DSADeformatter.VerifySignature(HashValue, SignedHashValue);
}
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
return verified;
}
}
If you look at how DSA works (e.g. on Wikipedia), you'll see that the first step while generating a signature is selecting a random value:
Later on you'll find that this randomness is necessary:
A very prominent case of breaking ECDSA (which is derived from DSA but working on elliptic curves) is mentioned thereafter.
Therefore, you should be happy you never got identical signatures. Otherwise your private key would have been endangered.