如标题所示,如何使用 Java 15+ 从私钥 (byte[]) 派生 ed25519 公钥(没有像 BouncyCastle 这样的依赖项)。
BouncyCastle 很简单:
byte[] rawPrivateKey = ...;
Ed25519PrivateKeyParameters privateKeyRebuild = new Ed25519PrivateKeyParameters(rawPrivateKey , 0);
Ed25519PublicKeyParameters publicKeyRebuild = privateKeyRebuild.generatePublicKey();
byte[] rawPublicKey = publicKeyRebuild.getEncoded();
openssl 有 EVP_PKEY_get_raw_public_key 方法。
Java 15 支持 ed25519,但我不明白如何使用它。由于https://openjdk.org/jeps/396,ed25519内部无法访问,那么还有可能吗?
您可以通过一个技巧来实现这一点:生成一个密钥对并强制密钥对生成器使用您的私钥而不是生成新的私钥。通过此过程,所讨论的公钥是使用内置 EC 算法隐式导出的(否则您无法访问该算法,因为它不会公开):
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.spec.NamedParameterSpec;
import java.util.Arrays;
...
byte[] rawPrivateKey = {...}; // 32 bytes raw private key
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("Ed25519");
keyPairGenerator.initialize(new NamedParameterSpec("Ed25519"), new StaticSecureRandom(rawPrivateKey));
byte[] spki = keyPairGenerator.generateKeyPair().getPublic().getEncoded(); // public key in SPKI format; the last 32 bytes are the raw public key
byte[] rawPublicKey = Arrays.copyOfRange(spki, spki.length - 32, spki.length); // 32 bytes raw public key
为了使用指定私钥生成密钥,需要派生
SecureRandom
,其中 nextBytes()
被适当覆盖:
class StaticSecureRandom extends SecureRandom {
private byte[] privateKey;
public StaticSecureRandom(byte[] privateKey) {
this.privateKey = privateKey;
}
public void nextBytes(byte[] bytes) {
System.arraycopy(privateKey, 0, bytes, 0, privateKey.length);
}
}
这个解决方案基于这篇文章,通过这种方式从X25519的私钥中提取公钥。