C# - 是不是可以使用 RSA SHA512 对哈希进行签名?

Posted

技术标签:

【中文标题】C# - 是不是可以使用 RSA SHA512 对哈希进行签名?【英文标题】:C# - Is it possible to Sign hash using RSA SHA512?C# - 是否可以使用 RSA SHA512 对哈希进行签名? 【发布时间】:2016-09-25 20:00:39 【问题描述】:

我使用 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 类,我尝试在其中实现和注册签名描述:

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 字节长,它返回一个CryptographicException: Bad Hash。但是如果我使用myHash var(20 字节长),虽然SignHash 中指定的算法是SHA512,但它可以工作,并使用SHA1 算法对哈希进行签名。

另外,如果我打印csp.SignatureAlgorithm,它的值为http://www.w3.org/2000/09/xmldsig#rsa-sha1。如果已安装证书的详细信息显示sha512RSA 为签名算法,为什么签名算法等于http://www.w3.org/2000/09/xmldsig#rsa-sha1?这可能是真正的问题吗?如果是这样,我该如何正确创建证书?提前致谢!

【问题讨论】:

【参考方案1】:

这个过程在 .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 每次也返回一个唯一的对象,因此您应该适当地处理它。

【讨论】:

【参考方案2】:

好的。不需要实现RsaPkCs1Sha512SignatureDescription 类或类似的东西,但指定正确的 CSP 以允许 CryptoAPI 使用 SHA256 或 SHA512:“Microsoft Enhanced RSA and AES Cryptographic Provider”,类型 24。

我们只需要将 CSP 类型作为 CspParameter 并导出/导入密钥信息:

    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"));

【讨论】:

我在这方面有点菜鸟,我正在尝试做同样的事情,所以我有几个后续问题:1. cert.PrivateKey 的命名空间是什么。 2. 原来的私钥是怎么分配给cert.PrivateKey的? 3. 为什么要先导出再重新导入 Blob——创建的第一个 csp 对象不应该足够吗?

以上是关于C# - 是不是可以使用 RSA SHA512 对哈希进行签名?的主要内容,如果未能解决你的问题,请参考以下文章

如何在自定义绑定的 defaultAlgorithmSuite 中使用 RSA-SHA512 作为签名算法?

RSA.SignHash SHA512 和 SHA256 给出相同的签名长度

使用 SHA512 对密码进行哈希处理以加密数据

JDK自带方法实现RSA数字签名

C#:使用来自 /etc/shadow 的 linux 用户的 salt 验证密码哈希 (SHA512)

如何通过 .NET 使用 RSA 和 SHA256 对文件进行签名?