Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion sshlib/src/main/kotlin/org/connectbot/sshlib/crypto/KeyTypes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,23 +121,48 @@ 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<Ed25519PublicKey>(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<Ed25519PrivateKey>(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<InvalidKeyException> {
factory.translateKey(foreignKey)
}
}

@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<InvalidKeyException> {
factory.translateKey(foreignKey)
Expand Down
Loading