【问题标题】:How to sign an request using PFX certificate in c#?如何在 C# 中使用 PFX 证书签署请求?
【发布时间】:2020-03-15 05:59:32
【问题描述】:

我正在尝试使用非官方的 API 文档。我需要用我自己的证书签署所有请求,但文档只提供了要使用的 Java 代码,这里是:

public class EncryptionUtils {
private static final String ALGORITHM_NAME = "SHA1withRSA";
private static final String CERT_TYPE = "pkcs12";
private static final String CONTAINER_NAME = "LoginCert";
private static final String PASSWORD = "CE75EA598C7743AD9B0B7328DED85B06";

public static String signContent(byte[] contents, final InputStream cert) throws IOException, GeneralSecurityException, NullPointerException {
    final KeyStore instance = KeyStore.getInstance(CERT_TYPE);
    instance.load(cert, PASSWORD.toCharArray());
    final PrivateKey privateKey = (PrivateKey) instance.getKey(CONTAINER_NAME, PASSWORD.toCharArray());
    final Signature instance2 = Signature.getInstance(ALGORITHM_NAME);
    instance2.initSign(privateKey);
    instance2.update(contents);
    return Base64.getEncoder().encodeToString(instance2.sign());
}}

我想出了这段代码

    private static string password = "CE75EA598C7743AD9B0B7328DED85B06";
    public static string Sign(string text, string cert)
    {
        X509Certificate2 certificate = new X509Certificate2(DecodeCrt(cert), password, X509KeyStorageFlags.Exportable);
        RSA provider = (RSA)certificate.PrivateKey;
        // Hash the data
        var hash = HashText(text);
        // Sign the hash

        var signature = provider.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
        return Convert.ToBase64String(signature);

    }
    public static byte[] HashText(string text) 
    {
        SHA1Managed sha1Hasher = new SHA1Managed();
        UnicodeEncoding encoding = new UnicodeEncoding();
        byte[] data = encoding.GetBytes(text);
        byte[] hash = sha1Hasher.ComputeHash(data);
        return hash;
    }
    public static byte[] DecodeCrt(string crt)
    {
        return Convert.FromBase64String(crt);
    }

但输出与 Java 版本不同。 我试图从 c# 临时运行 java 任务,所以我会知道它是否有效,而且确实有效。 有没有办法用c#写这个?

【问题讨论】:

标签: java c# encryption cryptography signature


【解决方案1】:

这两个代码都使用带有 Pkcs#1 v1.5 填充和 SHA1 的签名 RSA,这在 Java 代码中通过 SHA1withRSA 指定,在 C# 代码中通过第二个和第三个参数在 RSA#SignHash 方法中明确指定.由于签名的 Pkcs#1 v1.5 变体 (RSASSA-PKCS1-v1_5) 是确定性的,因此两个代码必须提供相同的签名(假设要签名的数据和私钥相同)。

如果不是这样,其实合理的解释只有两种:

  • 首先,使用的编码:在Java代码中,数据传输为byte[],因此无法根据发布的代码确定使用哪种编码。相比之下,在 C# 代码中,数据作为字符串传递并转换为 HashText 中的 byte[]。为此,使用UnicodeEncoding 的标准ctor,它应用UTF16LE 和字节顺序标记(BOM)。对于 UTF8(无 BOM)UTF8Encoding 必须使用。 至关重要在 C# 代码中应用与在 Java 代码中相同的编码,否则通常会生成不同的签名。
  • 二、pfx/p12文件:pfx/p12文件可以包含several certificates。在 Java 代码中,KeyStore#getKey 引用带有别名的私钥(证书也是如此),在 C# 代码中,X509Certificate2(Byte[], String, X509KeyStorageFlags) 引用容器中的 first 证书,另请参见 @ 987654330@。为了确保在两个代码中引用相同证书/密钥,pfx/p12 文件可能只包含恰好一个证书,包括相应的私钥。

如果考虑到这一点,两个代码都会在我的机器上生成相同的签名(假设要签名的数据和 pfx/p12 文件相同)。

最后,需要注意的是,在两个代码中cert 用于不同的对象。在Java代码中表示InputStream,在C#代码中表示Base64编码pfx/pf12文件的二进制数据。

【讨论】:

  • 我一直在努力解决这个问题,我想出了第二点,但是在为 pfx 中的每个证书创建签名时,它们都不匹配 Java 的签名。此外,在 Java 中,cert 变量用于相同的目的,因为在调用方法时我必须传递new ByteArrayInputStream(Base64.getDecoder().decode(pfxCert.getBytes())),所以它是相同的。我会尝试修改编码。感谢您的建议!
  • 好的,我刚刚意识到 pfx 只有一个证书,并且每次我尝试签名时都会继续导入它。
  • 您是否检查过两个代码是否使用相同的编码?目前,C# 代码使用 UTF-16LE。仅当 Java 代码也使用此填充时,才能预期签名匹配。是这样吗?
  • 好的,我在散列到 utf8 之前更改了文本的编码,突然签名开始匹配。谢谢!
猜你喜欢
  • 2015-07-29
  • 2020-03-21
  • 2013-08-07
  • 1970-01-01
  • 1970-01-01
  • 2017-06-01
  • 2011-02-24
  • 2018-11-30
  • 2018-05-17
相关资源
最近更新 更多