-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
11, 26
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
Windows 11
A DESCRIPTION OF THE PROBLEM :
According to the specification in [RFC 7748, Chapter 5][1], the implementation MUST ensure that the most significant bit of the input u-coordinate is cleared for X25519.
This is currently not the case, which is why the current implementation does not satisfy the second test vector for X25519 in [RFC 7748, Chapter 5.2][2].
If the most significant bit is explicitly cleared, the correct result is produced.
Please note that there is an erratum for this test vector ([Errata ID 5568][3]). However, this has been rejected, meaning that the original test vector is valid. This is also confirmed by processing with other libraries such as BouncyCastle (Java) or pyca/cryptography (Python), which produce the correct result for this test vector.
[1]: https://datatracker.ietf.org/doc/html/rfc7748#section-5
[2]: https://datatracker.ietf.org/doc/html/rfc7748#section-5.2
[3]: https://www.rfc-editor.org/errata/eid5568
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Step 1: Execute the code below for the input u-coordinate 0xe5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493, which corresponds to the official test vector from RFC 7748.
Step 2: Set the most significant bit of the input u-coordinate to 0 (note that X25519 uses little endian), which changes the last byte of the input u-coordinate from 0x93 to 0x13: 0xe5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a413 and execute the code for this input u-coordinate again.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
In both cases, the output u-coordinate should be 0x95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957, which corresponds to the output u-coordinate of the official test vector from RFC 7748.
ACTUAL -
For step 1, the output u-coordinate is 0xd5f33573c9f6b8129483acce1e2534e95d3c41af6b00d0d30437b87cada57e4a, which does not correspond to the output u-coordinate of the official test vector from RFC 7748.
For step 2, the output u-coordinate is 0x95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957, which corresponds to the output u-coordinate of the official test vector from RFC 7748.
---------- BEGIN SOURCE ----------
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.NamedParameterSpec;
import java.security.spec.XECPrivateKeySpec;
import java.security.spec.XECPublicKeySpec;
import java.util.HexFormat;
import javax.crypto.KeyAgreement;
public class Main {
// https://openjdk.org/jeps/324
public static void main(String[] args) throws Exception {
byte[] publicKey = HexFormat.of().parseHex("e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493");
//byte[] publicKey = HexFormat.of().parseHex("e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a413");
byte[] privateKey = HexFormat.of().parseHex("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d");
NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
KeyFactory kf = KeyFactory.getInstance("XDH");
reverse(publicKey);
BigInteger u = new BigInteger(1, publicKey);
XECPublicKeySpec pubSpec = new XECPublicKeySpec(paramSpec, u);
PublicKey pubKey = kf.generatePublic(pubSpec);
XECPrivateKeySpec privSpec = new XECPrivateKeySpec(paramSpec, privateKey);
PrivateKey privKey = kf.generatePrivate(privSpec);
KeyAgreement ka = KeyAgreement.getInstance("XDH");
ka.init(privKey);
ka.doPhase(pubKey, true);
byte[] secret = ka.generateSecret();
System.out.println( HexFormat.of().formatHex(secret));
}
private static void reverse(byte[] array) {
for(int i = 0; i < array.length / 2; i++)
{
byte temp = array[i];
array[i] = array[array.length - i - 1];
array[array.length - i - 1] = temp;
}
}
}
---------- END SOURCE ----------
Windows 11
A DESCRIPTION OF THE PROBLEM :
According to the specification in [RFC 7748, Chapter 5][1], the implementation MUST ensure that the most significant bit of the input u-coordinate is cleared for X25519.
This is currently not the case, which is why the current implementation does not satisfy the second test vector for X25519 in [RFC 7748, Chapter 5.2][2].
If the most significant bit is explicitly cleared, the correct result is produced.
Please note that there is an erratum for this test vector ([Errata ID 5568][3]). However, this has been rejected, meaning that the original test vector is valid. This is also confirmed by processing with other libraries such as BouncyCastle (Java) or pyca/cryptography (Python), which produce the correct result for this test vector.
[1]: https://datatracker.ietf.org/doc/html/rfc7748#section-5
[2]: https://datatracker.ietf.org/doc/html/rfc7748#section-5.2
[3]: https://www.rfc-editor.org/errata/eid5568
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Step 1: Execute the code below for the input u-coordinate 0xe5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493, which corresponds to the official test vector from RFC 7748.
Step 2: Set the most significant bit of the input u-coordinate to 0 (note that X25519 uses little endian), which changes the last byte of the input u-coordinate from 0x93 to 0x13: 0xe5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a413 and execute the code for this input u-coordinate again.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
In both cases, the output u-coordinate should be 0x95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957, which corresponds to the output u-coordinate of the official test vector from RFC 7748.
ACTUAL -
For step 1, the output u-coordinate is 0xd5f33573c9f6b8129483acce1e2534e95d3c41af6b00d0d30437b87cada57e4a, which does not correspond to the output u-coordinate of the official test vector from RFC 7748.
For step 2, the output u-coordinate is 0x95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957, which corresponds to the output u-coordinate of the official test vector from RFC 7748.
---------- BEGIN SOURCE ----------
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.NamedParameterSpec;
import java.security.spec.XECPrivateKeySpec;
import java.security.spec.XECPublicKeySpec;
import java.util.HexFormat;
import javax.crypto.KeyAgreement;
public class Main {
// https://openjdk.org/jeps/324
public static void main(String[] args) throws Exception {
byte[] publicKey = HexFormat.of().parseHex("e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493");
//byte[] publicKey = HexFormat.of().parseHex("e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a413");
byte[] privateKey = HexFormat.of().parseHex("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d");
NamedParameterSpec paramSpec = new NamedParameterSpec("X25519");
KeyFactory kf = KeyFactory.getInstance("XDH");
reverse(publicKey);
BigInteger u = new BigInteger(1, publicKey);
XECPublicKeySpec pubSpec = new XECPublicKeySpec(paramSpec, u);
PublicKey pubKey = kf.generatePublic(pubSpec);
XECPrivateKeySpec privSpec = new XECPrivateKeySpec(paramSpec, privateKey);
PrivateKey privKey = kf.generatePrivate(privSpec);
KeyAgreement ka = KeyAgreement.getInstance("XDH");
ka.init(privKey);
ka.doPhase(pubKey, true);
byte[] secret = ka.generateSecret();
System.out.println( HexFormat.of().formatHex(secret));
}
private static void reverse(byte[] array) {
for(int i = 0; i < array.length / 2; i++)
{
byte temp = array[i];
array[i] = array[array.length - i - 1];
array[array.length - i - 1] = temp;
}
}
}
---------- END SOURCE ----------
- relates to
-
JDK-8181595 JEP 324: Key Agreement with Curve25519 and Curve448
-
- Closed
-