[英]Porting signing function in bash/openssl which uses an RSA private key file (PEM) to C#
我正在尝试编写一些C#代码,这些代码将允许我向Chef服务器发出请求。 在遵循Chef服务器API的文档之后,我试图在我的C#代码中获取规范的标头,以便我可以对服务器进行身份验证并发出请求。
我在与我的客户证书一起使用的厨师文档中找到了以下脚本(请参见“ cURL”下的内容)。 调用此脚本可从服务器返回预期的响应JSON。 脚本中用于对规范标头进行签名的部分是:
method="GET"
hashed_path=$(echo -n "/organizations/[org]/nodes" | openssl dgst -sha1 -binary | openssl enc -base64) #where [org] is my organization
hashed_body=$(echo -n "" | openssl dgst -sha1 -binary | openssl enc -base64)
timestamp=$(date -u "+%Y-%m-%dT%H:%M:%SZ")
canonical_request="Method:$method\nHashed Path:$hashed_path\nX-Ops-Content-Hash:$hashed_body\nX-Ops-Timestamp:$timestamp\nX-Ops-UserId:$client_name"
auth_headers=$(printf "$canonical_request" | openssl rsautl -sign -inkey \
"$(_chef_dir)/${client_name}.pem" | openssl enc -base64 | _chomp | awk '{ll=int(length/60);i=0; \
while (i<=ll) {printf " -H X-Ops-Authorization-%s:%s", i+1, substr($0,i*60+1,60);i=i+1}}')
以上代码段的重要部分是$(printf "$canonical_request" | openssl rsautl -sign -inkey "$(_chef_dir)/${client_name}.pem" | openssl enc -base64
。
我有一些C#代码是我从GitHub上的dotnet-chef-api改编而成的,我正在尝试做同样的事情。 它使用BouncyCastle密码库对内容进行签名。
private string Sign(string privateKey)
{
var method = _method.ToString().ToUpperInvariant(); //evals to 'GET'
var hashedPath = _requestUri.AbsolutePath.ToBase64EncodedSha1String(); //evals to hash of '/organizations/[org]/nodes'
var contentHash = _body.ToBase64EncodedSha1String(); //evals to hash of empty string
var canonicalHeader = $"Method:{method}\nHashed Path:{hashedPath}\nX-Ops-Content-Hash:{contentHash}\nX-Ops-Timestamp:{_timestamp}\nX-Ops-UserId:{_client}";
var input = Encoding.UTF8.GetBytes(canonicalHeader);
using (var stringReader = new StringReader(privateKey))
{
var pemReader = new PemReader(stringReader);
var key = ((AsymmetricCipherKeyPair) pemReader.ReadObject()).Private;
var signer = new RsaDigestSigner(new NullDigest());
signer.Init(true, key);
signer.BlockUpdate(input, 0, input.Length);
return Convert.ToBase64String(signer.GenerateSignature());
}
}
我已经通过调试器和许多echo
语句验证了bash脚本中的规范头与C#代码中的规范头完全相同。 但是,我完全停留在签名部分。 我从GitHub项目获取的代码没有改变,但是生成的Base64字符串与我从bash脚本获得的字符串不同(已删除时间戳记)。
如何以与用openssl工具签名相同的方式在C#中签名? 我曾尝试将“ NullDigest”切换为其他类型,但没有找到能产生与openssl二进制文件相同的Base64结果的代码。 如果.NET框架中已经存在更好的方法,我也乐于接受。
我需要使用PKCS#1v1.5来代替@oliv建议的直接使用RSA操作。 我的C#方法中的代码变为:
private string Sign(string privateKey)
{
var method = _method.ToString().ToUpperInvariant();
var hashedPath = _requestUri.AbsolutePath.ToBase64EncodedSha1String();
var contentHash = _body.ToBase64EncodedSha1String();
var canonicalHeader = $"Method:{method}\nHashed Path:{hashedPath}\nX-Ops-Content-Hash:{contentHash}\nX-Ops-Timestamp:{_timestamp}\nX-Ops-UserId:{_client}";
var input = Encoding.UTF8.GetBytes(canonicalHeader);
using (var stringReader = new StringReader(privateKey))
{
var pemReader = new PemReader(stringReader);
var keyPair = (AsymmetricCipherKeyPair) pemReader.ReadObject();
var pkcs1Encoding = new Pkcs1Encoding(new RsaBlindedEngine());
pkcs1Encoding.Init(true, keyPair.Private);
var signature = pkcs1Encoding.ProcessBlock(input, 0, input.Length);
return Convert.ToBase64String(signature);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.