diff --git a/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/KeyTypes.kt b/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/KeyTypes.kt index 174b185..f7b354f 100644 --- a/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/KeyTypes.kt +++ b/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/KeyTypes.kt @@ -42,7 +42,22 @@ internal fun inferKeyType(publicKey: PublicKey): String = when (publicKey.algori "RSA" -> "ssh-rsa" - else -> throw SshException("Unsupported key type: ${publicKey.algorithm}") + else -> { + if (isEd25519Key(publicKey)) { + "ssh-ed25519" + } else { + throw SshException("Unsupported key type: ${publicKey.algorithm}") + } + } +} + +internal fun isEd25519Key(publicKey: PublicKey): Boolean { + val algorithm = publicKey.algorithm + if (algorithm == "EdDSA" || algorithm == "Ed25519" || algorithm == "1.3.101.112") { + return true + } + val className = publicKey.javaClass.name.lowercase() + return className.contains("ed25519") || className.contains("eddsa") } internal fun inferKeyType(keyPair: KeyPair): String = inferKeyType(keyPair.public) diff --git a/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ed25519/Ed25519KeyFactory.kt b/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ed25519/Ed25519KeyFactory.kt index 5f3d292..1115b32 100644 --- a/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ed25519/Ed25519KeyFactory.kt +++ b/sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/ed25519/Ed25519KeyFactory.kt @@ -48,19 +48,25 @@ internal class Ed25519KeyFactory : KeyFactorySpi() { return key } - if (key is PublicKey && key.format == "X.509") { - try { - return Ed25519PublicKey(X509EncodedKeySpec(key.encoded)) - } catch (e: InvalidKeySpecException) { - throw InvalidKeyException(e) + if (key is PublicKey) { + val encoded = key.encoded + if (encoded != null) { + try { + return Ed25519PublicKey(X509EncodedKeySpec(encoded)) + } catch (e: InvalidKeySpecException) { + throw InvalidKeyException(e) + } } } - if (key is PrivateKey && key.format == "PKCS#8") { - try { - return Ed25519PrivateKey(PKCS8EncodedKeySpec(key.encoded)) - } catch (e: InvalidKeySpecException) { - throw InvalidKeyException(e) + if (key is PrivateKey) { + val encoded = key.encoded + if (encoded != null) { + try { + return Ed25519PrivateKey(PKCS8EncodedKeySpec(encoded)) + } catch (e: InvalidKeySpecException) { + throw InvalidKeyException(e) + } } } diff --git a/sshlib/src/test/kotlin/org/connectbot/sshlib/crypto/ed25519/Ed25519KeyFactoryTest.kt b/sshlib/src/test/kotlin/org/connectbot/sshlib/crypto/ed25519/Ed25519KeyFactoryTest.kt index 82f603c..56bcff1 100644 --- a/sshlib/src/test/kotlin/org/connectbot/sshlib/crypto/ed25519/Ed25519KeyFactoryTest.kt +++ b/sshlib/src/test/kotlin/org/connectbot/sshlib/crypto/ed25519/Ed25519KeyFactoryTest.kt @@ -121,11 +121,36 @@ class Ed25519KeyFactoryTest { } @Test - fun `translateKey rejects public key with wrong format`() { + fun `translateKey converts public key with non-standard format`() { + val original = generateKeyPair().public as Ed25519PublicKey + val foreignKey = object : PublicKey { + override fun getAlgorithm() = "1.3.101.112" + override fun getFormat() = "RAW" + override fun getEncoded() = original.encoded + } + val result = factory.translateKey(foreignKey) + assertIs(result) + assertEquals(original, result) + } + + @Test + fun `translateKey converts private key with non-standard format`() { + val original = Ed25519PrivateKey(testSeed) + val foreignKey = object : PrivateKey { + override fun getAlgorithm() = "1.3.101.112" + override fun getFormat() = "RAW" + override fun getEncoded() = original.encoded + } + val resultKey = assertIs(factory.translateKey(foreignKey)) + assertContentEquals(testSeed, resultKey.getSeed()) + } + + @Test + fun `translateKey rejects public key with null encoded`() { val foreignKey = object : PublicKey { override fun getAlgorithm() = "EdDSA" override fun getFormat() = "RAW" - override fun getEncoded() = ByteArray(32) + override fun getEncoded(): ByteArray? = null } assertFailsWith { factory.translateKey(foreignKey) @@ -133,11 +158,11 @@ class Ed25519KeyFactoryTest { } @Test - fun `translateKey rejects private key with wrong format`() { + fun `translateKey rejects private key with null encoded`() { val foreignKey = object : PrivateKey { override fun getAlgorithm() = "EdDSA" override fun getFormat() = "RAW" - override fun getEncoded() = ByteArray(32) + override fun getEncoded(): ByteArray? = null } assertFailsWith { factory.translateKey(foreignKey)