Получить знак строки SHA1 с закрытым ключом DSA из файла PEM

У меня есть файл PEM, который включает мой закрытый ключ DSA, и мне нужно подписать строку с этим закрытым ключом, чтобы отправить его в API моего партнера. (код прилагается)

По какой-то причине я всегда получаю недействительную подпись от моего партнерского API. что означает, что знак не в хорошем формате.

Мой партнер предлагает мне использовать bouncycastle для С#, но я не смог найти примеров того, как подписать строку с помощью DSA из внешнего файла PEM.

Могу ли я получить какие-либо примеры здесь?

Спасибо.

Я попытался подписать строку методом, который я написал:

 public string ComputeSignature(string method, string path,string client_id, string timestamp, string username)
        {


        var data = String.Concat(method, path, client_id, timestamp);
        if (!string.IsNullOrEmpty(username))
        {
            data = data + username;
        }


        string sig;
        var encoding = new ASCIIEncoding();
        byte[] dataInBytes = encoding.GetBytes(data);
        using (System.Security.Cryptography.HMAC Hmac = new HMACSHA1())
        {
            Hmac.Key = encoding.GetBytes(privateKeyClean);

            byte[] hash = Hmac.ComputeHash(dataInBytes, 0, dataInBytes.Length);
            sig = Convert.ToBase64String(hash, 0, hash.Length);
        }
        return sig;


    }

person Eliran Eliassy    schedule 22.12.2016    source источник


Ответы (2)


Я решил эту проблему, используя bouncycastle:

    private static string ComputeSignature()
    {
        AsymmetricCipherKeyPair asymmetricCipherKeyPair;
        using (TextReader textReader = new StreamReader("myprivatekey.pem"))
        {
            asymmetricCipherKeyPair = (AsymmetricCipherKeyPair)new PemReader(textReader).ReadObject();
        }
        DsaPrivateKeyParameters parameters = (DsaPrivateKeyParameters)asymmetricCipherKeyPair.Private;
        string text = TEXTTOENC;
        if (!string.IsNullOrEmpty(userName))
        {
            text += userName;
        }
        Console.Out.WriteLine("Data: {0}", text);
        byte[] bytes = Encoding.ASCII.GetBytes(text);
        DsaDigestSigner dsaDigestSigner = new DsaDigestSigner(new DsaSigner(), new Sha1Digest());
        dsaDigestSigner.Init(true, parameters);
        dsaDigestSigner.BlockUpdate(bytes, 0, bytes.Length);
        byte[] inArray = dsaDigestSigner.GenerateSignature();
        string text2 = Convert.ToBase64String(inArray);
        Console.WriteLine("Signature: {0}", text2);
        return text2;
    }
person Eliran Eliassy    schedule 16.02.2017

Причина, по которой подпись DSA здесь не работает, заключается в том, что вы вообще не выполняете DSA. Вы выполняете HMAC-SHA-1, используя содержимое файла ключа в качестве ключа HMAC.

  1. Считайте ключевые параметры DSA из файла.

В .NET нет встроенной поддержки чтения файлов ключей PEM. Но в вашем заголовке упоминается BouncyCastle, поэтому вы, вероятно, можете адаптировать принятый ответ к Как прочитать закрытый ключ PEM RSA из .NET в DSA (используя PemReader).

В качестве альтернативы вы можете использовать OpenSSL для создания самозаверяющего сертификата на основе этого ключа и поместить ключ сертификата + в PFX. .NET может нормально загружать PFX.

  1. Заполните объект DSA.

Если вы пойдете по пути PFX, cert.GetDSAPrivateKey() сделает все правильно (.NET 4.6.2). В версиях старше 4.6.2 вы можете использовать cert.PrivateKey as DSA, который будет работать только для DSA, совместимого с FIPS 186-2 (DSA был обновлен в FIPS 186-3).

Если вы используете BouncyCastle для чтения ключевых параметров PEM, вы можете придерживаться BouncyCastle или сделать что-то вроде using (DSA dsa = DSA.Create()) { dsa.ImportParameters(parametersFromTheFile); /* other stuff here */ }. (DSA.Create() предоставит объект, ограниченный FIPS-186-2 в .NET Framework, но может соответствовать FIPS-186-3 в .NET Core).

  1. Подпишите данные

FIPS-186-2 допускает только SHA-1 в качестве алгоритма хэширования, FIPS-186-3 допускает семейство SHA-2 (SHA256, SHA384, SHA512). Мы предполагаем, что вы используете FIPS-186-2/SHA-1 (если нет, то необходимые замены, надеюсь, очевидны).

BouncyCastle: Однако они вычисляют подписи. (Извините, я не знаком с их API)

.NET 4.6.1 или старше:

using (SHA1 hash = SHA1.Create())
{
    signature = dsa.CreateSignature(hash.ComputeHash(dataInBytes));
}

.NET 4.6.2 или новее:

signature = dsa.SignData(dataInBytes, HashAlgorithmName.SHA1);

Мыльница

Затем, когда все сказано и сделано (или, возможно, раньше): спросите себя: «Почему я использую DSA?». В FIPS 186-2 (и более ранних версиях) DSA ограничен размером ключа 1024 бит и хэшем SHA-1. NIST SP800-57 классифицирует SHA-1 и DSA. -1024, оба имеют 80-битную защиту (таблицы 2 и 3). NIST классифицировал 80 бит безопасности как «устаревшие» для 2011–2013 гг. и «запрещенные» для 2014 г. и далее (таблица 4). Современное использование DSA (для объектов, на которые распространяются рекомендации NIST) требует поддержки FIPS-186-3.

ECDSA получает ~keysize/2 бита безопасности; таким образом, самый низкий (обычно поддерживаемый) размер ключа ECDSA (ключи, основанные на NIST P-256/secp256r1) обеспечивает 128-битную безопасность, что NIST оценивает как хорошее для 2031+.

RSA также является лучшим выбором, чем DSA, потому что он имеет гораздо большую поддержку подписей, которые все еще считаются безопасными NIST.

Хотя, если вы соблюдаете протокол, я думаю, вариантов не так много.

person bartonjs    schedule 22.12.2016
comment
Привет, во-первых - спасибо за подробный ответ. теперь я еще не нашел решения, но, похоже, вы помогли мне добраться туда, просто нужно немного больше направлений. Я думаю, что недостающая часть сейчас заключается в том, как создать объект DSA из файла закрытого ключа PEM. я видел много примеров с RSA, но не с DSA. я попытался сгенерировать DSACryptoServiceProvider из открытого ключа и импортировать параметры, и он также получил ту же ошибку неверной подписи. Для использования DSA, а не RSA - это не от меня зависит... :\ - person Eliran Eliassy; 23.12.2016