首先,我对加密/签名还很陌生,所以请容忍任何术语的误用。
我需要在 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。但是,我相信由于掩码生成函数 (MGF1) 在 Python 代码中使用 256 位哈希,但在 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();
}
其中还有一些额外的内容,因为还必须计算盐长度。我必须查看加密库的源代码来计算这里 python 代码中指示的盐 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 加密库 AmetryAlgorithm 转换为 Bouncy CaSTLe AmetryKeyParameter 需要上面看到的转换函数 TransformRSAPrivateKey。
关于使用 SHA-256 哈希算法使用 PSS 填充和 MGF1 掩码进行 C# RSA 签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64468934/