Java/Kotlin 以 JCE 密钥对实例和 OpenSSH 格式输出 Ed25519 密钥对

Java/Kotlin Output Ed25519 keypair as both JCE KeyPair instance and in OpenSSH format

我正在使用 BouncyCastle 库在我的 Kotlin 应用程序中生成 Ed25519 密钥对,并且有两个要求很容易单独实现,但似乎很难一前一后地实现:

我有两个使用 BouncyCastle 生成密钥的选项,每个选项只满足其中一个要求。

直接使用BouncyCastle生成器生成

val generator = Ed25519KeyPairGenerator()
generator.init(Ed25519KeyGenerationParameters(SecureRandom()))
val pair = generator.generateKeyPair()

这给了我一个包含 Ed25519PublicKeyParameters 的密钥,这使得使用 BouncyCastle 提供的 OpenSSHPublicKeyUtil 获取 OpenSSH .pub 格式非常容易:

"ssh-ed25519 " + toBase64(OpenSSHPublicKeyUtil.encodePublicKey(publicKey))

...但是没有明显的方法可以从这里进入 JCE KeyPair。 BouncyCastle JCE 实现似乎使用 BCEdDSAPublicKeyBCEdDSAPrivateKey 作为包装器 类 正是为了这个目的,但它们的构造函数是包私有的。

使用 BouncyCastle 作为 JCE 安全提供程序生成

Security.addProvider(BouncyCastleProvider())
val keyPairGenerator: KeyPairGenerator = KeyPairGenerator.getInstance(EdDSAParameterSpec.Ed25519, BouncyCastleProvider.PROVIDER_NAME)
keyPairGenerator.initialize(EdDSAParameterSpec(EdDSAParameterSpec.Ed25519), SecureRandom())
val pair = keyPairGenerator.generateKeyPair()

这给了我正在寻找的 JCE KeyPair,但没有明显的方法可以将它转换为 OpenSSH .pub 格式。 this RSA-specific question 中的答案都只支持 DSA/RSA,或者建议似乎也无法处理 Ed25519 密钥的库。我试过:

我认为我需要的

以下任意一项:

使用反射进行黑客攻击(包装到扩展 属性 的 getter 中),遵循方式 #2(从 BCEdDSAPublicKey 获取 Ed25519PublicKeyParameters 实例):

val BCEdDSAPublicKey.pubKey
    get() = BCEdDSAPublicKey::class.declaredMemberProperties
        .find { it.returnType.javaType == AsymmetricKeyParameter::class.java }!!
        .apply { isAccessible = true }
        .get(this) as AsymmetricKeyParameter