cryptography - 如何在 .NET Framework 中读取 ES512 私钥
问题描述
我正在尝试读取 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
}
});
}
}
解决方案
While .NET Core directly supports the import of key formats like PKCS#1, PKCS#8, SEC1 and X.509/SPKI, this is not the case with .NET Framework. Here is one way to use BouncyCastle. E.g. for the posted SEC1 key:
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;
Signing/verifying is supported by BouncyCastle's SignerUtilities
class, e.g:
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();
The generated signature is returned in ASN.1 format. Newer BC versions also support SHA-512withPLAIN-ECDSA
, which returns a signature in r|s format. This is interesting in the context of JWT, because JWT uses the r|s format.
Alternatively, an ECDsa
instance can be applied for signing/verifying (as obviously intended in the code posted in the question):
ECDsa ecdsa = ECDsa.Create(ecParams);
where the Create()
method expects a System.Security.Cryptography.ECParameters
instance. The latter can be derived from the ECPrivateKeyParameters
/ECPublicKeyParameters
instances, which is described in detail in this SO answer.
推荐阅读
- angular - 如果 Angular 5 打字稿中不存在,则添加事件侦听器
- python - 使用 Python 从文本中打印一些想要的行
- httpclient - 使用 boost::beast 解码 Ntrip 1.0 协议的最佳方法是什么
- twilio - Twilio Studio Chatbot - 连接 2 个呼叫者
- ios - ARKit - 如何在另一个 SCNNode 中包含 SCNText(讲话泡泡)
- c# - ASP.NET Web API 2 在单独的项目中使用实体框架
- c# - X509Certificate2 Import PathTooLongException:指定的路径、文件名或两者都太长
- python - 使用 matplotlib 创建随机形状/轮廓
- string - __str__ 在 python 中给出二维表的可视化表示
- php - 为 PHP 7.2.6 问题安装 MongoDB PECL