如何在 .NET Framework 中读取 ES512 私钥

Posted

技术标签:

【中文标题】如何在 .NET Framework 中读取 ES512 私钥【英文标题】:How to read ES512 private key in .NET Framework 【发布时间】:2020-11-15 12:07:35 【问题描述】:

我正在尝试读取 ES512 私钥以在 .NET Framework 4.7.2 中创建 JWT 令牌,但在创建 ECDsa 对象时它会引发验证异常。

System.Security.Cryptography.CryptographicException: 'The specified key parameters are not valid. Q.X and Q.Y are required fields. Q.X, Q.Y must be the same length. If D is specified it must be the same length as Q.X and Q.Y for named curves or the same length as Order for explicit curves.'

这里有什么问题?我检查了互联网,找不到任何解决方案。在 NET Core 3 中,它使用 ImportECPrivateKey 方法,但我不知道如何在我需要的 .NET Framework 中执行此操作。

class Program

    static string privateKey = @"MIHcAgEBBEIBiyAa7aRHFDCh2qga9sTUGINE5jHAFnmM8xWeT/uni5I4tNqhV5Xx0pDrmCV9mbroFtfEa0XVfKuMAxxfZ6LM/yKgBwYFK4EEACOhgYkDgYYABAGBzgdnP798FsLuWYTDDQA7c0r3BVk8NnRUSexpQUsRilPNv3SchO0lRw9Ru86x1khnVDx+duq4BiDFcvlSAcyjLACJvjvoyTLJiA+TQFdmrearjMiZNE25pT2yWP1NUndJxPcvVtfBW48kPOmvkY4WlqP5bAwCXwbsKrCgk6xbsp12ew==";

    static void Main(string[] args)
    
        var derArray = Convert.FromBase64String(privateKey);
        LoadPrivateKey(derArray);
    

    private static ECDsa LoadPrivateKey(byte[] key)
    
        var privKeyInt = new Org.BouncyCastle.Math.BigInteger(+1, key);
        var parameters = SecNamedCurves.GetByName("secp521r1");
        var ecPoint = parameters.G.Multiply(privKeyInt);
        var privKeyX = ecPoint.Normalize().XCoord.ToBigInteger().ToByteArrayUnsigned();
        var privKeyY = ecPoint.Normalize().YCoord.ToBigInteger().ToByteArrayUnsigned();

        return ECDsa.Create(new ECParameters
        
            Curve = ECCurve.NamedCurves.nistP521,
            D = privKeyInt.ToByteArrayUnsigned(),
            Q = new ECPoint
            
                X = privKeyX,
                Y = privKeyY
            
        );
    

【问题讨论】:

【参考方案1】:

虽然 .NET Core 直接支持导入 PKCS#1、PKCS#8、SEC1 和 X.509/SPKI 等密钥格式,但 .NET Framework 并非如此。这是使用BouncyCastle 的一种方法。例如。对于已发布的SEC1 键:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
...
string privateKey = @"-----BEGIN EC PRIVATE KEY-----
                    MIHcAgEBBEIBiyAa7aRHFDCh2qga9sTUGINE5jHAFnmM8xWeT/uni5I4tNqhV5Xx
                    0pDrmCV9mbroFtfEa0XVfKuMAxxfZ6LM/yKgBwYFK4EEACOhgYkDgYYABAGBzgdn
                    P798FsLuWYTDDQA7c0r3BVk8NnRUSexpQUsRilPNv3SchO0lRw9Ru86x1khnVDx+
                    duq4BiDFcvlSAcyjLACJvjvoyTLJiA+TQFdmrearjMiZNE25pT2yWP1NUndJxPcv
                    VtfBW48kPOmvkY4WlqP5bAwCXwbsKrCgk6xbsp12ew==
                    -----END EC PRIVATE KEY-----"; 
PemReader pemReader = new PemReader(new StringReader(privateKey));
AsymmetricCipherKeyPair ecKeyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
ECPrivateKeyParameters ecPrivateKeyParams = (ECPrivateKeyParameters)ecKeyPair.Private;
ECPublicKeyParameters ecPublicKeyParams = (ECPublicKeyParameters)ecKeyPair.Public;

BouncyCastle 的SignerUtilities 类支持签名/验证,例如:

byte[] message = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog");
ISigner signer = SignerUtilities.GetSigner("SHA-512withECDSA");
signer.Init(true, ecPrivateKeyParams);
signer.BlockUpdate(message, 0, message.Length);
byte[] signature = signer.GenerateSignature();

生成的签名以 ASN.1 格式返回。较新的 BC 版本还支持 SHA-512withPLAIN-ECDSA,它以 r|s 格式返回签名。这在 JWT 的上下文中很有趣,因为 JWT 使用 r|s 格式。

或者,ECDsa 实例可以应用于签名/验证(正如问题中发布的代码中所意图的那样):

ECDsa ecdsa = ECDsa.Create(ecParams);

Create() 方法需要一个 System.Security.Cryptography.ECParameters 实例。后者可以派生自ECPrivateKeyParameters/ECPublicKeyParameters实例,在this SO answer中有详细介绍。

【讨论】:

【参考方案2】:

这是一个 PKCS#8 / DER 编码的私钥。 DER 编码不仅仅包含私有元素。在这种情况下,它还有一个版本号、曲线的名称以及可能是 EC 公共点。您可以查看内容here on Lapo.it。重新计算公钥相对较快,因此您可以不用可选的公钥。

要对其进行解码,您需要专门的类,例如 Pkcs8PrivateKeyInfo。之后你可以extract the private key bytes from the class。请注意,它是一个 big endian 编码的数字,因此您的部分代码需要保持原样。

实际上,将私钥作为字节,我认为整个 LoadPrivateKey 仍然是正确的(除了名称,当我在名称中看到 load 时,我希望有某种 IO)。

【讨论】:

以上是关于如何在 .NET Framework 中读取 ES512 私钥的主要内容,如果未能解决你的问题,请参考以下文章

ASP.Net 控件如何从它们的数据源中读取数据?

如何升级net framework

如何查看framework版本

如何使用 Entity Framework 在读取时锁定表?

如何查看电脑.net framework版本

如何查看c#的版本.net framework