【问题标题】:Can't verify PyOpenSSL signature in C#无法在 C# 中验证 PyOpenSSL 签名
【发布时间】:2016-08-05 14:49:31
【问题描述】:

我可以使用 OpenSSL 在 PHP 中签名和验证数据:

function generate_signature($privateKey, $data) {

    $keyData = openssl_get_privatekey($privateKey);

    openssl_sign($data, $signature, $keyData, OPENSSL_ALGO_SHA256);
    openssl_free_key($keyData);

    $sigText = base64_encode($signature);
    return $sigText;
}

function verify_signature($pubKey, $sigText, $data) {
    $signature = base64_decode($sigText);       

    $keyData = openssl_get_publickey($pubKey);
    $ok = openssl_verify($data, $signature, $keyData, "sha256WithRSAEncryption");
    openssl_free_key($keyData);

    return $ok;
}

$privateKey= file_get_contents("private.key");
$pubKey = file_get_contents("public.pem");

$data = "This is a test";
$sigText = generate_signature($privateKey, $data);
$result = verify_signature($pubKey, $sigText, $data);

这适用于我尝试的任何数据值。 $result 总是正确的。

但是,当我尝试使用 BouncyCastle API 验证 C# 中的签名时,它总是失败:

public static bool VerifySignature(string data, string signatureText)
{
    // Using statements and error checking removed for brevity 

    var uri = new Uri("pack://application:,,,/Resources/public.pem");
    var resourceStream = Application.GetResourceStream(uri);
    var reader = new StreamReader(resourceStream.Stream);

    PemReader pemReader = new PemReader(reader);
    RsaKeyParameters parameters = (RsaKeyParameters)pemReader.ReadObject();
    RSACryptoServiceProvider provider = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();

    RSAParameters rParams = new RSAParameters();
    rParams.Modulus = parameters.Modulus.ToByteArray();
    rParams.Exponent = parameters.Exponent.ToByteArray();

    provider.ImportParameters(rParams);

    byte[] sigBytes = Convert.FromBase64String(signatureText);
    byte[] dataBytes = Encoding.UTF8.GetBytes(data);

    bool isValid = provider.VerifyData(dataBytes, CryptoConfig.MapNameToOID("SHA256"), sigBytes);

    return isValid;
}

无论我尝试什么,isValid 总是错误的。我尝试在两端使用 SHA1 而不是 SHA256,我尝试了不同的编码,我尝试反转各种字节数组以防出现一些字节序问题,但无论我尝试什么,我都无法验证 PHP签名。我显然在 C# 方面遗漏了一些东西,但我不知道是什么。

【问题讨论】:

  • 当签名出现问题时,您可以使用一个技巧进行调试:从技术上讲,RSA 签名是 RSA 加密的哈希值。您可以简单地使用您用于验证的公钥解密它(并且不使用填充算法)。然后保存数据,提取哈希值并将其与您期望的结果进行比较。
  • 1) 您是否在证书存储中添加了证书? 2)根据本文档:msdn.microsoft.com/en-us/library/55yk5665(v=vs.110).aspx 你应该计算哈希:hash.ComputeHash
  • @LeonidasMenendez 我很确定证书不需要在密钥库中就可以使用它们,这只是一个存储它们的安全地方。您仍然需要从中加载原始密钥字节。

标签: c# php cryptography bouncycastle pyopenssl


【解决方案1】:

好吧,我仍然不确定RSACryptoServiceProvider 对我有什么影响,但我找到了另一种完美的方法:

public static bool VerifySignature(string data, string signatureText)
{
    // Using statements and error checking removed for brevity 
    var uri = new Uri("pack://application:,,,/Resources/public.pem");
    var resourceStream = Application.GetResourceStream(uri);
    var reader = new StreamReader(resourceStream.Stream);

    PemReader pemReader = new PemReader(reader);
    RsaKeyParameters parameters = (RsaKeyParameters)pemReader.ReadObject();

    RsaDigestSigner signer = (RsaDigestSigner)SignerUtilities.GetSigner("SHA-256withRSA");
    signer.Init(false, parameters);

    byte[] sigBytes = Convert.FromBase64String(signatureText);
    byte[] dataBytes = Encoding.UTF8.GetBytes(data);

    signer.BlockUpdate(dataBytes, 0, dataBytes.Length);
    bool isValid = signer.VerifySignature(sigBytes);

    return isValid;
}

【讨论】:

    猜你喜欢
    • 2012-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多