簡體   English   中英

使用 SHA-256 哈希算法使用 PSS 填充和 MGF1 掩碼的 C# RSA 簽名

[英]C# RSA signing with PSS padding and a MGF1 mask using a SHA-256 hash algorithm

首先,我對加密/簽名還是個新手,所以請容忍任何濫用術語的行為。

我需要在 C# 中創建一個簽名,該簽名由 Python 庫驗證。 在 Python 中,解碼/驗證簽名是一段簡單的代碼:

    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.asymmetric import padding

    public_key.verify(signature, payload_contents,
                      padding.PSS(mgf=padding.MGF1(hashes.SHA256()),
                                  salt_length=padding.PSS.MAX_LENGTH,
                                  ), hashes.SHA256(), )

我當前的 C# 代碼如下所示:

    private static string CreateSignature(byte[] data, string privateKeyFileLocation)
    {
        var cert = new X509Certificate2(privateKeyFileLocation);
        
        byte[] signedBytes;
        using (var rsa = cert.GetRSAPrivateKey())
        {
            signedBytes = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
        }
        var finalString = Convert.ToBase64String(signedBytes);
        return finalString;
    }

但是,簽名未通過 Python 代碼中的驗證檢查。 看起來 .Net 庫中的 PSS 填充默認使用 MGF1。 但是,我相信由於在 Python 代碼中使用 256 位哈希的掩碼生成函數 (MGF1) 而出現問題,但在 C# 中默認為 SHA1。 我已經瀏覽了 .Net C# 文檔,看起來沒有辦法覆蓋它。 我查看了 Bouncy Castle 的 C# 文檔,但無法找到有關如何使用自定義參數設置填充的任何類型的類似示例。 有沒有人在這方面有經驗並且可以提供一些提示?

僅適用於處理此問題的其他人。 這是我最終得到的代碼。

    private static string GenerateSignatureForData(string data, string privateKeyFileLocation)
    {
        var cert = new X509Certificate2(privateKeyFileLocation, "12345", X509KeyStorageFlags.Exportable);
        var bcCert = TransformRSAPrivateKey(cert.PrivateKey);
        var keyLen = (int)Math.Ceiling((cert.GetRSAPrivateKey().KeySize - 1) / 8.0);

        byte[] signedBytes = CreateSignature(Encoding.ASCII.GetBytes(data), bcCert, keyLen);
        return Convert.ToBase64String(signedBytes);
    }

    private static AsymmetricKeyParameter TransformRSAPrivateKey(AsymmetricAlgorithm privateKey)
    {
        RSACryptoServiceProvider prov = privateKey as RSACryptoServiceProvider;
        RSAParameters parameters = prov.ExportParameters(true);

        return new RsaPrivateCrtKeyParameters(
            new BigInteger(1, parameters.Modulus),
            new BigInteger(1, parameters.Exponent),
            new BigInteger(1, parameters.D),
            new BigInteger(1, parameters.P),
            new BigInteger(1, parameters.Q),
            new BigInteger(1, parameters.DP),
            new BigInteger(1, parameters.DQ),
            new BigInteger(1, parameters.InverseQ));
    }

    private static byte[] CreateSignature(byte[] data, AsymmetricKeyParameter privateKey, int keyLength)
    {
        var digest = new Sha256Digest();
        var saltLength = keyLength - digest.GetDigestSize() - 2;

        PssSigner signer = new PssSigner(new RsaEngine(), new Sha256Digest(), digest, saltLength);
        signer.Init(true, new ParametersWithRandom((RsaPrivateCrtKeyParameters)privateKey));
        signer.BlockUpdate(data, 0, data.Length);
        return signer.GenerateSignature();
    }

那里有一些額外的東西,因為還必須計算鹽的長度。 我不得不查看crypto庫的源代碼來計算這里的python代碼中指示的salt MAX_LENGTH:

    salt_length=padding.PSS.MAX_LENGTH

以下是執行此操作所需的嚴格代碼:

    var cert = new X509Certificate2(privateKeyFileLocation, "12345", X509KeyStorageFlags.Exportable);
    var bcCert = TransformRSAPrivateKey(cert.PrivateKey);
    var keyLen = (int)Math.Ceiling((cert.GetRSAPrivateKey().KeySize - 1) / 8.0);
    var digest = new Sha256Digest();
    var saltLength = keyLength - digest.GetDigestSize() - 2;

類似地,將 .Net 加密庫 AsymmetricAlgorithm 轉換為 Bouncy Castle AsymmetricKeyParameter 需要使用上面看到的轉換函數 TransformRSAPrivateKey。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM