Как подписать запрос с использованием сертификата PFX в c#? - PullRequest
1 голос
/ 15 марта 2020

Я пытаюсь использовать неофициальную документацию 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. Я попытался временно запустить задачу java из c#, чтобы я знал, работает ли она, и это так. Есть ли способ написать это в c#?

1 Ответ

0 голосов
/ 15 марта 2020

Оба кода используют для подписи RSA с заполнением Pkcs # 1 v1.5 и SHA1, что указано в коде Java через SHA1withRSA и в коде C#, явно указанном в RSA#SignHash метод с помощью 2-го и 3-го параметра. Так как вариант Pkcs # 1 v1.5 для подписей ( RSASSA-PKCS1-v1_5 ) является детерминированным c, оба кода должны предоставлять одну и ту же сигнатуру (при условии, что подписываются одни и те же данные и один и тот же закрытый ключ). ).

Если это не так, на самом деле есть только два разумных объяснения:

  • Сначала используется кодировка: В коде Java данные передаются. как byte[], так что невозможно определить, какая кодировка используется на основе опубликованного кода. Напротив, в коде C# данные передаются в виде строки и преобразуются в byte[] в HashText. Для этого используется стандартный ctor UnicodeEncoding, который применяет UTF16LE и метку порядка байтов ( BOM ). Для UTF8 (без спецификации) следует использовать UTF8Encoding. крайне важно , чтобы в коде C# применялась та же кодировка, что и в коде Java, в противном случае обычно генерируются разные подписи.
  • Во-вторых, файл pfx / p12: файлы pfx / p12 могут содержать несколько сертификатов . В коде Java KeyStore#getKey ссылается на закрытый ключ с его псевдонимом (то же самое относится и к сертификату), в коде C# X509Certificate2(Byte[], String, X509KeyStorageFlags) ссылается на первый сертификат в контейнере, см. Также здесь . Чтобы гарантировать, что один и тот же сертификат / ключ указан в обоих кодах, файл pfx / p12 может поэтому содержать только ровно один сертификат, включая соответствующий закрытый ключ.

Если принять это во внимание, оба кода генерируют одну и ту же подпись на моем компьютере (при условии, что подписываются одни и те же данные и один и тот же файл pfx / p12).

Наконец, следует отметить, что в оба кода cert используются для разных объектов. В коде Java он обозначает InputStream, в коде C# двоичные данные в кодировке Base64 файла pfx / pf12.

...