使用 PEM 文件中的 DSA 私钥获取字符串的 SHA1 符号

Get SHA1 sign of string with DSA private key from PEM file

我有一个包含我的 DSA 私钥的 PEM 文件,我需要用这个私钥签署一个字符串才能将它发送给我的合作伙伴 API。 (附代码)

出于某种原因,我总是收到来自我的合作伙伴的签名无效 API。这意味着标志的格式不正确。

我的合作伙伴让我使用 bouncycastle for c#,但我找不到任何示例说明如何使用来自外部 PEM 文件的 DSA 对字符串进行签名。

我可以在这里找到任何示例吗?

谢谢。

我尝试用我写的方法对字符串进行签名:

 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;


    }

此处 DSA 签名失败的原因是您根本没有进行 DSA。您正在 HMAC-SHA-1 使用密钥文件的内容作为 HMAC 密钥。

  1. 从文件中读取 DSA 密钥参数。

.NET 不支持读取 PEM 密钥文件。但是您的标题提到了 BouncyCastle,因此您可以将接受的答案 How to read a PEM RSA private key from .NET 调整为 DSA(使用 PemReader)。

或者,您可以使用 OpenSSL 基于此密钥制作 self-signed 证书,并将证书+密钥放入 PFX 中。 .NET 可以很好地加载 PFX。

  1. 填充 DSA object。

如果你走 PFX 路线,cert.GetDSAPrivateKey() 会做正确的事 (.NET 4.6.2)。在 4.6.2 之前的版本上,您可以使用 cert.PrivateKey as DSA,它仅适用于兼容 FIPS 186-2 的 DSA(DSA 在 FIPS 186-3 中升级)。

如果您使用 BouncyCastle 来读取 PEM 关键参数,那么您可以坚持使用 BouncyCastle 或执行类似 using (DSA dsa = DSA.Create()) { dsa.ImportParameters(parametersFromTheFile); /* other stuff here */ } 的操作。 (DSA.Create() 将在 .NET Framework 上提供 object 限制为 FIPS-186-2,但它可以在 .NET Core 上执行 FIPS-186-3。

  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);

肥皂盒

然后,一旦一切都说完了(或者,也许之前):问问自己 "why am I using DSA?"。在 FIPS 186-2(及之前)中,DSA 仅限于 1024 位密钥大小和 SHA-1 散列。 NIST SP800-57 将 SHA-1 和 DSA-1024 归类为具有 80 位安全性(Tables 2 和 3)。 NIST 将 80 位安全性分类为 2011-2013 年的 "Deprecated" 和 2014 年及以后的 "Disallowed" (Table 4)。 DSA 的现代使用(对于受 NIST 建议约束的实体)需要 FIPS-186-3 支持。

ECDSA 获得 ~keysize/2 位安全性;所以最低的(普遍支持的)ECDSA 密钥大小(基于 NIST P-256/secp256r1 的密钥)获得 128 位的安全性,NIST 对 2031+ 的评价是好的。

RSA 也是比 DSA 更好的选择,因为它对仍然被 NIST 认为安全的签名提供更广泛的支持。

不过,如果您要遵守某个协议,我想没有太多选择。

我使用 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;
    }