C# - 将 public 密钥 blob 导入 ECDiffieHellmanCng
C# - importing a public key blob into ECDiffieHellmanCng
我在使用 ECDiffieHellmanCng class:
交换密钥时遇到问题
第 1 步 - 创建 public 密钥
public byte[] CreatePublicKey()
{
using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng())
{
cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
cng.HashAlgorithm = CngAlgorithm.Sha512;
return cng.PublicKey.ToByteArray();
}
}
步骤 2 - 交换并获取私钥
public byte[] CreatePrivateKey(byte[] publicKey1, byte[] publicKey2)
{
using(ECDiffieHellmanCng cng = new ECDiffieHellmanCng(CngKey.Import(publicKey1, CngKeyBlobFormat.EccPublicBlob)))
{
cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
cng.HashAlgorithm = CngAlgorithm.Sha512;
return cng.DeriveKeyMaterial(CngKey.Import(publicKey2, CngKeyBlobFormat.EccPublicBlob));
}
}
例子
byte[] alicePublicKey = CreatePublicKey();
byte[] bobPublicKey = CreatePublicKey();
// This fails
byte[] alicePrivateKey = CreatePrivateKey(alicePublicKey, bobPublicKey);
byte[] bobPrivateKey = CreatePrivateKey(bobPublicKey, alicePublicKey);
具体来说,它在 CreatePrivateKey(...)
方法的这一行上失败了:
return cng.DeriveKeyMaterial(CngKey.Import(publicKey2, CngKeyBlobFormat.EccPublicBlob));
错误
System.Security.Cryptography.CryptographicException: 'Key does not exist.'
我做错了什么?
问题是您正在尝试使用两个 public 密钥导出共享密钥(DeriveKeyMaterial
的结果)。这是行不通的,因为您需要一方的私钥和另一方的 public 密钥(不需要第一方的 public 密钥,因为它可以从私钥派生) .这是一个示例(我修正了一些术语,因为现在它们具有误导性 - CreatePrivateKey
不创建私钥)。请注意,您通常不会像这样导出私钥并将它们存储在容器中,所以这只是一个例子:
public static (byte[] publicKey, byte[] privateKey) CreateKeyPair() {
using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng(
// need to do this to be able to export private key
CngKey.Create(
CngAlgorithm.ECDiffieHellmanP256,
null,
new CngKeyCreationParameters
{ ExportPolicy = CngExportPolicies.AllowPlaintextExport }))) {
cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
cng.HashAlgorithm = CngAlgorithm.Sha512;
// export both private and public keys and return
var pr = cng.Key.Export(CngKeyBlobFormat.EccPrivateBlob);
var pub = cng.PublicKey.ToByteArray();
return (pub, pr);
}
}
public static byte[] CreateSharedSecret(byte[] privateKey, byte[] publicKey) {
// this returns shared secret, not private key
// initialize algorithm with private key of one party
using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng(CngKey.Import(privateKey, CngKeyBlobFormat.EccPrivateBlob))) {
cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
cng.HashAlgorithm = CngAlgorithm.Sha512;
// use public key of another party
return cng.DeriveKeyMaterial(CngKey.Import(publicKey, CngKeyBlobFormat.EccPublicBlob));
}
}
现在有以上两个功能:
var aliceKeyPair = CreateKeyPair();
var bobKeyPair = CreateKeyPair();
byte[] bobSharedSecret = CreateSharedSecret(bobKeyPair.privateKey, aliceKeyPair.publicKey);
byte[] aliceSharedSecret = CreateSharedSecret(aliceKeyPair.privateKey, bobKeyPair.publicKey);
// derived shared secrets are the same - the whole point of this algoritm
Debug.Assert(aliceSharedSecret.SequenceEqual(bobSharedSecret));
我在使用 ECDiffieHellmanCng class:
交换密钥时遇到问题第 1 步 - 创建 public 密钥
public byte[] CreatePublicKey()
{
using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng())
{
cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
cng.HashAlgorithm = CngAlgorithm.Sha512;
return cng.PublicKey.ToByteArray();
}
}
步骤 2 - 交换并获取私钥
public byte[] CreatePrivateKey(byte[] publicKey1, byte[] publicKey2)
{
using(ECDiffieHellmanCng cng = new ECDiffieHellmanCng(CngKey.Import(publicKey1, CngKeyBlobFormat.EccPublicBlob)))
{
cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
cng.HashAlgorithm = CngAlgorithm.Sha512;
return cng.DeriveKeyMaterial(CngKey.Import(publicKey2, CngKeyBlobFormat.EccPublicBlob));
}
}
例子
byte[] alicePublicKey = CreatePublicKey();
byte[] bobPublicKey = CreatePublicKey();
// This fails
byte[] alicePrivateKey = CreatePrivateKey(alicePublicKey, bobPublicKey);
byte[] bobPrivateKey = CreatePrivateKey(bobPublicKey, alicePublicKey);
具体来说,它在 CreatePrivateKey(...)
方法的这一行上失败了:
return cng.DeriveKeyMaterial(CngKey.Import(publicKey2, CngKeyBlobFormat.EccPublicBlob));
错误
System.Security.Cryptography.CryptographicException: 'Key does not exist.'
我做错了什么?
问题是您正在尝试使用两个 public 密钥导出共享密钥(DeriveKeyMaterial
的结果)。这是行不通的,因为您需要一方的私钥和另一方的 public 密钥(不需要第一方的 public 密钥,因为它可以从私钥派生) .这是一个示例(我修正了一些术语,因为现在它们具有误导性 - CreatePrivateKey
不创建私钥)。请注意,您通常不会像这样导出私钥并将它们存储在容器中,所以这只是一个例子:
public static (byte[] publicKey, byte[] privateKey) CreateKeyPair() {
using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng(
// need to do this to be able to export private key
CngKey.Create(
CngAlgorithm.ECDiffieHellmanP256,
null,
new CngKeyCreationParameters
{ ExportPolicy = CngExportPolicies.AllowPlaintextExport }))) {
cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
cng.HashAlgorithm = CngAlgorithm.Sha512;
// export both private and public keys and return
var pr = cng.Key.Export(CngKeyBlobFormat.EccPrivateBlob);
var pub = cng.PublicKey.ToByteArray();
return (pub, pr);
}
}
public static byte[] CreateSharedSecret(byte[] privateKey, byte[] publicKey) {
// this returns shared secret, not private key
// initialize algorithm with private key of one party
using (ECDiffieHellmanCng cng = new ECDiffieHellmanCng(CngKey.Import(privateKey, CngKeyBlobFormat.EccPrivateBlob))) {
cng.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
cng.HashAlgorithm = CngAlgorithm.Sha512;
// use public key of another party
return cng.DeriveKeyMaterial(CngKey.Import(publicKey, CngKeyBlobFormat.EccPublicBlob));
}
}
现在有以上两个功能:
var aliceKeyPair = CreateKeyPair();
var bobKeyPair = CreateKeyPair();
byte[] bobSharedSecret = CreateSharedSecret(bobKeyPair.privateKey, aliceKeyPair.publicKey);
byte[] aliceSharedSecret = CreateSharedSecret(aliceKeyPair.privateKey, bobKeyPair.publicKey);
// derived shared secrets are the same - the whole point of this algoritm
Debug.Assert(aliceSharedSecret.SequenceEqual(bobSharedSecret));