C# - 是否可以使用 RSA SHA512 对哈希进行签名?
C# - Is it possible to Sign hash using RSA SHA512?
我使用 OpenSSL 创建了一个自签名证书,如下所示:
openssl req -x509 -sha512 -new keyrsa:2048 -keyout key2.pem -out cert2.pem -days 100
openssl pkcs12 -export -out pkcs12_cert_test2.pfx -inkey key2.pem -in cert2.pem
我在Windows上安装了pkcs12_cert_test2.pfx
,证书签名算法值为sha512RSA
然后,我在 C# .NET 4.0 中编写了以下代码:
public static bool DSHandler(string operation, string path, string devicePath)
{
bool result = false;
CryptoConfig.AddAlgorithm(typeof(USBSaferAppEFB.RsaPkCs1Sha512SignatureDescription),
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512");
string password = "xxxx";
bool validSignature = false;
byte[] hashchain = generateHash(path);
string digSignFile = Utils.RegVarValue(DIGSIGNFILE);
string subjectDN = Utils.RegVarValue(SUBJECTDN);
if (operation == "sign")
{
byte[] signature = SignFromContainer(hashchain, subjectDN);
if (signature != null)
{
string signaturestring = Convert.ToBase64String(signature);
File.WriteAllBytes(devicePath + digSignFile, signature);
result = true;
}
else
result = false;
}
}
static byte[] SignFromContainer(byte[] hashchain, string certSubject)
{
try
{
X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser);
my.Open(OpenFlags.ReadOnly);
RSACryptoServiceProvider csp = null;
foreach (X509Certificate2 cert in my.Certificates)
{
if (cert.Subject.Contains(certSubject))
{
// We found it.
// Get its associated CSP and private key
csp = (RSACryptoServiceProvider)cert.PrivateKey;
}
}
if (csp == null)
{
return null;
}
byte[] myHash = { 59,4,248,102,77,97,142,201,
210,12,224,93,25,41,100,197,
210,12,224,93};
// Sign the hash
return csp.SignHash(hashchain, CryptoConfig.MapNameToOID("SHA-512"));
}
catch (Exception e)
{
log.Logger("Exception: "+e.Message, "debug");
log.Logger(e.StackTrace, "debug");
return null;
}
}
使用一些文章和答案中的解决方案,我 RsaPkCs1Sha512SignatureDescription
class 我尝试在其中实施和注册签名描述:
public class RsaPkCs1Sha512SignatureDescription : SignatureDescription
{
public RsaPkCs1Sha512SignatureDescription()
{
KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;
DigestAlgorithm = typeof(SHA512Managed).FullName;
FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).FullName;
DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).FullName;
}
public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
{
var sigProcessor = (AsymmetricSignatureDeformatter)CryptoConfig.CreateFromName(DeformatterAlgorithm);
sigProcessor.SetKey(key);
sigProcessor.SetHashAlgorithm("SHA-512");
return sigProcessor;
}
public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
{
var sigProcessor =
(AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm);
sigProcessor.SetKey(key);
sigProcessor.SetHashAlgorithm("SHA-512");
return sigProcessor;
}
}
我已验证散列的长度为 64
个字节,并且 returns 为 CryptographicException: Bad Hash
。但是,如果我使用 myHash
var(20 个字节长),尽管 SignHash
中指定的算法是 SHA512
,它仍然有效,并使用 SHA1
算法对哈希进行签名。
此外,如果我打印 csp.SignatureAlgorithm
,如果安装证书的详细信息显示 sha512RSA
作为签名算法,它的值为 http://www.w3.org/2000/09/xmldsig#rsa-sha1. Why is signature algorithm equals to http://www.w3.org/2000/09/xmldsig#rsa-sha1?这一点可能是真正的问题吗?如果是这样,我该如何正确创建证书?提前致谢!
好的。没有必要实施 RsaPkCs1Sha512SignatureDescription
class 或类似的东西,但要指定正确的 CSP 以允许 CryptoAPI 使用 SHA256 或 SHA512:"Microsoft Enhanced RSA and AES Cryptographic Provider",键入 24.
我们只需要将 CSP 类型作为 CspParameter 和 export/import 关键信息:
byte[] privateKeyBlob;
CspParameters cp = new CspParameters(24);
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PrivateKey;
privateKeyBlob = csp.ExportCspBlob(true);
csp = new RSACryptoServiceProvider(cp);
csp.ImportCspBlob(privateKeyBlob);
// Sign the hash
return csp.SignHash(hashchain, CryptoConfig.MapNameToOID("SHA-512"));
此过程在 .NET 4.6 中得到了简化:
byte[] signature;
using (RSA rsa = cert.GetRSAPrivateKey())
{
signature = rsa.SignHash(hash, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
请注意,.NET 4.6 RSA 类型不再需要转换为 RSACryptoServiceProvider,如果您使用 GetRSAPrivateKey()(而不是 PrivateKey 属性),则返回的对象可能会处理 SHA-512 签名生成. GetRSAPrivateKey 每次也是 returns 一个唯一的对象,所以你应该适当地处理它。
我使用 OpenSSL 创建了一个自签名证书,如下所示:
openssl req -x509 -sha512 -new keyrsa:2048 -keyout key2.pem -out cert2.pem -days 100
openssl pkcs12 -export -out pkcs12_cert_test2.pfx -inkey key2.pem -in cert2.pem
我在Windows上安装了pkcs12_cert_test2.pfx
,证书签名算法值为sha512RSA
然后,我在 C# .NET 4.0 中编写了以下代码:
public static bool DSHandler(string operation, string path, string devicePath)
{
bool result = false;
CryptoConfig.AddAlgorithm(typeof(USBSaferAppEFB.RsaPkCs1Sha512SignatureDescription),
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512");
string password = "xxxx";
bool validSignature = false;
byte[] hashchain = generateHash(path);
string digSignFile = Utils.RegVarValue(DIGSIGNFILE);
string subjectDN = Utils.RegVarValue(SUBJECTDN);
if (operation == "sign")
{
byte[] signature = SignFromContainer(hashchain, subjectDN);
if (signature != null)
{
string signaturestring = Convert.ToBase64String(signature);
File.WriteAllBytes(devicePath + digSignFile, signature);
result = true;
}
else
result = false;
}
}
static byte[] SignFromContainer(byte[] hashchain, string certSubject)
{
try
{
X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser);
my.Open(OpenFlags.ReadOnly);
RSACryptoServiceProvider csp = null;
foreach (X509Certificate2 cert in my.Certificates)
{
if (cert.Subject.Contains(certSubject))
{
// We found it.
// Get its associated CSP and private key
csp = (RSACryptoServiceProvider)cert.PrivateKey;
}
}
if (csp == null)
{
return null;
}
byte[] myHash = { 59,4,248,102,77,97,142,201,
210,12,224,93,25,41,100,197,
210,12,224,93};
// Sign the hash
return csp.SignHash(hashchain, CryptoConfig.MapNameToOID("SHA-512"));
}
catch (Exception e)
{
log.Logger("Exception: "+e.Message, "debug");
log.Logger(e.StackTrace, "debug");
return null;
}
}
使用一些文章和答案中的解决方案,我 RsaPkCs1Sha512SignatureDescription
class 我尝试在其中实施和注册签名描述:
public class RsaPkCs1Sha512SignatureDescription : SignatureDescription
{
public RsaPkCs1Sha512SignatureDescription()
{
KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;
DigestAlgorithm = typeof(SHA512Managed).FullName;
FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).FullName;
DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).FullName;
}
public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
{
var sigProcessor = (AsymmetricSignatureDeformatter)CryptoConfig.CreateFromName(DeformatterAlgorithm);
sigProcessor.SetKey(key);
sigProcessor.SetHashAlgorithm("SHA-512");
return sigProcessor;
}
public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
{
var sigProcessor =
(AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm);
sigProcessor.SetKey(key);
sigProcessor.SetHashAlgorithm("SHA-512");
return sigProcessor;
}
}
我已验证散列的长度为 64
个字节,并且 returns 为 CryptographicException: Bad Hash
。但是,如果我使用 myHash
var(20 个字节长),尽管 SignHash
中指定的算法是 SHA512
,它仍然有效,并使用 SHA1
算法对哈希进行签名。
此外,如果我打印 csp.SignatureAlgorithm
,如果安装证书的详细信息显示 sha512RSA
作为签名算法,它的值为 http://www.w3.org/2000/09/xmldsig#rsa-sha1. Why is signature algorithm equals to http://www.w3.org/2000/09/xmldsig#rsa-sha1?这一点可能是真正的问题吗?如果是这样,我该如何正确创建证书?提前致谢!
好的。没有必要实施 RsaPkCs1Sha512SignatureDescription
class 或类似的东西,但要指定正确的 CSP 以允许 CryptoAPI 使用 SHA256 或 SHA512:"Microsoft Enhanced RSA and AES Cryptographic Provider",键入 24.
我们只需要将 CSP 类型作为 CspParameter 和 export/import 关键信息:
byte[] privateKeyBlob;
CspParameters cp = new CspParameters(24);
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PrivateKey;
privateKeyBlob = csp.ExportCspBlob(true);
csp = new RSACryptoServiceProvider(cp);
csp.ImportCspBlob(privateKeyBlob);
// Sign the hash
return csp.SignHash(hashchain, CryptoConfig.MapNameToOID("SHA-512"));
此过程在 .NET 4.6 中得到了简化:
byte[] signature;
using (RSA rsa = cert.GetRSAPrivateKey())
{
signature = rsa.SignHash(hash, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
请注意,.NET 4.6 RSA 类型不再需要转换为 RSACryptoServiceProvider,如果您使用 GetRSAPrivateKey()(而不是 PrivateKey 属性),则返回的对象可能会处理 SHA-512 签名生成. GetRSAPrivateKey 每次也是 returns 一个唯一的对象,所以你应该适当地处理它。