C# 和 Java 之间的 Diffie-Hellman 算法
Diffie-Hellman algorithm between C# and Java
我在 c# 和 Java 中有控制台应用程序。它们都为 Eliptic 曲线 Diffie-Hellman 算法生成 public 和私钥。 Public 密钥在 base64 中加密,然后在控制台中打印。然后我将 public 密钥从 c# 粘贴到 java 程序中,反之亦然。 不幸的是,最后必须相同的派生密钥不同。似乎算法的配置相同,没有例外。
C#:
static void Main(string[] args)
{
ECDiffieHellmanCng eCDiffie = new ECDiffieHellmanCng(256);
eCDiffie.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
eCDiffie.HashAlgorithm = CngAlgorithm.Sha256;
byte[] myPublicKey = eCDiffie.ExportSubjectPublicKeyInfo(); //export in x509 format
String myPublicKeyBase64 = Convert.ToBase64String(myPublicKey);
Console.WriteLine(myPublicKeyBase64);
string otherKey = Console.ReadLine(); // here paste public key in console from Java
byte[] otherKeyFromBase64 = Convert.FromBase64String(otherKey);
ECDiffieHellmanCng eCDiffie2 = new ECDiffieHellmanCng(256);
eCDiffie2.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
eCDiffie2.HashAlgorithm = CngAlgorithm.Sha256;
int some = 0;
eCDiffie2.ImportSubjectPublicKeyInfo(otherKeyFromBase64, out some);
byte[] otherKeyDecoded = eCDiffie2.PublicKey.ToByteArray();
CngKey k = CngKey.Import(otherKeyDecoded, CngKeyBlobFormat.EccPublicBlob);
byte[] derivedKey = eCDiffie.DeriveKeyMaterial(k);
String derivedKeyBase64 = Convert.ToBase64String(derivedKey);
Console.WriteLine("Derived key: ");
Console.WriteLine(derivedKeyBase64);
}
Java:
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
// Generate ephemeral ECDH keypair
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(256);
KeyPair kp = kpg.generateKeyPair();
byte[] ourPk = kp.getPublic().getEncoded(); //public key in x509 format
// Display our public key
byte[] ourPublicKeyBase64 = Base64.getEncoder().encode(ourPk);
System.out.println(String.format("Public Key: %s", new String(ourPublicKeyBase64)));
// Read other's public key:
Scanner in = new Scanner(System.in);
String oth = in.nextLine(); // here paste in console public key C#
byte[] otherPk = Base64.getDecoder().decode(oth);
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(otherPk);
PublicKey otherPublicKey = kf.generatePublic(pkSpec);
// Perform key agreement
KeyAgreement ka = KeyAgreement.getInstance("ECDH");
ka.init(kp.getPrivate());
ka.doPhase(otherPublicKey, true);
// Read shared secret
byte[] sharedSecret = ka.generateSecret();
// Derive a key from the shared secret and both public keys
MessageDigest hash = MessageDigest.getInstance("SHA-256");
hash.update(sharedSecret);
// Simple deterministic ordering
List<ByteBuffer> keys = Arrays.asList(ByteBuffer.wrap(ourPk), ByteBuffer.wrap(otherPk));
Collections.sort(keys);
hash.update(keys.get(0));
hash.update(keys.get(1));
byte[] derivedKey = hash.digest();
byte[] derivedKeyBase64 = Base64.getEncoder().encode(derivedKey);
System.out.println(String.format("Derived key: %s", new String(derivedKeyBase64)));
}
您的 Java
代码做了一些额外的工作来获取派生密钥。只需删除以下行,您将获得与 С#
代码中相同的密钥:
// Simple deterministic ordering
List<ByteBuffer> keys = Arrays.asList(ByteBuffer.wrap(ourPk), ByteBuffer.wrap(otherPk));
Collections.sort(keys);
hash.update(keys.get(0));
hash.update(keys.get(1));
这里是完整的 Java
代码:
public static void main(String[] args) throws Exception {
// Generate ephemeral ECDH keypair
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(256);
KeyPair kp = kpg.generateKeyPair();
byte[] ourPk = kp.getPublic().getEncoded(); //public key in x509 format
// Display our public key
byte[] ourPublicKeyBase64 = Base64.getEncoder().encode(ourPk);
System.out.println(String.format("Public Key: %s", new String(ourPublicKeyBase64)));
// Read other's public key:
Scanner in = new Scanner(System.in);
String oth = in.nextLine(); // here paste in console public key C#
byte[] otherPk = Base64.getDecoder().decode(oth);
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(otherPk);
PublicKey otherPublicKey = kf.generatePublic(pkSpec);
// Perform key agreement
KeyAgreement ka = KeyAgreement.getInstance("ECDH");
ka.init(kp.getPrivate());
ka.doPhase(otherPublicKey, true);
// Read shared secret
byte[] sharedSecret = ka.generateSecret();
// Derive a key from the shared secret
MessageDigest hash = MessageDigest.getInstance("SHA-256");
hash.update(sharedSecret);
byte[] derivedKey = hash.digest();
byte[] derivedKeyBase64 = Base64.getEncoder().encode(derivedKey);
System.out.println(String.format("Derived key: %s", new String(derivedKeyBase64)));
}
我在 c# 和 Java 中有控制台应用程序。它们都为 Eliptic 曲线 Diffie-Hellman 算法生成 public 和私钥。 Public 密钥在 base64 中加密,然后在控制台中打印。然后我将 public 密钥从 c# 粘贴到 java 程序中,反之亦然。 不幸的是,最后必须相同的派生密钥不同。似乎算法的配置相同,没有例外。
C#:
static void Main(string[] args)
{
ECDiffieHellmanCng eCDiffie = new ECDiffieHellmanCng(256);
eCDiffie.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
eCDiffie.HashAlgorithm = CngAlgorithm.Sha256;
byte[] myPublicKey = eCDiffie.ExportSubjectPublicKeyInfo(); //export in x509 format
String myPublicKeyBase64 = Convert.ToBase64String(myPublicKey);
Console.WriteLine(myPublicKeyBase64);
string otherKey = Console.ReadLine(); // here paste public key in console from Java
byte[] otherKeyFromBase64 = Convert.FromBase64String(otherKey);
ECDiffieHellmanCng eCDiffie2 = new ECDiffieHellmanCng(256);
eCDiffie2.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
eCDiffie2.HashAlgorithm = CngAlgorithm.Sha256;
int some = 0;
eCDiffie2.ImportSubjectPublicKeyInfo(otherKeyFromBase64, out some);
byte[] otherKeyDecoded = eCDiffie2.PublicKey.ToByteArray();
CngKey k = CngKey.Import(otherKeyDecoded, CngKeyBlobFormat.EccPublicBlob);
byte[] derivedKey = eCDiffie.DeriveKeyMaterial(k);
String derivedKeyBase64 = Convert.ToBase64String(derivedKey);
Console.WriteLine("Derived key: ");
Console.WriteLine(derivedKeyBase64);
}
Java:
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
// Generate ephemeral ECDH keypair
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(256);
KeyPair kp = kpg.generateKeyPair();
byte[] ourPk = kp.getPublic().getEncoded(); //public key in x509 format
// Display our public key
byte[] ourPublicKeyBase64 = Base64.getEncoder().encode(ourPk);
System.out.println(String.format("Public Key: %s", new String(ourPublicKeyBase64)));
// Read other's public key:
Scanner in = new Scanner(System.in);
String oth = in.nextLine(); // here paste in console public key C#
byte[] otherPk = Base64.getDecoder().decode(oth);
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(otherPk);
PublicKey otherPublicKey = kf.generatePublic(pkSpec);
// Perform key agreement
KeyAgreement ka = KeyAgreement.getInstance("ECDH");
ka.init(kp.getPrivate());
ka.doPhase(otherPublicKey, true);
// Read shared secret
byte[] sharedSecret = ka.generateSecret();
// Derive a key from the shared secret and both public keys
MessageDigest hash = MessageDigest.getInstance("SHA-256");
hash.update(sharedSecret);
// Simple deterministic ordering
List<ByteBuffer> keys = Arrays.asList(ByteBuffer.wrap(ourPk), ByteBuffer.wrap(otherPk));
Collections.sort(keys);
hash.update(keys.get(0));
hash.update(keys.get(1));
byte[] derivedKey = hash.digest();
byte[] derivedKeyBase64 = Base64.getEncoder().encode(derivedKey);
System.out.println(String.format("Derived key: %s", new String(derivedKeyBase64)));
}
您的 Java
代码做了一些额外的工作来获取派生密钥。只需删除以下行,您将获得与 С#
代码中相同的密钥:
// Simple deterministic ordering
List<ByteBuffer> keys = Arrays.asList(ByteBuffer.wrap(ourPk), ByteBuffer.wrap(otherPk));
Collections.sort(keys);
hash.update(keys.get(0));
hash.update(keys.get(1));
这里是完整的 Java
代码:
public static void main(String[] args) throws Exception {
// Generate ephemeral ECDH keypair
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(256);
KeyPair kp = kpg.generateKeyPair();
byte[] ourPk = kp.getPublic().getEncoded(); //public key in x509 format
// Display our public key
byte[] ourPublicKeyBase64 = Base64.getEncoder().encode(ourPk);
System.out.println(String.format("Public Key: %s", new String(ourPublicKeyBase64)));
// Read other's public key:
Scanner in = new Scanner(System.in);
String oth = in.nextLine(); // here paste in console public key C#
byte[] otherPk = Base64.getDecoder().decode(oth);
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(otherPk);
PublicKey otherPublicKey = kf.generatePublic(pkSpec);
// Perform key agreement
KeyAgreement ka = KeyAgreement.getInstance("ECDH");
ka.init(kp.getPrivate());
ka.doPhase(otherPublicKey, true);
// Read shared secret
byte[] sharedSecret = ka.generateSecret();
// Derive a key from the shared secret
MessageDigest hash = MessageDigest.getInstance("SHA-256");
hash.update(sharedSecret);
byte[] derivedKey = hash.digest();
byte[] derivedKeyBase64 = Base64.getEncoder().encode(derivedKey);
System.out.println(String.format("Derived key: %s", new String(derivedKeyBase64)));
}