获取临时密钥 x 和 y 坐标
Get Ephemeral key x and y coordinates
使用 .NET Core 3.1,C#。
我对这些加密的东西一点都不擅长。有人可以帮助我吗?
如何获取新生成的临时 public 密钥 X 和 Y 字节? [编辑:得到这个工作!请参阅下面的代码]。
如何生成未散列的 DerivedKeyMaterial?也许这没有意义,但我被要求不申请 ecdh.HashAlgorithm = CngAlgorithm.Sha256;
但 null 不是一个选项。
这是我目前正在做的获取 X 和 Y 字节的操作,但我认为这是错误的,因为当我在控制台中打印出来时,它与客户端生成的密钥不同。
public byte[] GetEphSecret(byte[] myPublicKey) {
using var ecdh = new ECDiffieHellmanCng();
ecdh.ImportSubjectPublicKeyInfo(myPublicKey, out _);
ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
ecdh.HashAlgorithm = CngAlgorithm.Sha256;
ecdh.GenerateKey(ECCurve.NamedCurves.nistP256);
// 1. Obtain Ephemeral Key public x and y [Edit: Succesfully obtained with the following:]
var x = ecdh.PublicKey.ExportParameters().Q.X;
var y = ecdh.PublicKey.ExportParameters().Q.Y;
CngKey cngKey = ImportEcPublicKey(myPublicKey);
// 2. Is it possible to derive a Key that is not hashed?
var derivedKey = ecdh.DeriveKeyMaterial(cngKey);
return derivedKeyMaterial;
}
既然第一个问题已经自己回答了,那我就只说第二个问题了。
ECDiffieHellmanCng#DeriveKeyMaterial()
不是 return 原始密钥协议,而只是从中派生的值。而且,所使用的函数是不可逆的,所以无法确定原来的密钥约定。
密钥派生的详细信息在 ECDiffieHellmanCng#KeyDerivationFunction
and ECDiffieHellmanCng#HashAlgorithm
属性中配置。在发布的代码中,密钥协议的 SHA256 哈希是 returned (ECDiffieHellmanKeyDerivationFunction.Hash
, CngAlgorithm.Sha256
).
没有强制return编辑原始密钥协议的选项,另请参阅 and here。因此,要确定原始密钥协议,只能使用其他库或从头开始重新计算密钥协议。
关于第一个变体,BouncyCastle 是一个选项。一种可能的实现是:
private static byte[] GetKeyAgreementBC(X9ECParameters ecParams, ECPoint publicKey, byte[] privateKey)
{
ECDomainParameters eCDomainParameters = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N);
Org.BouncyCastle.Math.EC.ECCurve curve = eCDomainParameters.Curve;
Org.BouncyCastle.Math.EC.ECPoint pubKey = curve.CreatePoint(new BigInteger(1, publicKey.X), new BigInteger(1, publicKey.Y));
BigInteger privKey = new BigInteger(1, privateKey);
ECPublicKeyParameters ecPubKeyParams = new ECPublicKeyParameters("ECDH", pubKey, SecObjectIdentifiers.SecP256r1);
ECPrivateKeyParameters ecPrivKeyParams = new ECPrivateKeyParameters(privKey, eCDomainParameters);
IBasicAgreement basicAgreement = AgreementUtilities.GetBasicAgreement("ECDH");
basicAgreement.Init(ecPrivKeyParams);
byte[] keyAgreement = basicAgreement.CalculateAgreement(ecPubKeyParams).ToByteArrayUnsigned();
return keyAgreement;
}
关于第二种变体,必须记住一方的密钥协议是 EC 点的 X 坐标,它是通过将这一方的私钥与 public 密钥相乘获得的另一方面,参见Elliptic-curve Diffie-Hellman(使用椭圆曲线的算法)。同样,可以针对必要的计算使用 BouncyCastle。一个可能的实现是:
private static byte[] GetKeyAgreementExplicit(X9ECParameters ecParams, ECPoint publicKey, byte[] privateKey)
{
ECDomainParameters eCDomainParameters = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N);
Org.BouncyCastle.Math.EC.ECCurve curve = eCDomainParameters.Curve;
Org.BouncyCastle.Math.EC.ECPoint pubKey = curve.CreatePoint(new BigInteger(1, publicKey.X), new BigInteger(1, publicKey.Y));
BigInteger privKey = new BigInteger(1, privateKey);
Org.BouncyCastle.Math.EC.ECPoint keyAgreementECPoint = pubKey.Multiply(privKey).Normalize();
byte[] keyAgreement = keyAgreementECPoint.XCoord.ToBigInteger().ToByteArrayUnsigned();
return keyAgreement;
}
如前所述,这两种实现在功能上是相同的,因此可以互换。可以使用以下代码对其进行测试:
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Security.Cryptography;
...
using (var ecdhAlice = new ECDiffieHellmanCng())
using (var ecdhBob = new ECDiffieHellmanCng())
{
// Generate Alice's private and public key
ecdhAlice.HashAlgorithm = CngAlgorithm.Sha256;
ecdhAlice.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
ecdhAlice.GenerateKey(ECCurve.NamedCurves.nistP256);
byte[] privateKeyAlice = ecdhAlice.ExportParameters(true).D;
ECPoint publicKeyAlice = ecdhAlice.ExportParameters(false).Q;
// Generate Bob's private and public key
ecdhBob.HashAlgorithm = CngAlgorithm.Sha256;
ecdhBob.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
ecdhBob.GenerateKey(ECCurve.NamedCurves.nistP256);
byte[] privateKeyBob = ecdhBob.ExportParameters(true).D;
ECPoint publicKeyBob = ecdhBob.ExportParameters(false).Q;
// Alice's key agreement
byte[] keyAgreementAlice = GetKeyAgreementBC(NistNamedCurves.GetByName("P-256"), publicKeyBob, privateKeyAlice);
byte[] keyAgreementSHA256Alice = SHA256.Create().ComputeHash(keyAgreementAlice);
byte[] keyAgreementCngAlice = ecdhAlice.DeriveKeyMaterial(ecdhBob.PublicKey);
Console.WriteLine("Alice's raw key agreement (BC): " + Hex.ToHexString(keyAgreementAlice));
Console.WriteLine("Alice's hashed key agreement (BC): " + Hex.ToHexString(keyAgreementSHA256Alice));
Console.WriteLine("Alice's key agreement (.NET): " + Hex.ToHexString(keyAgreementCngAlice));
Console.WriteLine();
// Bob's key agreement
byte[] keyAgreementBob = GetKeyAgreementExplicit(NistNamedCurves.GetByName("P-256"), publicKeyAlice, privateKeyBob);
byte[] keyAgreementSHA256Bob = SHA256.Create().ComputeHash(keyAgreementBob);
byte[] keyAgreementCngBob = ecdhBob.DeriveKeyMaterial(ecdhAlice.PublicKey);
Console.WriteLine("Bob's raw key agreement (explicit): " + Hex.ToHexString(keyAgreementBob));
Console.WriteLine("Bob's hashed key agreement (explicit): " + Hex.ToHexString(keyAgreementSHA256Bob));
Console.WriteLine("Bob's key agreement (.NET): " + Hex.ToHexString(keyAgreementCngBob));
Console.WriteLine();
}
为简单起见,该示例省略了导出 public 密钥(例如使用 ExportSubjectPublicKeyInfo()
)和导入(例如使用 ImportSubjectPublicKeyInfo()
)的步骤。当代码被执行时,例如输出结果如下:
Alice's raw key agreement (BC): d6f337d4c0d8e8bb34848d4f0c1c6834f66f69bbf9f284df5b87c7aee0584fc7
Alice's hashed key agreement (BC): fb95a6b3b95d0882fa6796c28aa5f1a88d14c5b9a3f302b5deae50316cb7a273
Alice's key agreement (.NET): fb95a6b3b95d0882fa6796c28aa5f1a88d14c5b9a3f302b5deae50316cb7a273
Bob's raw key agreement (explicit): d6f337d4c0d8e8bb34848d4f0c1c6834f66f69bbf9f284df5b87c7aee0584fc7
Bob's hashed key agreement (explicit): fb95a6b3b95d0882fa6796c28aa5f1a88d14c5b9a3f302b5deae50316cb7a273
Bob's key agreement (.NET): fb95a6b3b95d0882fa6796c28aa5f1a88d14c5b9a3f302b5deae50316cb7a273
在代码中,Alice 的原始密钥协议 keyAgreementAlice
是用 GetKeyAgreementBC()
生成的,Bob 的原始密钥协议 keyAgreementBob
是用 GetKeyAgreementExplicit()
生成的。两个实现的等价性体现在两个变体 return 相同的原始密钥协议。
此外,ECDiffieHellmanCng#DeriveKeyMaterial()
(即 keyAgreementCngAlice
和 keyAgreementCngBob
的(散列)密钥协议分别在 SHA256 散列(即 keyAgreementSHA256Alice
和 [=由于上述原因,29=] 分别从原始密钥协议生成。
使用 .NET Core 3.1,C#。
我对这些加密的东西一点都不擅长。有人可以帮助我吗?
如何获取新生成的临时 public 密钥 X 和 Y 字节? [编辑:得到这个工作!请参阅下面的代码]。
如何生成未散列的 DerivedKeyMaterial?也许这没有意义,但我被要求不申请
ecdh.HashAlgorithm = CngAlgorithm.Sha256;
但 null 不是一个选项。
这是我目前正在做的获取 X 和 Y 字节的操作,但我认为这是错误的,因为当我在控制台中打印出来时,它与客户端生成的密钥不同。
public byte[] GetEphSecret(byte[] myPublicKey) {
using var ecdh = new ECDiffieHellmanCng();
ecdh.ImportSubjectPublicKeyInfo(myPublicKey, out _);
ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
ecdh.HashAlgorithm = CngAlgorithm.Sha256;
ecdh.GenerateKey(ECCurve.NamedCurves.nistP256);
// 1. Obtain Ephemeral Key public x and y [Edit: Succesfully obtained with the following:]
var x = ecdh.PublicKey.ExportParameters().Q.X;
var y = ecdh.PublicKey.ExportParameters().Q.Y;
CngKey cngKey = ImportEcPublicKey(myPublicKey);
// 2. Is it possible to derive a Key that is not hashed?
var derivedKey = ecdh.DeriveKeyMaterial(cngKey);
return derivedKeyMaterial;
}
既然第一个问题已经自己回答了,那我就只说第二个问题了。
ECDiffieHellmanCng#DeriveKeyMaterial()
不是 return 原始密钥协议,而只是从中派生的值。而且,所使用的函数是不可逆的,所以无法确定原来的密钥约定。
密钥派生的详细信息在 ECDiffieHellmanCng#KeyDerivationFunction
and ECDiffieHellmanCng#HashAlgorithm
属性中配置。在发布的代码中,密钥协议的 SHA256 哈希是 returned (ECDiffieHellmanKeyDerivationFunction.Hash
, CngAlgorithm.Sha256
).
没有强制return编辑原始密钥协议的选项,另请参阅
关于第一个变体,BouncyCastle 是一个选项。一种可能的实现是:
private static byte[] GetKeyAgreementBC(X9ECParameters ecParams, ECPoint publicKey, byte[] privateKey)
{
ECDomainParameters eCDomainParameters = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N);
Org.BouncyCastle.Math.EC.ECCurve curve = eCDomainParameters.Curve;
Org.BouncyCastle.Math.EC.ECPoint pubKey = curve.CreatePoint(new BigInteger(1, publicKey.X), new BigInteger(1, publicKey.Y));
BigInteger privKey = new BigInteger(1, privateKey);
ECPublicKeyParameters ecPubKeyParams = new ECPublicKeyParameters("ECDH", pubKey, SecObjectIdentifiers.SecP256r1);
ECPrivateKeyParameters ecPrivKeyParams = new ECPrivateKeyParameters(privKey, eCDomainParameters);
IBasicAgreement basicAgreement = AgreementUtilities.GetBasicAgreement("ECDH");
basicAgreement.Init(ecPrivKeyParams);
byte[] keyAgreement = basicAgreement.CalculateAgreement(ecPubKeyParams).ToByteArrayUnsigned();
return keyAgreement;
}
关于第二种变体,必须记住一方的密钥协议是 EC 点的 X 坐标,它是通过将这一方的私钥与 public 密钥相乘获得的另一方面,参见Elliptic-curve Diffie-Hellman(使用椭圆曲线的算法)。同样,可以针对必要的计算使用 BouncyCastle。一个可能的实现是:
private static byte[] GetKeyAgreementExplicit(X9ECParameters ecParams, ECPoint publicKey, byte[] privateKey)
{
ECDomainParameters eCDomainParameters = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N);
Org.BouncyCastle.Math.EC.ECCurve curve = eCDomainParameters.Curve;
Org.BouncyCastle.Math.EC.ECPoint pubKey = curve.CreatePoint(new BigInteger(1, publicKey.X), new BigInteger(1, publicKey.Y));
BigInteger privKey = new BigInteger(1, privateKey);
Org.BouncyCastle.Math.EC.ECPoint keyAgreementECPoint = pubKey.Multiply(privKey).Normalize();
byte[] keyAgreement = keyAgreementECPoint.XCoord.ToBigInteger().ToByteArrayUnsigned();
return keyAgreement;
}
如前所述,这两种实现在功能上是相同的,因此可以互换。可以使用以下代码对其进行测试:
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Security.Cryptography;
...
using (var ecdhAlice = new ECDiffieHellmanCng())
using (var ecdhBob = new ECDiffieHellmanCng())
{
// Generate Alice's private and public key
ecdhAlice.HashAlgorithm = CngAlgorithm.Sha256;
ecdhAlice.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
ecdhAlice.GenerateKey(ECCurve.NamedCurves.nistP256);
byte[] privateKeyAlice = ecdhAlice.ExportParameters(true).D;
ECPoint publicKeyAlice = ecdhAlice.ExportParameters(false).Q;
// Generate Bob's private and public key
ecdhBob.HashAlgorithm = CngAlgorithm.Sha256;
ecdhBob.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
ecdhBob.GenerateKey(ECCurve.NamedCurves.nistP256);
byte[] privateKeyBob = ecdhBob.ExportParameters(true).D;
ECPoint publicKeyBob = ecdhBob.ExportParameters(false).Q;
// Alice's key agreement
byte[] keyAgreementAlice = GetKeyAgreementBC(NistNamedCurves.GetByName("P-256"), publicKeyBob, privateKeyAlice);
byte[] keyAgreementSHA256Alice = SHA256.Create().ComputeHash(keyAgreementAlice);
byte[] keyAgreementCngAlice = ecdhAlice.DeriveKeyMaterial(ecdhBob.PublicKey);
Console.WriteLine("Alice's raw key agreement (BC): " + Hex.ToHexString(keyAgreementAlice));
Console.WriteLine("Alice's hashed key agreement (BC): " + Hex.ToHexString(keyAgreementSHA256Alice));
Console.WriteLine("Alice's key agreement (.NET): " + Hex.ToHexString(keyAgreementCngAlice));
Console.WriteLine();
// Bob's key agreement
byte[] keyAgreementBob = GetKeyAgreementExplicit(NistNamedCurves.GetByName("P-256"), publicKeyAlice, privateKeyBob);
byte[] keyAgreementSHA256Bob = SHA256.Create().ComputeHash(keyAgreementBob);
byte[] keyAgreementCngBob = ecdhBob.DeriveKeyMaterial(ecdhAlice.PublicKey);
Console.WriteLine("Bob's raw key agreement (explicit): " + Hex.ToHexString(keyAgreementBob));
Console.WriteLine("Bob's hashed key agreement (explicit): " + Hex.ToHexString(keyAgreementSHA256Bob));
Console.WriteLine("Bob's key agreement (.NET): " + Hex.ToHexString(keyAgreementCngBob));
Console.WriteLine();
}
为简单起见,该示例省略了导出 public 密钥(例如使用 ExportSubjectPublicKeyInfo()
)和导入(例如使用 ImportSubjectPublicKeyInfo()
)的步骤。当代码被执行时,例如输出结果如下:
Alice's raw key agreement (BC): d6f337d4c0d8e8bb34848d4f0c1c6834f66f69bbf9f284df5b87c7aee0584fc7
Alice's hashed key agreement (BC): fb95a6b3b95d0882fa6796c28aa5f1a88d14c5b9a3f302b5deae50316cb7a273
Alice's key agreement (.NET): fb95a6b3b95d0882fa6796c28aa5f1a88d14c5b9a3f302b5deae50316cb7a273
Bob's raw key agreement (explicit): d6f337d4c0d8e8bb34848d4f0c1c6834f66f69bbf9f284df5b87c7aee0584fc7
Bob's hashed key agreement (explicit): fb95a6b3b95d0882fa6796c28aa5f1a88d14c5b9a3f302b5deae50316cb7a273
Bob's key agreement (.NET): fb95a6b3b95d0882fa6796c28aa5f1a88d14c5b9a3f302b5deae50316cb7a273
在代码中,Alice 的原始密钥协议 keyAgreementAlice
是用 GetKeyAgreementBC()
生成的,Bob 的原始密钥协议 keyAgreementBob
是用 GetKeyAgreementExplicit()
生成的。两个实现的等价性体现在两个变体 return 相同的原始密钥协议。
此外,ECDiffieHellmanCng#DeriveKeyMaterial()
(即 keyAgreementCngAlice
和 keyAgreementCngBob
的(散列)密钥协议分别在 SHA256 散列(即 keyAgreementSHA256Alice
和 [=由于上述原因,29=] 分别从原始密钥协议生成。