繁体   English   中英

bash / openssl中的移植签名功能,它使用RSA私钥文件(PEM)到C#

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM