首页 > 解决方案 > OAEP 填充与 CreateSignature

问题描述

我有一些创建数字签名的代码。消息和签名从一个系统传递到另一个系统。当它收到时,签名被验证。此代码已通过 Fortify 运行,这是一项分析代码以查找安全漏洞的服务。Fortify 报告说“RSACryptography.cs 中的 CreateDigitalSignature() 方法在没有 OAEP 填充的情况下执行公钥 RSA 加密”。

我在 RSACryptoServiceProvider.Encrypt() 方法上看到一个参数,如果为真,则意味着使用 OAEP 填充。但我没有使用 Encrypt()。我正在使用 RSAPKCS1SignatureFormatter 生成并使用 RSAPKCS1SignatureDeformatter 来验证签名。所以我的问题是如何添加填充?我应该在发回之前加密签名吗?请参阅我的代码,其中我标记了“我需要做的事情”,其中我添加了 Encrypt 和 Decrypt 调用。这是我需要做的还是别的什么?

// create a digital signature
// returns true if successful. Also, the public key (as an xml string) that can be sent to the other party to verify messages sent
public bool CreateDigitalSignature(string msgToSend, out string publicKey, out string signature)
{
    bool rc = false;
    publicKey = null;
    signature = null;

    try
    {
        // get the hash of the message to send
        byte[] hashValue = GetHashedBytes(msgToSend);

        // Load or generate a public/private key pair.  
        // If it already exists in the key container it will be loaded, otherwise, a new key pair is created
        CspParameters cp = new CspParameters();
        cp.KeyContainerName = KeyStoreContainerName;

        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(cp);

        // get some info about the key:
        CspKeyContainerInfo info = new CspKeyContainerInfo(cp);

        //Create an RSAPKCS1SignatureFormatter object and pass it the RSACryptoServiceProvider to transfer the private key.  
        RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter(RSA);

        // Set the hash algorithm
        RSAFormatter.SetHashAlgorithm(hashAlgorithm);  // "SHA256", "SHA1", etc.

        //Create a signature for the hashed value of the data
        byte[] signedHashValue = RSAFormatter.CreateSignature(hashValue);

        // fortify says I need to use OAEP padding
        // IS THIS WHAT I NEED TO DO? Encrypt the signature before I convert it to a string?
        signedHashValue = RSA.Encrypt(signedHashValue, true);

        // convert the signature to a string
        signature = Convert.ToBase64String(signedHashValue);

        // get the public key to return so it can be pased to the receiver and used to verify the signature
        // There are two ways - either export the parameters or create an xml string
        // Using export: This gets public key inforation only (specify true to get both public and private keys)
        // RSAParameters RSAKeyInfo = RSA.ExportParameters(false);

        // get a string value of the public key
        publicKey = RSA.ToXmlString(false);

        // demonstration only. how to get the private key
        //string privateKey = RSA.ToXmlString(true);

        rc = true;
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return rc;
}

然后验证签名:

public bool VerifySignature(string origintalData, string publicKeyXml, string signature)
{
    bool verified = false;
    try
    {
        // get the hashed value of the original data. used the specified algoritm stored in the this class
        byte[] hashValue = GetHashedBytes(origintalData);

        // get a byte array of the signature
        byte[] signaturebytes = Convert.FromBase64String(signature);

        // create a crypto provider
        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();

        // set the public key of the crypto service provider
        RSA.FromXmlString(publicKeyXml);

        // create a deformatter
        RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(RSA);

        // set the hash algorithm. The sender must use the same algorithm
        RSADeformatter.SetHashAlgorithm(hashAlgorithm);

        // As per Fortify, need to use OAEP padding
        // IS THIS WHAT i NEED TO DO - decrypt the signature before veryfying it?
        signaturebytes = RSA.Decrypt(signaturebytes, true);

        // verify the signature
        verified = RSADeformatter.VerifySignature(hashValue, signaturebytes);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return verified;
}

更新:从 .Net 4.5.1 升级到 4.6.1 后。我可以用

byte[] signedHashValue = RSA.SignData(bytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)

以及对应的方法

RSA.VerifyData(System.Text.Encoding.UTF8.GetBytes(originalData), signaturebytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)

但我不能指定 RSASignaturePadding.Pss。如果我这样做,我会得到一个异常“指定的填充模式对此算法无效。”

我也得到了和以前一样的签名,所以我觉得我还没有真正完成任何事情。没有办法使用 AOEP 填充?

标签: c#.netrsa

解决方案


推荐阅读