Java 使用来自 RFC7748 的测试向量时,X25519 共享机密不正确
Java X25519 shared secret is not correct when using testing vectors from RFC7748
使用RFC7748 test vectors for elliptic curve diffie hellman in java, I cannot get expected shared secret key. I am able to do so in other languages. I am using openjdk 11 with default Sun security provider. I found official tests which use these test vectors. But I cannot get expected result even if I copy-paste and run them. For instance, here is test that uses these same vectors which will fail if I copy-paste and run locally. It uses some utility functions which are from here时,我也复制了。我知道我一定做错了什么,但我无法弄清楚到底是什么。这是我的代码:
public class main {
public static BigInteger hexStringToBigInteger(boolean clearHighBit, String str) {
BigInteger result = BigInteger.ZERO;
for (int i = 0; i < str.length() / 2; i++) {
int curVal = Character.digit(str.charAt(2 * i), 16);
curVal <<= 4;
curVal += Character.digit(str.charAt(2 * i + 1), 16);
if (clearHighBit && i == str.length() / 2 - 1) {
curVal &= 0x7F;
result = result.add(BigInteger.valueOf(curVal).shiftLeft(8 * i));
}
}
return result;
}
public static byte[] hexStringToByteArray(String str) {
byte[] result = new byte[str.length() / 2];
for (int i = 0; i < result.length; i++) {
result[i] = (byte) Character.digit(str.charAt(2 * i), 16);
result[i] <<= 4;
result[i] += Character.digit(str.charAt(2 * i + 1), 16);
}
return result;
}
public static String byteArrayToHexString(byte[] arr) {
StringBuilder result = new StringBuilder();
for (byte curVal : arr) {
result.append(Character.forDigit(curVal >> 4 & 0xF, 16));
result.append(Character.forDigit(curVal & 0xF, 16));
}
return result.toString();
}
private static void runDiffieHellmanTest(String curveName, String a_pri,
String b_pub, String result) throws Exception {
NamedParameterSpec paramSpec = new NamedParameterSpec(curveName);
KeyFactory kf = KeyFactory.getInstance("XDH");
KeySpec privateSpec = new XECPrivateKeySpec(paramSpec, hexStringToByteArray(a_pri));
PrivateKey privateKey = kf.generatePrivate(privateSpec);
boolean clearHighBit = curveName.equals("X25519");
KeySpec publicSpec = new XECPublicKeySpec(paramSpec, hexStringToBigInteger(clearHighBit, b_pub));
PublicKey publicKey = kf.generatePublic(publicSpec);
byte[] encodedPrivateKey = privateKey.getEncoded();
System.out.println("Encoded private: " + byteArrayToHexString(encodedPrivateKey));
byte[] encodedPublicKey = publicKey.getEncoded();
System.out.println("Encoded public: " + byteArrayToHexString(encodedPublicKey));
KeyAgreement ka = KeyAgreement.getInstance("XDH");
ka.init(privateKey);
ka.doPhase(publicKey, true);
byte[] sharedSecret = ka.generateSecret();
byte[] expectedResult = hexStringToByteArray(result);
if (!Arrays.equals(sharedSecret, expectedResult)) {
throw new RuntimeException("fail: expected=" + result + ", actual="
+ byteArrayToHexString(sharedSecret));
}
}
public static void main(String[] args) throws Exception {
runDiffieHellmanTest(
"X25519",
"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
}
}
您在 hexStringToBigInteger
中错误地交换了两行:
if (clearHighBit && i == str.length() / 2 - 1) {
curVal &= 0x7F;
result = result.add(BigInteger.valueOf(curVal).shiftLeft(8 * i));
}
应该改为:
if (clearHighBit && i == str.length() / 2 - 1) {
curVal &= 0x7F;
}
result = result.add(BigInteger.valueOf(curVal).shiftLeft(8 * i));
我无法在 Go 和 Java 应用程序之间建立共享秘密,所以我试图调试是什么原因导致我阅读 RFC7748
并挖掘 [= 的源代码11=] Java 中的密钥交换。因此,对于想要在 Java 和其他 non-Java 应用程序之间执行 X25519
密钥交换的人来说 - 这是主要内容。 Java 已经期望输入 public 键是 BigInteger
而不是字节数组。一些其他语言可能 return public 键作为 big-endian
格式的字节数组。由于 RFC7748
规范,椭圆曲线上的点的 X
坐标(这是您的 public 关键字节数组) 必须采用 little-endian
格式。因此,在输入 BigInteger
.
之前,您只需反转输入 public 键字节数组使其成为 little-endian
使用RFC7748 test vectors for elliptic curve diffie hellman in java, I cannot get expected shared secret key. I am able to do so in other languages. I am using openjdk 11 with default Sun security provider. I found official tests which use these test vectors. But I cannot get expected result even if I copy-paste and run them. For instance, here is test that uses these same vectors which will fail if I copy-paste and run locally. It uses some utility functions which are from here时,我也复制了。我知道我一定做错了什么,但我无法弄清楚到底是什么。这是我的代码:
public class main {
public static BigInteger hexStringToBigInteger(boolean clearHighBit, String str) {
BigInteger result = BigInteger.ZERO;
for (int i = 0; i < str.length() / 2; i++) {
int curVal = Character.digit(str.charAt(2 * i), 16);
curVal <<= 4;
curVal += Character.digit(str.charAt(2 * i + 1), 16);
if (clearHighBit && i == str.length() / 2 - 1) {
curVal &= 0x7F;
result = result.add(BigInteger.valueOf(curVal).shiftLeft(8 * i));
}
}
return result;
}
public static byte[] hexStringToByteArray(String str) {
byte[] result = new byte[str.length() / 2];
for (int i = 0; i < result.length; i++) {
result[i] = (byte) Character.digit(str.charAt(2 * i), 16);
result[i] <<= 4;
result[i] += Character.digit(str.charAt(2 * i + 1), 16);
}
return result;
}
public static String byteArrayToHexString(byte[] arr) {
StringBuilder result = new StringBuilder();
for (byte curVal : arr) {
result.append(Character.forDigit(curVal >> 4 & 0xF, 16));
result.append(Character.forDigit(curVal & 0xF, 16));
}
return result.toString();
}
private static void runDiffieHellmanTest(String curveName, String a_pri,
String b_pub, String result) throws Exception {
NamedParameterSpec paramSpec = new NamedParameterSpec(curveName);
KeyFactory kf = KeyFactory.getInstance("XDH");
KeySpec privateSpec = new XECPrivateKeySpec(paramSpec, hexStringToByteArray(a_pri));
PrivateKey privateKey = kf.generatePrivate(privateSpec);
boolean clearHighBit = curveName.equals("X25519");
KeySpec publicSpec = new XECPublicKeySpec(paramSpec, hexStringToBigInteger(clearHighBit, b_pub));
PublicKey publicKey = kf.generatePublic(publicSpec);
byte[] encodedPrivateKey = privateKey.getEncoded();
System.out.println("Encoded private: " + byteArrayToHexString(encodedPrivateKey));
byte[] encodedPublicKey = publicKey.getEncoded();
System.out.println("Encoded public: " + byteArrayToHexString(encodedPublicKey));
KeyAgreement ka = KeyAgreement.getInstance("XDH");
ka.init(privateKey);
ka.doPhase(publicKey, true);
byte[] sharedSecret = ka.generateSecret();
byte[] expectedResult = hexStringToByteArray(result);
if (!Arrays.equals(sharedSecret, expectedResult)) {
throw new RuntimeException("fail: expected=" + result + ", actual="
+ byteArrayToHexString(sharedSecret));
}
}
public static void main(String[] args) throws Exception {
runDiffieHellmanTest(
"X25519",
"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
}
}
您在 hexStringToBigInteger
中错误地交换了两行:
if (clearHighBit && i == str.length() / 2 - 1) {
curVal &= 0x7F;
result = result.add(BigInteger.valueOf(curVal).shiftLeft(8 * i));
}
应该改为:
if (clearHighBit && i == str.length() / 2 - 1) {
curVal &= 0x7F;
}
result = result.add(BigInteger.valueOf(curVal).shiftLeft(8 * i));
我无法在 Go 和 Java 应用程序之间建立共享秘密,所以我试图调试是什么原因导致我阅读 RFC7748
并挖掘 [= 的源代码11=] Java 中的密钥交换。因此,对于想要在 Java 和其他 non-Java 应用程序之间执行 X25519
密钥交换的人来说 - 这是主要内容。 Java 已经期望输入 public 键是 BigInteger
而不是字节数组。一些其他语言可能 return public 键作为 big-endian
格式的字节数组。由于 RFC7748
规范,椭圆曲线上的点的 X
坐标(这是您的 public 关键字节数组) 必须采用 little-endian
格式。因此,在输入 BigInteger
.
little-endian