java - 使用 JSch 和 PEM 私钥的 SSH,而路由器使用 openssl 密钥
问题描述
我想在 Kotlin 中使用 JSch 使用 SSL 密钥通过 SSH 连接到我的 OpenWRT 路由器。OpenWRT 支持使用 ssh-keygen ( https://openwrt.org/docs/guide-user/security/dropbear.public-key.auth ) 生成的密钥。
ssh-keygen -t rsa -b 4096
这会生成一个公共 id_rsa.pub 和私有 id_rsa 密钥。OpenWRT 接受这个 id_rsa.pub。我希望 JSch 使用私钥:
private fun sshCommand(
username: String? = "root",
host: String? = "192.168.1.1",
port: Int = 22,
command: String?
) {
GlobalScope.launch(Dispatchers.IO) {
var session: Session? = null
var channel: ChannelExec? = null
val privateKey: String = "-----BEGIN OPENSSH PRIVATE KEY-----\n" +
"...\n" +
"...\n" +
"-----END OPENSSH PRIVATE KEY-----"
try {
JSch().addIdentity("name", privateKey.toByteArray(), null, null)
session = JSch().getSession(username, host, port)
session.setConfig("PreferredAuthentications", "publickey");
session.setConfig("StrictHostKeyChecking", "no")
session.connect()
channel = session.openChannel("exec") as ChannelExec
channel.setCommand(command)
val responseStream = ByteArrayOutputStream()
channel.outputStream = responseStream
channel.connect()
while (channel.isConnected) {
Thread.sleep(100)
}
val responseString = String(responseStream.toByteArray())
println(responseString)
} finally {
session?.disconnect()
channel?.disconnect()
}
}
}
但是,这会产生错误:
com.jcraft.jsch.JSchException: invalid privatekey: [B@6166596
JSch 不支持这种密钥格式,它需要是 PEM。所以我转换了私钥:
-----BEGIN RSA PRIVATE KEY-----
.
.
.
-----END RSA PRIVATE KEY-----
但现在错误是:
com.jcraft.jsch.JSchException: Auth fail
是不是 OpenWRT 上的公钥和 JSch 上的私钥格式不同的问题?
编辑 13Feb2021:我添加了这一行:
session.setConfig("PreferredAuthentications", "publickey");
我还使用此代码向 JSch 添加了一个记录器,这是输出:
W/System.err: INFO: Connecting to 192.168.1.1 port 22
W/System.err: INFO: Connection established
W/System.err: INFO: Remote version string: SSH-2.0-dropbear
W/System.err: INFO: Local version string: SSH-2.0-JSCH-0.1.54
INFO: CheckCiphers: aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256
D/EGL_emulation: eglMakeCurrent: 0xf0a7ee60: ver 3 0 (tinfo 0xf0aca800)
D/EGL_emulation: eglMakeCurrent: 0xf0a7ee60: ver 3 0 (tinfo 0xf0aca800)
W/System.err: INFO: CheckKexes: diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521
W/System.err: INFO: CheckSignatures: ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
W/System.err: INFO: SSH_MSG_KEXINIT sent
W/System.err: INFO: SSH_MSG_KEXINIT received
W/System.err: INFO: kex: server: curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,kexguess2@matt.ucc.asn.au
W/System.err: INFO: kex: server: ssh-rsa
W/System.err: INFO: kex: server: aes128-ctr,aes256-ctr
W/System.err: INFO: kex: server: aes128-ctr,aes256-ctr
W/System.err: INFO: kex: server: hmac-sha1,hmac-sha2-256
W/System.err: INFO: kex: server: hmac-sha1,hmac-sha2-256
INFO: kex: server: none
W/System.err: INFO: kex: server: none
W/System.err: INFO: kex: server:
INFO: kex: server:
W/System.err: INFO: kex: client: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1
W/System.err: INFO: kex: client: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
W/System.err: INFO: kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc
W/System.err: INFO: kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc
W/System.err: INFO: kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96
W/System.err: INFO: kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96
W/System.err: INFO: kex: client: none
W/System.err: INFO: kex: client: none
INFO: kex: client:
W/System.err: INFO: kex: client:
W/System.err: INFO: kex: server->client aes128-ctr hmac-sha1 none
W/System.err: INFO: kex: client->server aes128-ctr hmac-sha1 none
W/System.err: INFO: SSH_MSG_KEXDH_INIT sent
W/System.err: INFO: expecting SSH_MSG_KEXDH_REPLY
W/System.err: INFO: ssh_rsa_verify: signature true
W/System.err: WARN: Permanently added '192.168.1.1' (RSA) to the list of known hosts.
W/System.err: INFO: SSH_MSG_NEWKEYS sent
W/System.err: INFO: SSH_MSG_NEWKEYS received
W/System.err: INFO: SSH_MSG_SERVICE_REQUEST sent
W/System.err: INFO: SSH_MSG_SERVICE_ACCEPT received
W/System.err: INFO: Authentications that can continue: publickey
INFO: Next authentication method: publickey
W/System.err: INFO: Disconnecting from 192.168.1.1 port 22
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.example.ps4nuker, PID: 30981
com.jcraft.jsch.JSchException: Auth fail
at com.jcraft.jsch.Session.connect(Session.java:519)
at com.jcraft.jsch.Session.connect(Session.java:183)
at com.example.ps4nuker.MainActivity$sshCommand$1.invokeSuspend(MainActivity.kt:113)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
I/Process: Sending signal. PID: 30981 SIG: 9
Disconnected from the target VM, address: 'localhost:56256', transport: 'socket'
这是 OpenWRT 路由器上的日志(最高日志级别):
Sat Feb 13 15:47:51 2021 authpriv.info dropbear[7783]: Child connection from 192.168.1.23:56269
Sat Feb 13 15:47:52 2021 authpriv.info dropbear[7783]: Exit before auth (user 'root', 0 fails): Disconnect received
使用相同私钥的 Mobaxterm 连接到 SSH 时,相同的 OpenWRT 日志:
Thu Feb 18 00:24:51 2021 authpriv.info dropbear[17648]: Child connection from 192.168.1.23:50127
Thu Feb 18 00:24:52 2021 authpriv.notice dropbear[17648]: Pubkey auth succeeded for 'root' with key sha1!! 85:eb:c4:d2:dd:d9:15:d3:ee:29:3a:80:df:48:8f:6c:41:73:a8:5e from 192.168.1.23:50127
解决方案
您有两个 Jsch 实例,因此会话不会获得您添加到另一个实例的身份。改成
val jSch = JSch()
jSch.addIdentity("blabla123", privateKey.toByteArray(), null, null)
session = jSch.getSession(username, host, port)
推荐阅读
- python - 如何使用 Keycloak 处理 API 端点访问
- python - 通过 message_id 从聊天中获取消息?
- bash - 如何修复 JAVAC 无效标志错误?
- python-3.x - 创建一个 Process 对象,其功能来自另一个类 [导致错误]
- python - 正则表达式将短语拆分为由许多空格分隔的列
- python - 如何在 Python 中计算准确的单词
- amazon-web-services - 使用 AWS CLI 为 SNS 主题启用加密
- iis - 2 台较旧的 IIS 7 服务器移至 1 台新的 IIS 10 服务器。有1个工作,我如何获得第二个?
- go - 如何使用 for 循环在多个 goroutine 之间进行通信,其中一个循环调用阻塞函数
- macos - Mac 键盘如何在 Apache Guacamole 中发出 Alt 键输入