Необходимо иметь возможность получить ту же сигнатуру из кода C # (dotnet-core), что и openssl rsautl -sign -inkey - PullRequest
1 голос
/ 18 октября 2019

Для связи между приложением ac # dotnet-core (windows и linux) и Chef.io API мне нужно иметь возможность создать такую ​​же сигнатуру в ядре c # dotnet, как этот вызов исполняемого файла openssl:

openssl rsautl -in encryption.txt -sign -inkey chefprivatekey.pem |openssl enc -base64

Первая реализация (dotnet framework) была основана на этом https://github.com/mattberther/dotnet-chef-api:

        byte[] input = Encoding.UTF8.GetBytes(canonicalHeader);

        var pemReader = new PemReader(new StringReader(privateKey));
        AsymmetricKeyParameter key = ((AsymmetricCipherKeyPair)pemReader.ReadObject()).Private;

        ISigner signer = new RsaDigestSigner(new NullDigest());
        signer.Init(true, key);
        signer.BlockUpdate(input, 0, input.Length);
        _signature = Convert.ToBase64String(signer.GenerateSignature());

Пакет nuget dotnet-chef-api содержит также старую версиюBouncyCastle.Crypto.dll. Пока я использую эту dll, все работает нормально, но если я обновлю dll до более новой версии, используя для этого пакет nuget, то ничего больше не будет работать. В качестве обходного пути я реализовал системный вызов исполняемого файла openssl, чтобы получить правильную сигнатуру для API. Это отлично работает. Но мне нужно избавиться от системных вызовов. Сейчас я сравнил результат системного вызова openssl exe с результатами, полученными из любых алгоритмов подписания, таких как BouncyCastle lib. Я не смог получить тот же результат, что и вышеупомянутый вызов openssl-exe. Реализация должна быть dotnet-core для Windows и Linux. Поскольку результаты между openssl exe и любой реализацией на c # не совпадают, я не буду тестировать chef-api. Мне удалось создать System.Security.Cryptography.RSACryptoServiceProvider из файла pem, следуя этому примеру: Как загрузить открытый ключ RSA из файла в C # . с помощью этого кода я могу получить объект типа RSACryptoServiceProvider из файла pem.

        RSACryptoServiceProvider provider = PemKeyUtils.GetRSAProviderFromPemFile(pemFile);
        var trial1 = Convert.ToBase64String(provider.SignData(Convert.FromBase64String("test"), new SHA1CryptoServiceProvider()));

Содержимое «trial1» такое же, как «_signature», но не такое же, как в openssl.exe. ЧтоЯ делаю неправильно?

"openssl rsautl" по умолчанию использует PKCS # 1 v1.5, может ли это быть проблемой?

1 Ответ

1 голос
/ 21 октября 2019

Нашел решение самостоятельно. Я заглянул в Unittests BouncyCastle и получил это как рабочее решение:

public string Sign(byte[] input, string privateKeyPath)
    {
        asymmetricKeyParameter AsymmetricKeyParameterFromPrivateKeyInPemFile
        // Sign the hash

        IBufferedCipher c = CipherUtilities.GetCipher("RSA//PKCS1Padding");

        c.Init(true, asymmetricKeyParameter);

        var outBytes = c.DoFinal(input);
        return Convert.ToBase64String(outBytes);
    }

    public AsymmetricKeyParameter AsymmetricKeyParameterFromPrivateKeyInPemFile(string privateKeyPath)
    {
        using (TextReader privateKeyTextReader = new StringReader(File.ReadAllText(privateKeyPath)))
        {
            PemReader pr = new PemReader(privateKeyTextReader);
            AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)pr.ReadObject();
            return keyPair.Private;
        }
    }
...