Reputation: 371
I'm trying to convert Ed25519 public key to x25519 public key in Java, using the lazysodium package:
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import com.goterl.lazysodium.LazySodium;
import com.goterl.lazysodium.LazySodiumJava;
import com.goterl.lazysodium.SodiumJava;
public class KeyOps {
public static PublicKey ed25519ToX25519(PublicKey ed25519PublicKey) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
byte[] x25519PublicKeyBytes = new byte[32];
LazySodium lazySodium = new LazySodiumJava(new SodiumJava());
byte[] ed25519PublicKeyBytes = new byte[32];
System.arraycopy(ed25519PublicKey.getEncoded(), 12, ed25519PublicKeyBytes, 0, 32);
lazySodium.convertPublicKeyEd25519ToCurve25519(x25519PublicKeyBytes, ed25519PublicKeyBytes);
return KeyFactory.getInstance("X25519", "BC").generatePublic(new X509EncodedKeySpec(x25519PublicKeyBytes));
}
}
... where ed25519PublicKey
will be generated like:
KeyPair keyPair = KeyPairGenerator.getInstance("Ed25519", "BC").generateKeyPair();
PublicKey ed25519PublicKey = keyPair.getPublic();
However, I'm getting random errors, like one of below:
An exception occured while executing the Java class. encoded key spec not recognized: failed to construct sequence from byte[]: Extra data detected in stream
or
An exception occured while executing the Java class. encoded key spec not recognized: failed to construct sequence from byte[]: corrupted stream - out of bounds length found: 57 >= 54
(57
and 54
can be other values)
May I know what's wrong here? How do I convert Ed25519 pk to x25519 pk, and convert it back to PublicKey
format?
Upvotes: 0
Views: 158
Reputation: 371
OK I figured it out.
I have no idea how to encode X25519 pk with X509EncodedKeySpec natively in Java, so I construct it manually...
public static PublicKey ed25519ToX25519(PublicKey ed25519PublicKey) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
byte[] x25519PublicKeyBytes = new byte[32];
LazySodium lazySodium = new LazySodiumJava(new SodiumJava());
byte[] ed25519PublicKeyBytes = new byte[32];
System.arraycopy(ed25519PublicKey.getEncoded(), 12, ed25519PublicKeyBytes, 0, 32);
boolean conversion_success = lazySodium.convertPublicKeyEd25519ToCurve25519(x25519PublicKeyBytes, ed25519PublicKeyBytes);
if (!conversion_success) {
System.out.println("Conversion failed!");
System.exit(1);
}
byte[] x509Header = new byte[]{
0x30, 0x2a, // SEQUENCE, length 42
0x30, 0x05, // SEQUENCE, length 5
0x06, 0x03, 0x2b, 0x65, 0x6e, // OID for X25519
0x03, 0x21, 0x00 // BIT STRING, length 33
};
// Combine the header and the key bytes
byte[] x509EncodedKey = new byte[x509Header.length + x25519PublicKeyBytes.length];
System.arraycopy(x509Header, 0, x509EncodedKey, 0, x509Header.length);
System.arraycopy(x25519PublicKeyBytes, 0, x509EncodedKey, x509Header.length, x25519PublicKeyBytes.length);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(x509EncodedKey);
KeyFactory keyFactory = KeyFactory.getInstance("X25519");
PublicKey x25519PublicKey = keyFactory.generatePublic(keySpec);
return x25519PublicKey;
}
Upvotes: 0