如何在C#中使用PFX证书签署请求?

时间:2020-03-15 05:59:32

标签: java c# encryption cryptography signature

我正在尝试使用非官方的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#编写吗?

1 个答案:

答案 0 :(得分:0)

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

如果不是这种情况,实际上只有两种合理的解释:

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

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

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