c# - 需要能够从 C#(dotnet-core)代码中获得与 openssl rsautl -sign -inkey 相同的签名
问题描述
对于 ac# dotnet-core 应用程序(windows 和 linux)和 Chef.io API 之间的通信,我需要能够在 c# dotnet core 中创建与 openssl 可执行文件调用相同的签名:
openssl rsautl -in encryption.txt -sign -inkey chefprivatekey.pem | openssl enc -base64
第一个实现(dotnet 框架)基于此 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 一切都可以正常工作,但是如果我通过为此使用 nuget-package 将 dll 更新到较新的版本,那么就没有任何效果了。作为一种解决方法,我已经实现了 openssl 可执行文件的系统调用,以获取 API 的正确签名。这工作正常。但我需要摆脱系统调用。我现在所做的是将 openssl exe 的系统调用结果与我从任何签名算法(如 BouncyCastle lib)获得的结果进行比较。我无法获得与上述调用 openssl-exe 相同的结果。对于 Windows 和 Linux,实现需要是 dotnet-core。只要 openssl exe 和任何 c# 实现之间的结果不一样,我就不需要测试 chef-api。如何从 C# 中的文件加载 RSA 公钥。使用此代码,我可以从 pem 文件中获取 RSACryptoServiceProvider 类型的对象。
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 这可能是个问题吗?
解决方案
我自己找到了解决方案。我查看了 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;
}
}