我正在使用this MSDN article中给出的关于DSACryptoServiceProvider
类的示例。问题是每次运行代码时都会得到不同的签名。
我尝试过OpenSSL并没有遇到这个问题,但这次我需要使用System.Security.Cryptography。
这是一些源代码:
这是要签名的散列值
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[] SignedHashValue1 = DSASignHash(HashValue, privateKeyInfo, "SHA1");
byte[] SignedHashValue2 = DSASignHash(HashValue, privateKeyInfo, "SHA1");
我使用调试器来确定SignedHashValue1
不等于SignedHashValue2
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;
}
}
答案 0 :(得分:4)
如果您查看DSA的工作原理(例如,在Wikipedia上),您会看到生成签名时的第一步是选择随机值:
生成随机的每消息值k,其中0 <0。 k&lt; q
稍后你会发现这种随机性是必要的:
使用DSA,随机签名值k的熵,保密性和唯一性是至关重要的。至关重要的是,违反这三个要求中的任何一个都可以向攻击者揭示整个私钥。使用相同的值两次(即使在保持k秘密的情况下),使用可预测的值,或者在几个签名的每一个中泄漏甚至几个k位,都足以打破DSA。
此后提到了一个非常突出的破坏ECDSA的案例(由DSA衍生但在椭圆曲线上工作)。
因此,您应该感到高兴,因为您从未获得过相同的签名。否则你的私钥就会受到威胁。
答案 1 :(得分:1)
AFAIK,它每次都会生成一个新的密钥对,所以签名应该是不同的,对吗?
// 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);
}
你是不是每次都保存密钥对并加载同一对,以便每次都能获得相同的结果? 见How to store/retrieve RSA public/private key