From 234fab059e279fd17b752cdc4e0d72b718ae6431 Mon Sep 17 00:00:00 2001 From: "weiqiu.lj" Date: Sun, 8 Jul 2018 00:15:40 +0800 Subject: [PATCH] sync to 0.1.54 --- .gitignore | 1 + ChangeLog | 664 ++++++--- LICENSE.txt | 2 +- README | 16 +- build.xml | 38 +- examples/AES.java | 4 + examples/ChangePassphrase.java | 11 + examples/Compression.java | 9 + examples/Daemon.java | 5 + examples/Exec.java | 10 + examples/KeyGen.java | 37 +- examples/KnownHosts.java | 10 + examples/Logger.java | 4 + examples/OpenSSHConfig.java | 137 ++ examples/PortForwardingL.java | 11 + examples/PortForwardingR.java | 11 + examples/README | 22 + examples/ScpFrom.java | 9 + examples/ScpTo.java | 11 +- examples/ScpToNoneCipher.java | 4 + examples/Sftp.java | 39 +- examples/Shell.java | 132 +- examples/StreamForwarding.java | 24 +- examples/Subsystem.java | 4 + examples/Sudo.java | 184 +++ examples/UserAuthKI.java | 8 + examples/UserAuthPubKey.java | 8 + examples/ViaHTTP.java | 8 + examples/ViaSOCKS5.java | 8 + examples/X11Forwarding.java | 10 + pom.xml | 113 ++ src/com/jcraft/jsch/IdentityFile.java | 914 ------------ src/com/jcraft/jsch/JSch.java | 298 ---- src/com/jcraft/jsch/KeyExchange.java | 159 --- src/com/jcraft/jsch/KeyPair.java | 665 --------- src/com/jcraft/jsch/jce/HMACMD5.java | 75 - src/com/jcraft/jsch/jce/HMACMD596.java | 77 - src/com/jcraft/jsch/jce/HMACSHA196.java | 76 - .../java}/com/jcraft/jsch/Buffer.java | 49 +- .../java}/com/jcraft/jsch/Channel.java | 309 ++-- .../jcraft/jsch/ChannelAgentForwarding.java | 89 +- .../com/jcraft/jsch/ChannelDirectTCPIP.java | 119 +- .../java}/com/jcraft/jsch/ChannelExec.java | 2 +- .../jcraft/jsch/ChannelForwardedTCPIP.java | 170 ++- .../java}/com/jcraft/jsch/ChannelSession.java | 20 +- .../java}/com/jcraft/jsch/ChannelSftp.java | 848 +++++++++-- .../java}/com/jcraft/jsch/ChannelShell.java | 2 +- .../com/jcraft/jsch/ChannelSubsystem.java | 4 +- .../java}/com/jcraft/jsch/ChannelX11.java | 13 +- .../java}/com/jcraft/jsch/Cipher.java | 2 +- .../java}/com/jcraft/jsch/CipherNone.java | 2 +- .../java}/com/jcraft/jsch/Compression.java | 4 +- .../com/jcraft/jsch/ConfigRepository.java} | 37 +- src/{ => main/java}/com/jcraft/jsch/DH.java | 6 +- src/main/java/com/jcraft/jsch/DHEC256.java | 37 + src/main/java/com/jcraft/jsch/DHEC384.java | 37 + src/main/java/com/jcraft/jsch/DHEC521.java | 37 + src/main/java/com/jcraft/jsch/DHECN.java | 187 +++ src/{ => main/java}/com/jcraft/jsch/DHG1.java | 128 +- src/main/java/com/jcraft/jsch/DHG14.java | 215 +++ .../java}/com/jcraft/jsch/DHGEX.java | 157 +-- src/main/java/com/jcraft/jsch/DHGEX256.java | 36 + src/main/java/com/jcraft/jsch/ECDH.java | 37 + .../com/jcraft/jsch/ForwardedTCPIPDaemon.java | 2 +- .../java}/com/jcraft/jsch/GSSContext.java | 2 +- src/{ => main/java}/com/jcraft/jsch/HASH.java | 2 +- .../java}/com/jcraft/jsch/HostKey.java | 49 +- .../com/jcraft/jsch/HostKeyRepository.java | 94 ++ src/{ => main/java}/com/jcraft/jsch/IO.java | 2 +- src/main/java/com/jcraft/jsch/Identity.java | 83 ++ .../java/com/jcraft/jsch/IdentityFile.java | 130 ++ .../com/jcraft/jsch/IdentityRepository.java | 115 ++ src/main/java/com/jcraft/jsch/JSch.java | 591 ++++++++ .../jcraft/jsch/JSchAuthCancelException.java | 2 +- .../java}/com/jcraft/jsch/JSchException.java | 2 +- .../jcraft/jsch/JSchPartialAuthException.java | 2 +- .../java/com/jcraft/jsch/KeyExchange.java | 325 +++++ src/main/java/com/jcraft/jsch/KeyPair.java | 1255 +++++++++++++++++ .../java}/com/jcraft/jsch/KeyPairDSA.java | 135 +- .../java/com/jcraft/jsch/KeyPairECDSA.java | 391 +++++ .../java}/com/jcraft/jsch/KeyPairGenDSA.java | 2 +- .../java/com/jcraft/jsch/KeyPairGenECDSA.java | 37 + .../java}/com/jcraft/jsch/KeyPairGenRSA.java | 2 +- .../java/com/jcraft/jsch/KeyPairPKCS8.java | 363 +++++ .../java}/com/jcraft/jsch/KeyPairRSA.java | 268 ++-- .../java}/com/jcraft/jsch/KnownHosts.java | 175 ++- .../jcraft/jsch/LocalIdentityRepository.java | 151 ++ .../java}/com/jcraft/jsch/Logger.java | 2 +- src/{ => main/java}/com/jcraft/jsch/MAC.java | 2 +- .../java/com/jcraft/jsch/OpenSSHConfig.java | 264 ++++ src/main/java/com/jcraft/jsch/PBKDF.java | 34 + .../java}/com/jcraft/jsch/Packet.java | 9 +- .../java}/com/jcraft/jsch/PortWatcher.java | 21 +- .../java}/com/jcraft/jsch/Proxy.java | 2 +- .../java}/com/jcraft/jsch/ProxyHTTP.java | 2 +- .../java}/com/jcraft/jsch/ProxySOCKS4.java | 2 +- .../java}/com/jcraft/jsch/ProxySOCKS5.java | 2 +- .../java}/com/jcraft/jsch/Random.java | 2 +- .../java}/com/jcraft/jsch/Request.java | 2 +- .../jcraft/jsch/RequestAgentForwarding.java | 2 +- .../java}/com/jcraft/jsch/RequestEnv.java | 2 +- .../java}/com/jcraft/jsch/RequestExec.java | 2 +- .../java}/com/jcraft/jsch/RequestPtyReq.java | 2 +- .../java}/com/jcraft/jsch/RequestSftp.java | 2 +- .../java}/com/jcraft/jsch/RequestShell.java | 2 +- .../java}/com/jcraft/jsch/RequestSignal.java | 2 +- .../com/jcraft/jsch/RequestSubsystem.java | 2 +- .../com/jcraft/jsch/RequestWindowChange.java | 2 +- .../java}/com/jcraft/jsch/RequestX11.java | 2 +- .../com/jcraft/jsch/ServerSocketFactory.java | 2 +- .../java}/com/jcraft/jsch/Session.java | 1088 ++++++++++++-- .../java}/com/jcraft/jsch/SftpATTRS.java | 49 +- .../java}/com/jcraft/jsch/SftpException.java | 2 +- .../com/jcraft/jsch/SftpProgressMonitor.java | 3 +- .../java/com/jcraft/jsch/SftpStatVFS.java | 122 ++ .../java/com/jcraft/jsch/Signature.java} | 6 +- .../java}/com/jcraft/jsch/SignatureDSA.java | 8 +- .../java/com/jcraft/jsch/SignatureECDSA.java | 35 + .../java/com/jcraft/jsch/SignatureRSA.java | 35 + .../java}/com/jcraft/jsch/SocketFactory.java | 2 +- .../jcraft/jsch/UIKeyboardInteractive.java | 2 +- .../java}/com/jcraft/jsch/UserAuth.java | 2 +- .../jcraft/jsch/UserAuthGSSAPIWithMIC.java | 2 +- .../jsch/UserAuthKeyboardInteractive.java | 10 +- .../java}/com/jcraft/jsch/UserAuthNone.java | 2 +- .../com/jcraft/jsch/UserAuthPassword.java | 8 +- .../com/jcraft/jsch/UserAuthPublicKey.java | 38 +- .../java}/com/jcraft/jsch/UserInfo.java | 2 +- src/{ => main/java}/com/jcraft/jsch/Util.java | 82 +- .../java}/com/jcraft/jsch/jce/AES128CBC.java | 12 +- .../java}/com/jcraft/jsch/jce/AES128CTR.java | 12 +- .../java}/com/jcraft/jsch/jce/AES192CBC.java | 12 +- .../java}/com/jcraft/jsch/jce/AES192CTR.java | 12 +- .../java}/com/jcraft/jsch/jce/AES256CBC.java | 12 +- .../java}/com/jcraft/jsch/jce/AES256CTR.java | 12 +- .../java}/com/jcraft/jsch/jce/ARCFOUR.java | 12 +- .../java}/com/jcraft/jsch/jce/ARCFOUR128.java | 12 +- .../java}/com/jcraft/jsch/jce/ARCFOUR256.java | 12 +- .../com/jcraft/jsch/jce/BlowfishCBC.java | 12 +- .../java}/com/jcraft/jsch/jce/DH.java | 37 +- .../java/com/jcraft/jsch/jce/ECDH256.java | 36 + .../java/com/jcraft/jsch/jce/ECDH384.java | 36 + .../java/com/jcraft/jsch/jce/ECDH521.java | 36 + src/main/java/com/jcraft/jsch/jce/ECDHN.java | 146 ++ .../java/com/jcraft/jsch/jce/HMAC.java} | 37 +- .../java/com/jcraft/jsch/jce/HMACMD5.java | 42 + .../java/com/jcraft/jsch/jce/HMACMD596.java} | 29 +- .../java/com/jcraft/jsch/jce/HMACSHA1.java | 38 + .../java/com/jcraft/jsch/jce/HMACSHA196.java | 47 + .../java/com/jcraft/jsch/jce/HMACSHA256.java | 38 + .../java/com/jcraft/jsch/jce/HMACSHA512.java | 38 + .../com/jcraft/jsch/jce/KeyPairGenDSA.java | 2 +- .../com/jcraft/jsch/jce/KeyPairGenECDSA.java | 96 ++ .../com/jcraft/jsch/jce/KeyPairGenRSA.java | 2 +- .../java}/com/jcraft/jsch/jce/MD5.java | 2 +- src/main/java/com/jcraft/jsch/jce/PBKDF.java | 59 + .../java}/com/jcraft/jsch/jce/Random.java | 2 +- .../java}/com/jcraft/jsch/jce/SHA1.java | 2 +- src/main/java/com/jcraft/jsch/jce/SHA256.java | 51 + src/main/java/com/jcraft/jsch/jce/SHA384.java | 49 + src/main/java/com/jcraft/jsch/jce/SHA512.java | 49 + .../com/jcraft/jsch/jce/SignatureDSA.java | 2 +- .../com/jcraft/jsch/jce/SignatureECDSA.java | 186 +++ .../com/jcraft/jsch/jce/SignatureRSA.java | 2 +- .../com/jcraft/jsch/jce/TripleDESCBC.java | 12 +- .../com/jcraft/jsch/jce/TripleDESCTR.java | 12 +- .../com/jcraft/jsch/jcraft/Compression.java | 51 +- .../java}/com/jcraft/jsch/jcraft/HMAC.java | 3 +- .../java}/com/jcraft/jsch/jcraft/HMACMD5.java | 2 +- .../com/jcraft/jsch/jcraft/HMACMD596.java | 2 +- .../com/jcraft/jsch/jcraft/HMACSHA1.java | 2 +- .../com/jcraft/jsch/jcraft/HMACSHA196.java | 2 +- .../com/jcraft/jsch/jgss/GSSContextKrb5.java | 2 +- 173 files changed, 9968 insertions(+), 3713 deletions(-) create mode 100644 .gitignore create mode 100644 examples/OpenSSHConfig.java create mode 100644 examples/Sudo.java create mode 100644 pom.xml delete mode 100644 src/com/jcraft/jsch/IdentityFile.java delete mode 100644 src/com/jcraft/jsch/JSch.java delete mode 100644 src/com/jcraft/jsch/KeyExchange.java delete mode 100644 src/com/jcraft/jsch/KeyPair.java delete mode 100644 src/com/jcraft/jsch/jce/HMACMD5.java delete mode 100644 src/com/jcraft/jsch/jce/HMACMD596.java delete mode 100644 src/com/jcraft/jsch/jce/HMACSHA196.java rename src/{ => main/java}/com/jcraft/jsch/Buffer.java (85%) rename src/{ => main/java}/com/jcraft/jsch/Channel.java (69%) rename src/{ => main/java}/com/jcraft/jsch/ChannelAgentForwarding.java (70%) rename src/{ => main/java}/com/jcraft/jsch/ChannelDirectTCPIP.java (68%) rename src/{ => main/java}/com/jcraft/jsch/ChannelExec.java (97%) rename src/{ => main/java}/com/jcraft/jsch/ChannelForwardedTCPIP.java (62%) rename src/{ => main/java}/com/jcraft/jsch/ChannelSession.java (93%) rename src/{ => main/java}/com/jcraft/jsch/ChannelSftp.java (75%) rename src/{ => main/java}/com/jcraft/jsch/ChannelShell.java (97%) rename src/{ => main/java}/com/jcraft/jsch/ChannelSubsystem.java (96%) rename src/{ => main/java}/com/jcraft/jsch/ChannelX11.java (95%) rename src/{ => main/java}/com/jcraft/jsch/Cipher.java (96%) rename src/{ => main/java}/com/jcraft/jsch/CipherNone.java (96%) rename src/{ => main/java}/com/jcraft/jsch/Compression.java (93%) rename src/{com/jcraft/jsch/HostKeyRepository.java => main/java/com/jcraft/jsch/ConfigRepository.java} (65%) rename src/{ => main/java}/com/jcraft/jsch/DH.java (88%) create mode 100644 src/main/java/com/jcraft/jsch/DHEC256.java create mode 100644 src/main/java/com/jcraft/jsch/DHEC384.java create mode 100644 src/main/java/com/jcraft/jsch/DHEC521.java create mode 100644 src/main/java/com/jcraft/jsch/DHECN.java rename src/{ => main/java}/com/jcraft/jsch/DHG1.java (67%) create mode 100644 src/main/java/com/jcraft/jsch/DHG14.java rename src/{ => main/java}/com/jcraft/jsch/DHGEX.java (66%) create mode 100644 src/main/java/com/jcraft/jsch/DHGEX256.java create mode 100644 src/main/java/com/jcraft/jsch/ECDH.java rename src/{ => main/java}/com/jcraft/jsch/ForwardedTCPIPDaemon.java (96%) rename src/{ => main/java}/com/jcraft/jsch/GSSContext.java (96%) rename src/{ => main/java}/com/jcraft/jsch/HASH.java (96%) rename src/{ => main/java}/com/jcraft/jsch/HostKey.java (68%) create mode 100644 src/main/java/com/jcraft/jsch/HostKeyRepository.java rename src/{ => main/java}/com/jcraft/jsch/IO.java (98%) create mode 100644 src/main/java/com/jcraft/jsch/Identity.java create mode 100644 src/main/java/com/jcraft/jsch/IdentityFile.java create mode 100644 src/main/java/com/jcraft/jsch/IdentityRepository.java create mode 100644 src/main/java/com/jcraft/jsch/JSch.java rename src/{ => main/java}/com/jcraft/jsch/JSchAuthCancelException.java (96%) rename src/{ => main/java}/com/jcraft/jsch/JSchException.java (96%) rename src/{ => main/java}/com/jcraft/jsch/JSchPartialAuthException.java (96%) create mode 100644 src/main/java/com/jcraft/jsch/KeyExchange.java create mode 100644 src/main/java/com/jcraft/jsch/KeyPair.java rename src/{ => main/java}/com/jcraft/jsch/KeyPairDSA.java (66%) create mode 100644 src/main/java/com/jcraft/jsch/KeyPairECDSA.java rename src/{ => main/java}/com/jcraft/jsch/KeyPairGenDSA.java (96%) create mode 100644 src/main/java/com/jcraft/jsch/KeyPairGenECDSA.java rename src/{ => main/java}/com/jcraft/jsch/KeyPairGenRSA.java (96%) create mode 100644 src/main/java/com/jcraft/jsch/KeyPairPKCS8.java rename src/{ => main/java}/com/jcraft/jsch/KeyPairRSA.java (61%) rename src/{ => main/java}/com/jcraft/jsch/KnownHosts.java (74%) create mode 100644 src/main/java/com/jcraft/jsch/LocalIdentityRepository.java rename src/{ => main/java}/com/jcraft/jsch/Logger.java (97%) rename src/{ => main/java}/com/jcraft/jsch/MAC.java (96%) create mode 100644 src/main/java/com/jcraft/jsch/OpenSSHConfig.java create mode 100644 src/main/java/com/jcraft/jsch/PBKDF.java rename src/{ => main/java}/com/jcraft/jsch/Packet.java (93%) rename src/{ => main/java}/com/jcraft/jsch/PortWatcher.java (91%) rename src/{ => main/java}/com/jcraft/jsch/Proxy.java (96%) rename src/{ => main/java}/com/jcraft/jsch/ProxyHTTP.java (98%) rename src/{ => main/java}/com/jcraft/jsch/ProxySOCKS4.java (99%) rename src/{ => main/java}/com/jcraft/jsch/ProxySOCKS5.java (99%) rename src/{ => main/java}/com/jcraft/jsch/Random.java (96%) rename src/{ => main/java}/com/jcraft/jsch/Request.java (97%) rename src/{ => main/java}/com/jcraft/jsch/RequestAgentForwarding.java (97%) rename src/{ => main/java}/com/jcraft/jsch/RequestEnv.java (97%) rename src/{ => main/java}/com/jcraft/jsch/RequestExec.java (97%) rename src/{ => main/java}/com/jcraft/jsch/RequestPtyReq.java (97%) rename src/{ => main/java}/com/jcraft/jsch/RequestSftp.java (96%) rename src/{ => main/java}/com/jcraft/jsch/RequestShell.java (97%) rename src/{ => main/java}/com/jcraft/jsch/RequestSignal.java (97%) rename src/{ => main/java}/com/jcraft/jsch/RequestSubsystem.java (97%) rename src/{ => main/java}/com/jcraft/jsch/RequestWindowChange.java (97%) rename src/{ => main/java}/com/jcraft/jsch/RequestX11.java (97%) rename src/{ => main/java}/com/jcraft/jsch/ServerSocketFactory.java (96%) rename src/{ => main/java}/com/jcraft/jsch/Session.java (60%) rename src/{ => main/java}/com/jcraft/jsch/SftpATTRS.java (90%) rename src/{ => main/java}/com/jcraft/jsch/SftpException.java (96%) rename src/{ => main/java}/com/jcraft/jsch/SftpProgressMonitor.java (93%) create mode 100644 src/main/java/com/jcraft/jsch/SftpStatVFS.java rename src/{com/jcraft/jsch/SignatureRSA.java => main/java/com/jcraft/jsch/Signature.java} (88%) rename src/{ => main/java}/com/jcraft/jsch/SignatureDSA.java (86%) create mode 100644 src/main/java/com/jcraft/jsch/SignatureECDSA.java create mode 100644 src/main/java/com/jcraft/jsch/SignatureRSA.java rename src/{ => main/java}/com/jcraft/jsch/SocketFactory.java (96%) rename src/{ => main/java}/com/jcraft/jsch/UIKeyboardInteractive.java (96%) rename src/{ => main/java}/com/jcraft/jsch/UserAuth.java (97%) rename src/{ => main/java}/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java (99%) rename src/{ => main/java}/com/jcraft/jsch/UserAuthKeyboardInteractive.java (96%) rename src/{ => main/java}/com/jcraft/jsch/UserAuthNone.java (98%) rename src/{ => main/java}/com/jcraft/jsch/UserAuthPassword.java (96%) rename src/{ => main/java}/com/jcraft/jsch/UserAuthPublicKey.java (88%) rename src/{ => main/java}/com/jcraft/jsch/UserInfo.java (96%) rename src/{ => main/java}/com/jcraft/jsch/Util.java (85%) rename src/{ => main/java}/com/jcraft/jsch/jce/AES128CBC.java (88%) rename src/{ => main/java}/com/jcraft/jsch/jce/AES128CTR.java (88%) rename src/{ => main/java}/com/jcraft/jsch/jce/AES192CBC.java (88%) rename src/{ => main/java}/com/jcraft/jsch/jce/AES192CTR.java (88%) rename src/{ => main/java}/com/jcraft/jsch/jce/AES256CBC.java (88%) rename src/{ => main/java}/com/jcraft/jsch/jce/AES256CTR.java (88%) rename src/{ => main/java}/com/jcraft/jsch/jce/ARCFOUR.java (89%) rename src/{ => main/java}/com/jcraft/jsch/jce/ARCFOUR128.java (89%) rename src/{ => main/java}/com/jcraft/jsch/jce/ARCFOUR256.java (89%) rename src/{ => main/java}/com/jcraft/jsch/jce/BlowfishCBC.java (88%) rename src/{ => main/java}/com/jcraft/jsch/jce/DH.java (79%) create mode 100644 src/main/java/com/jcraft/jsch/jce/ECDH256.java create mode 100644 src/main/java/com/jcraft/jsch/jce/ECDH384.java create mode 100644 src/main/java/com/jcraft/jsch/jce/ECDH521.java create mode 100644 src/main/java/com/jcraft/jsch/jce/ECDHN.java rename src/{com/jcraft/jsch/jce/HMACSHA1.java => main/java/com/jcraft/jsch/jce/HMAC.java} (76%) create mode 100644 src/main/java/com/jcraft/jsch/jce/HMACMD5.java rename src/{com/jcraft/jsch/Identity.java => main/java/com/jcraft/jsch/jce/HMACMD596.java} (78%) create mode 100644 src/main/java/com/jcraft/jsch/jce/HMACSHA1.java create mode 100644 src/main/java/com/jcraft/jsch/jce/HMACSHA196.java create mode 100644 src/main/java/com/jcraft/jsch/jce/HMACSHA256.java create mode 100644 src/main/java/com/jcraft/jsch/jce/HMACSHA512.java rename src/{ => main/java}/com/jcraft/jsch/jce/KeyPairGenDSA.java (97%) create mode 100644 src/main/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java rename src/{ => main/java}/com/jcraft/jsch/jce/KeyPairGenRSA.java (97%) rename src/{ => main/java}/com/jcraft/jsch/jce/MD5.java (96%) create mode 100644 src/main/java/com/jcraft/jsch/jce/PBKDF.java rename src/{ => main/java}/com/jcraft/jsch/jce/Random.java (97%) rename src/{ => main/java}/com/jcraft/jsch/jce/SHA1.java (96%) create mode 100644 src/main/java/com/jcraft/jsch/jce/SHA256.java create mode 100644 src/main/java/com/jcraft/jsch/jce/SHA384.java create mode 100644 src/main/java/com/jcraft/jsch/jce/SHA512.java rename src/{ => main/java}/com/jcraft/jsch/jce/SignatureDSA.java (98%) create mode 100644 src/main/java/com/jcraft/jsch/jce/SignatureECDSA.java rename src/{ => main/java}/com/jcraft/jsch/jce/SignatureRSA.java (98%) rename src/{ => main/java}/com/jcraft/jsch/jce/TripleDESCBC.java (90%) rename src/{ => main/java}/com/jcraft/jsch/jce/TripleDESCTR.java (90%) rename src/{ => main/java}/com/jcraft/jsch/jcraft/Compression.java (81%) rename src/{ => main/java}/com/jcraft/jsch/jcraft/HMAC.java (97%) rename src/{ => main/java}/com/jcraft/jsch/jcraft/HMACMD5.java (96%) rename src/{ => main/java}/com/jcraft/jsch/jcraft/HMACMD596.java (96%) rename src/{ => main/java}/com/jcraft/jsch/jcraft/HMACSHA1.java (96%) rename src/{ => main/java}/com/jcraft/jsch/jcraft/HMACSHA196.java (96%) rename src/{ => main/java}/com/jcraft/jsch/jgss/GSSContextKrb5.java (98%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/ChangeLog b/ChangeLog index bb41d0b..eff7fa9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,17 +1,316 @@ ChangeLog of JSch ==================================================================== -Last modified: Tue Nov 2 11:59:57 JST 2010 +Last modified: Tue Aug 30 06:47:52 UTC 2016 + + +Changes since version 0.1.53: +- bugfix: fixed CVS-2016-5725 + Refer to following links, + http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2016-5725 + https://github.com/tintinweb/pub/tree/master/pocs/cve-2016-5725 + Thanks a lot for tintinweb's contributions. +- bugfix: sftp-put may send the garbage data in some rare case. +- bugfix: fixed a deadlock bug in KnownHosts#getHostKey(). +- bugfix: SftpProgressMonitor#init() was not invoked in sftp-put + by using the output-stream. +- change: KnownHosts#setKnownHosts() should accept the non-existing file. +- change: excluding the user interaction time from the timeout value. +- change: addressing SFTP slow file transfer speed with Titan FTP. +- change: updating copyright messages; 2015 -> 2016 + + +Changes since version 0.1.52: +- bugfix: the rekey initiated by the remote may crash the session. +- change: Logjam: use ecdh-sha2-nistp* if available, + 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 +- change: Logjam: diffie-hellman-group-exchange-sha256 and + diffie-hellman-group-exchange-sha1 will use 2048-bit key on + Java8's SunJCE, thanks to JDK-6521495 and JDK-7044060. +- change: key words for OpenSSH's config file should be case-insensitive. +- change: there should be the host name in "WARNING: REMOTE HOST + IDENTIFICATION HAS CHANGED" message. + + +Changes since version 0.1.51: +- bugfix: resource leak: duplicate keys in LocalIdentityRepository. +- feature: added the support for SSH ECC defined in RFC5656, + ecdsa-sha2-nistp256, + ecdsa-sha2-nistp384, + ecdsa-sha2-nistp521, + ecdh-sha2-nistp256, + ecdh-sha2-nistp384, + ecdh-sha2-nistp521 + This functionality requires Java7 or later. +- feature: added the support for server host keys in + ecdsa-sha2-nistp256, + ecdsa-sha2-nistp384, + ecdsa-sha2-nistp521 +- feature: generating key-pairs in + ecdh-sha2-nistp256, + ecdh-sha2-nistp384, + ecdh-sha2-nistp521 +- change: aes192-ctr, aes256-ctr and + diffie-hellman-group-exchange-sha256 have been enabled + by the default. +- change: key exchange methods, ecdh-sha2-nistp256, + ecdh-sha2-nistp384 and ecdh-sha2-nistp521 have been enabled + by the default. +- change: the support for host keys in ecdsa-sha2-nistp256, + ecdsa-sha2-nistp384 and ecdsa-sha2-nistp521 have been enabled + by the default. +- change: 'examples/KeyGen.java' demonstrates how to generate + ecdsa-sha2-* key-pairs. +- change: updating copyright messages; 2014 -> 2015 +- TODO: The ECC support is not functional on Java6 with BouncyCastle. + + +Changes since version 0.1.50: +- bugfix: reproducibility of "verify: false". FIXED. + Hundreds of thousands of connections had caused that exception. +- bugfix: resource leaks at the failure of making local port forwarding. FIXED. +- bugfix: NPE in connecting to the non-standard TCP port. FIXED. + This problem had appeared if a host-key does not exist in + "known_host" file. +- bugfix: TCP connection may not be dropped if error messages from + the remote are too long. FIXED. +- bugfix: SftpATTRS#getAtimeString() returns the wrong string. FIXED. +- bugfix: bytes to be added by SSH_MSG_CHANNEL_WINDOW_ADJUST must be in + unsigned integer. FIXED. +- bugfix: Util#checkTilde() should not convert a tilde in + "C:\PROGRA~1\". FIXED. +- bugfix: A long long command for ChannelExec will cause + an ArrayIndexOutOfBoundsException. FIXED. +- bugfix: ChannelSftp should not send bulk request greedily even if the remote + window has the enough space. FIXED. +- bugfix: Util.createSocket() should throw an exception with 'cause'. FIXED. +- bugfix: failed to parse .ssh/config in the EBCDIC environment. FIXED. +- bugfix: com.jcraft.jsch.jcraft.HMACSHA1(used only for MacOSX) is not + reusable. FIXED. +- bugfix: NPE caused by the delayed response for channel opening + requests. FIXED. +- bugfix: hung-up in uploading huge data to ProFTPd without the config + 'SFTPClientMatch "JSCH.*" channelWindowSize 1GB' FIXED. +- bugfix: Cipher#init() may cause an infinite loop with 100% cpu use due to + https://bugs.openjdk.java.net/browse/JDK-8028627 FIXED. +- bugfix: in some case, JSche#setKnowHosts(InputStream stream) may fail + to close the given stream. FIXED +- change: com.jcraft.jsch.jcraft.HMAC* will not be used. + It seems Java6 on Mac OS X has fixed some memory leak bug in JCE, + so there is no reason to use c.j.j.j.HMAC* introduced at 0.1.30. +- change: updating copyright messages; 2013 -> 2014 +- change: allowed to create the symbolic/hard link to the relative path by + ChannelSftp#symlink(String oldpath, String newpath) + ChannelSftp#hardlink(String oldpath, String newpath) +- change: the availability of ciphers listed in "CheckCiphers" config will + not be checked if they are not used. +- change: Util#fromBase64() will throw JSchException in stead of + RuntimeException, if the given string is not in base64 format. +- feature: added the support for private keys in PKCS#8 format. +- feature: introduced the interface com.jcraft.jsch.PBKDF to abstract + the implementation of Password-Based Key Derivation Function, + and added its implementation com.jcraft.jsch.jce.PBKDF by using JCE. + + +Changes since version 0.1.49: +- bugfix: "verify: false" error on Java7u6(and later). FIXED. + http://stackoverflow.com/questions/12279836/ssh-using-jschexception-verify-false-sometimes-fails + https://issues.apache.org/jira/browse/IVY-1374 +- bugfix: Session#setPortForwardingL(String bind_address, + int lport, String host, int rport) + will not work for the long host name. FIXED. +- change: changed JSch#getIdentityRepository() to be public. +- feature: added the following method to choose a canceled remote + port-forwarding with the specified bind address, + Session#delPortForwardingR(String bind_address, int rport) +- feature: added support for following OpenSSH's sftp extensions, + posix-rename@openssh.com, + statvfs@openssh.com, + hardlink@openssh.com, + and some methods and a class to use those functionalities, + ChannelSftp#hardlink(String oldpath, String newpath), + ChannelSftp#statVFS(String path) + SftpStatVFS +- feature: added support for OpenSSH's configuration file, + JSch#setConfigRepository(ConfigRepository configRepository) + JSch#getConfigRepository() + OpenSSHConfig class + Session#getSession(String host) + and added an example to demonstrate how to use it, + examples/OpenSSHConfig.java + OpenSSHConfig class will recognize the following keywords, + Host + User + Hostname + Port + PreferredAuthentications + IdentityFile + NumberOfPasswordPrompts + ConnectTimeout + HostKeyAlias + UserKnownHostsFile + KexAlgorithms + HostKeyAlgorithms + Ciphers + Macs + Compression + CompressionLevel + ForwardAgent + RequestTTY + ServerAliveInterval + LocalForward + RemoteForward + ClearAllForwardings +- feature: added support for "diffie-hellman-group-exchange-sha256" +- feature: allowed to use tilde(~) in the file name, + JSch#setIdentity(String prvkey, String pubkey) + JSch#setKnownHosts(String prvkey, String pubkey) +- feature: added support for known_hosts file, which may include + markers(@revoke) and comments. + HostKey(String host, int type, byte[] key, String comment) + HostKey(String marker, String host, int type, + byte[] key, String comment) + HostKey#getComment() + HostKey#getMarker() +- feature: added following methods to KeyPar class, + writePrivateKey(java.io.OutputStream out, byte[] passphrase) + writePrivateKey(String name, byte[] passphrase) +- feature: allowed to set the connection timeout for the local port-forwarding, + and added following methods, + Session#setPortForwardingL(String bind_address, + int lport, String host, int rport, + ServerSocketFactory ssf, + int connectTimeout) + ChannelDirectTCPIP#connect(int connectTimeout) +- feature: added the following method to Session class + getStreamForwarder(String host, int port) + and updated example/StreamForwarding.java to use that method. +- feature: added following methods to Session class, + setPortForwardingL(String conf) + setPortForwardingR(String conf) +- feature: allowed to have the session local HostkeyRepository, + Session#setHostKeyRepository(HostKeyRepository hostkeyRepository) + Session#getHostKeyRepository() +- feature: added support for OpenSSH's local extension, + "no-more-sessions@openssh.com" and the method, + Session#noMoreSessionChannels() + + +Changes since version 0.1.48: +- bugfix: Some sftp servers will sometimes fail to handle bulk requests, + and whenever detecting such failures, we should re-send + requests again and again. FIXED +- bugfix: KeyPair#getFingerPrint() should return a fingerprint instead + of keysize + " " + fingerprint. FIXED +- bugfix: KeyPair#getKeySize() should return its key size. FIXED +- bugfix: SftpATTRS#isDir() should return false for unix domain + socket files. FIXED +- change: improved the heuristics for the password prompt in + the keyboard-interactive authentication. It may not be + started with "password:". +- change: ChannelSftp#put(InputStream src, String dst) will not check + if dst is directory or not, and if an exception is thrown, + the check will be done. +- change: if the compression is enabled without jzlib.jar, + an exception will be thrown. +- feature: JSch#addIdentity() and KeyPair#load() methods will accept + Putty's private key files. + Note that Putty encrypts its private key with "aes256-cbc". + So, to handle such key files, "Java Cryptography + Extension (JCE) Unlimited Strength Jurisdiction Policy Files" + must be installed. +- feature: hmac-sha2-256 defined in RFC6668 is supported. +- feature: added following methods to KeyPair class, + byte[] getSignature(byte[] data) + Signature getVerifier() + byte[] forSSHAgent() + void setPublicKeyComment(String comment) +- feature: added following methods to SftpATTR class, + boolean isChr() + boolean isBlk() + boolean isFifo() + boolean isSock() + + +Changes since version 0.1.47: +- change: the file transfer speed with ChannelSftp#get(String src) has been + improved; sending multiple requests at any one time. +- change: by the default, at most, 16 requests will be sent at any one time + in ChannelSftp. +- feature: added Session#{setIdentityRepository(),getIdentityRepository()} + + +Changes since version 0.1.46: +- bugfix: failed to initialize channels for the stream forwarding. FIXED +- change: Session#getHostKey() will return the given hostkey + even if session is not established. +- change: Logger will record additional messages about algorithm negotiations. +- feature: added ChannelSftp#ls(String path, LsEntrySelector selector) method. +- feature: added IdentityRepository#{getName(),getStatus()} methods. + + +Changes since version 0.1.45: +- bugfix: in the agent forwarding mode, "ssh-add -l" on the remote + will freeze. FIXED +- bugfix: requests should not be sent to the closed channel. FIXED +- bugfix: ChannelShell#setAgentForwarding(true) will cause + resource leaks. FIXED +- change: for the efficiency, channel opening will be delayed + in local port forwarding. +- change: added examples/Sudo.java to demonstrate sudo on exec channel. +- change: authentication trials will be failed at 6 failures by the default. +- change: updating copyright messages; 2011 -> 2012 +- feature: added JSch#setIdentityRepository(IdentityRepository irepo) to + integrate with jsch-agent-proxy. + + +Changes since version 0.1.44: +- bugfix: fields referred by multiple threads simultaneously should be + volatile. FIXED +- bugfix: use local window size offered by the remote in sftp put. + FIXED +- bugfix: SftpProgressMonitor#init was not invoked in sftp-put + for input-stream. FIXED +- bugfix: sftp protocol version 3, 4 and 5 should allow only + UTF-8 encoding. FIXED +- bugfix: Channel Subsystem had failed to set X forwarding flag. + FIXED +- bugfix: Channel X11 had leaked some resources. + FIXED +- bugfix: packet compression may break sessions + in some case(transferring deflated data). FIXED +- bugfix: failed to set dev-null for logger + FIXED +- bugfix: even in sftp protocol version 3 session, some sftpd sends data + packets defined in sftp protocol 6 ;-( working around it. FIXED +- bugfix: ChannelSftp file globbing logic had missed + the string "foo\\\*bar" as a pattern. FIXED +- bugfix: sequential accesses to ChannelSftp by multiple threads may + break its I/O channel. + https://bugs.eclipse.org/bugs/show_bug.cgi?id=359184 FIXED +- bugfix: KeyPair.load can not handle private keys cyphered with AES. FIXED +- change: to improve sftp-put performance, send multiple packet at one time. +- change: wait/notify will be used instead of sleep loop + in establishing channel connections. +- change: increasing local window size for sftp get. +- change: updating copyright messages; 2010 -> 2011 +- change: src/com -> src/main/java/com +- feature: key-exchange method "diffie-hellman-group14-sha1" + (RFC4253#section-8.2) +- feature: KeyPair#getPlulicKeyCommment() is added. + - Changes since version 0.1.43: - bugfix: hmac-md5-96 and hmac-sha1-96 are broken. FIXED. - bugfix: working around OOME in parsing broken data from the remote. FIXED. - bugfix: failed to send very long command for exec channels. FIXED. -- bugfix: in some case, failed to get the response +- bugfix: in some case, failed to get the response for remote port-forwarding request. FIXED. - feature: support for private keys ciphered with aes192-cbc and aes128-cbc. - + Changes since version 0.1.42: - bugfix: the remote window size must be in unsigned int. FIXED. - bugfix: support for EBCDIC environment. FIXED. @@ -20,26 +319,26 @@ Changes since version 0.1.42: - bugfix: the private key file may include garbage data before its header. FIXED. - bugfix: the session down may not be detected during the re-keying process. FIXED. - change: try keyboard-interactive auth with the given password if UserInfo is not given. -- change: working around the wrong auth method list sent by some SSHD +- change: working around the wrong auth method list sent by some SSHD in the partial auth success. - change: working around the CPNI-957037 Plain-text Recovery Attack. -- change: in searching for [host]:non-default port in known_hosts, +- change: in searching for [host]:non-default port in known_hosts, host:22 should be also checked. - change: updating copyright messages; 2009 -> 2010 - + Changes since version 0.1.41: -- bugfix: making exec request during re-keying process will cause +- bugfix: making exec request during re-keying process will cause the dead lock for the session. FIXED. - Many thanks for PanLi at Prominic dot NET and www.prominic.net, + Many thanks for PanLi at Prominic dot NET and www.prominic.net, US based hosting company. Without their testing JSch with - hundreds of hosts and their bug reports, this problem + hundreds of hosts and their bug reports, this problem was not fixed. -- change: updating copyright messages; 2008 -> 2009 +- change: updating copyright messages; 2008 -> 2009 + - Changes since version 0.1.40: -- bugfix: canceling the remote port-forwarding with the incorrect +- bugfix: canceling the remote port-forwarding with the incorrect bind-address. FIXED. - bugfix: sftp had missed to close the file in some case. FIXED. - bugfix: ls(sftp) will throw an exception for the empty directory @@ -51,19 +350,19 @@ Changes since version 0.1.40: - feature: new ciphers: aes128-ctr,aes192-ctr,aes256-ctr, 3des-ctr,arcfour,arcfour128 ,arcfour256 - + Changes since version 0.1.39: - bugfix: ProxySOCKS4 had not been functional. FIXED. - bugfix: NPE at closing the session when it is not opened. FIXED. - change: JSch#getConfing has become public. - + Changes since version 0.1.38: - bugfix: session will be dropped at rekeying. FIXED. - bugfix: NPE should not be thrown at unexpected session drop. FIXED. - change: Channel#getSession() may throw JSchExecption. - + Changes since version 0.1.37: - bugfix: NPE should not be thrown at unexpected session drop. FIXED. - bugfix: AIOOBE at Session#connect(). FIXED. @@ -87,7 +386,7 @@ Changes since version 0.1.37: Changes since version 0.1.36: -- bugfix: some sftpd will send invalid data in sftp protocol +- bugfix: some sftpd will send invalid data in sftp protocol point of view, and we need to work around such data. FIXED. - bugfix: the stream forwarding had been broken since 0.1.30. FIXED. - bugfix: failed to detect 'SSH_MSG_CHANNEL_OPEN_FAILURE'. FIXED. @@ -100,18 +399,18 @@ Changes since version 0.1.36: - change: build.xml will enable 'javac.debug' option by the default. - change: added logging messages to IndentityFile and Session class. - change: followings are deprecated methods, - InputStream ChannelSftp#get(String src, + InputStream ChannelSftp#get(String src, int mode) - InputStream ChannelSftp#get(String src, - SftpProgressMonitor, + InputStream ChannelSftp#get(String src, + SftpProgressMonitor, int mode) - feature: following method is added, - InputStream ChannelSftp#get(String src, - SftpProgressMonitor monitor, + InputStream ChannelSftp#get(String src, + SftpProgressMonitor monitor, long skip) - -Changes since version 0.1.35: + +Changes since version 0.1.35: - bugfix: ChannelSftp can not handle the local filenames correctly on Windows. FIXED. - bugfix: '/' must be handled as the file separator on JVM for Windows. FIXED. - change: the system property @@ -120,20 +419,20 @@ Changes since version 0.1.35: if that property is not given explicitly. - change: added changes about ChannelSftp#{pwd(), home()} to ChangeLog; 'Changes since version 0.1.34:' section. - - -Changes since version 0.1.34: + + +Changes since version 0.1.34: - bugfix: the OutputStream from the channel may make the JVM lockup in some case. FIXED. - There was a possibility that Channel#connect() may be failed + There was a possibility that Channel#connect() may be failed to initialize its internal without throwing the JSchException. - On such case, the write operation for OutputStream from + On such case, the write operation for OutputStream from that channel will cause the system(JVM) to lock up. - bugfix: ChannelSftp had problems filename globbing. FIXED. - bugfix: the message included in SSH_FXP_STATUS must be UTF-8. FIXED. -- change: ChannelSftp supports the filename globbing for +- change: ChannelSftp supports the filename globbing for the filename in multi-byte characters. -- change: ChannelSftp will internally handle filenames in UTF-8 encoding. +- change: ChannelSftp will internally handle filenames in UTF-8 encoding. - change: ChannelSftp#pwd() may throw an SftpException. - change: ChannelSftp#home() may throw an SftpException. - feature: following methods have been added in ChannelSftp @@ -141,16 +440,16 @@ Changes since version 0.1.34: String getClientVersion() void setFilenameEncoding(String encoding) String getExtension(String key) - -Changes since version 0.1.33: -- bugfix: there had a possibility that the session may be broken + +Changes since version 0.1.33: +- bugfix: there had a possibility that the session may be broken if ciphers for upward/downward streams are different. FIXED. -- bugfix: the authentication method "keyboard-interactive" had +- bugfix: the authentication method "keyboard-interactive" had not been tried without UserInfo. FIXED. -- bugfix: ChannelShell#setTerminalMode(byte[] terminal_mode) had +- bugfix: ChannelShell#setTerminalMode(byte[] terminal_mode) had not been functional. FIXED. -- bugfix: the remote port-forwarding to the daemon had been broken - since 0.1.30. FIXED. +- bugfix: the remote port-forwarding to the daemon had been broken + since 0.1.30. FIXED. - change: the cipher "aes128-cbc" will be used if AES is available. - change: the interface 'com.jcraft.jsch.ForwardedTCPIPDaemon' has been changed. - change: the data transfer rate will be improved on some environment. @@ -162,8 +461,8 @@ Changes since version 0.1.33: - feature: Session#setConfig(String key, String value), JSch#setConfig(String key, String value) have been added. - -Changes since version 0.1.32: + +Changes since version 0.1.32: - bugfix: freeze in 'diffie-hellman-group-exchange-sha1'. FIXED. By the default, 'diffie-hellman-group1-sha1' will be used and if you have not chosen 'diffie-hellman-group-exchange-sha1' @@ -177,15 +476,15 @@ Changes since version 0.1.32: At the failure or timeout, 'SSH_MSG_CHANNEL_OPEN_FAILURE' will be sent to sshd. - -Changes since version 0.1.31: + +Changes since version 0.1.31: - bugfix: remote port forwarding will be hanged at its closing. FIXED. -- bugfix: X forwarding channels will be hanged and some resources +- bugfix: X forwarding channels will be hanged and some resources will be leaked whenever they are closed. FIXED. - bugfix: failed to detect "Connection refused". FIXED. -- bugfix: at the failure for keyboard-interactive auth method, +- bugfix: at the failure for keyboard-interactive auth method, a session will be terminated. FIXED. -- bugfix: due to the cancel for keyboard-interactive auth method, +- bugfix: due to the cancel for keyboard-interactive auth method, a session will be terminated. FIXED. - change: com.jcraft.jsch.jcraft.Compression#uncompress will respect the argument "start". @@ -193,11 +492,11 @@ Changes since version 0.1.31: - feature: Session#setPortForwardingL will return the assigned local TCP port number; TCP port will be assigned dynamically if lport==0. - feature: support for SSH_MSG_UNIMPLEMENTED. -- feature: support for PASSWD_CHANGEREQ. +- feature: support for PASSWD_CHANGEREQ. + - -Changes since version 0.1.30: -- bugfix: a problem in padding for ciphered private key. +Changes since version 0.1.30: +- bugfix: a problem in padding for ciphered private key. PKCS#5 padding should be used. FIXED. - bugfix: crash in parsing invalid public key file. FIXED. - bugfix: a public key may not have a comment. FIXED. @@ -213,7 +512,8 @@ Changes since version 0.1.30: - change: if alias-name is given, non-standard TCP port number will not be saved in 'known_hosts' file. -Changes since version 0.1.29: + +Changes since version 0.1.29: - bugfix: ChannelSftp#cd() will not throw an exception even if a file is given. FIXED. - bugfix: ChannelSftp#put() has a bug which will appear in using @@ -227,7 +527,7 @@ Changes since version 0.1.29: be used automatically. FIXED. - bugfix: the session will be crashed by the long banner message. FIXED. - change: '/dev/random' will not be referred on Gnu/Linux. -- change: if non-standard TCP port number is used, that number will +- change: if non-standard TCP port number is used, that number will be saved in known_hosts file as recent OpenSSH's ssh client does. - change: Channel#getOutputStream will not use Piped{Output,Input}Stream. - change: com.jcraft.jsch.HostKeyRepository interface has been @@ -238,12 +538,12 @@ Changes since version 0.1.29: Refer to 'examples/KnownHosts.java'. - feature: the authentication method 'gssapi-with-mic' has been experimentally supported. -- feature: com.jcraft.jsch.Logger interface and +- feature: com.jcraft.jsch.Logger interface and JSch#setLogger(Logger logger) have been added. Refer to 'examples/Logger.java' for the usage. -Changes since version 0.1.28: +Changes since version 0.1.28: - bugfix: ChannelSftp#put will stack in some situations FIXED. - bugfix: ChannelSftp invoked 'glob_remote' redundantly. FIXED. - bugfix: ChannelSftp failed to make globbing for some file names. FIXED. @@ -256,7 +556,7 @@ Changes since version 0.1.28: - bugfix: ProxySOCKS4 did not carefully read file input-streams. FIXED. - bugfix: ProxySOCKS5 did not carefully read file input-streams. FIXED. - bugfix: ForwardedTCPIPDaemom may fail in some situation. FIXED. -- bugfix: X forwarding failed to handle the magic-cookie +- bugfix: X forwarding failed to handle the magic-cookie in some case FIXED. Thanks to Walter Pfannenmller. - bugfix: setKnownHosts in KnownHosts.java doesn't read the last @@ -294,48 +594,48 @@ Changes since version 0.1.28: - feature: ChannelShell#setPtyType(String ttype) is added. - feature: Session#setPassword(byte[] password) is added. - feature: Session#setHostKeyAlias(String alias) is added. -- feature: KeepAlive is implemented and +- feature: KeepAlive is implemented and Session#setServerAliveInterval(int interval) and Session#setServerAliveCountMax(int count) are added. - feature: Session#sendKeepAliveMsg() is added. - feature: JSchException#getCause() may return a reason. -- feature: SftpException#getCause() may return a reason. +- feature: SftpException#getCause() may return a reason. - feature: ChannelExec#setErrStream(OutputStream out, boolean dontclose) is added. - -Changes since version 0.1.27: + +Changes since version 0.1.27: - bugfix: ChannelSftp#localAbsolutePath did not work correctly. FIXED. - bugfix: ChannelSftp#chmod did not work for directory. FIXED. - bugfix: ProxyHTTP had a bug in processing HTTP headers. FIXED. - bugfix: messages before server's version string should be ignored. FIXED. - feature: Environment Variable Passing. - + Changes since version 0.1.26: -- bugfix: there was a session crash bug. That occurrence is rare, but +- bugfix: there was a session crash bug. That occurrence is rare, but depends on the thread scheduling. FIXED. - bugfix: problems in generating remote/local absolute paths on sftp. FIXED. - bugfix: problems in handling cancel operations for sftp. FIXED. - bugfix: ChannelX11s were not terminated for a wrong cookie. FIXED. -- bugfix: NoSuchAlgorithmException should be thrown if JCE is not +- bugfix: NoSuchAlgorithmException should be thrown if JCE is not accessible. FIXED. - bugfix: ProxyHTTP should check the return code from proxy. FIXED. - bugfix: server's version string should be checked carefully. FIXED. - feature: some more improvements on sftp uploading. - feature: 'getUserName' method is added to Session class. - -Changes since version 0.1.25: + +Changes since version 0.1.25: - bugfix: infinite loop/hang on connection at unexpected error during key-exchanging operation. FIXED - bugfix: delays on sftp uploading. FIXED - bugfix: failed to purge a host-key from its repository in some case. FIXED. - feature: SOCKS4 proxy - -Changes since version 0.1.24: -- bugfix: remote port forwarding is not established. FIXED. + +Changes since version 0.1.24: +- bugfix: remote port forwarding is not established. FIXED. - bugfix: failed to parse known_hosts file if it has a long public key blob. FIXED. - bugfix: sftp put/get operations keep failing. FIXED. @@ -346,45 +646,45 @@ Changes since version 0.1.24: - feature: added NONE Cipher switching support. - feature: timeout check will be enabled for proxy connections. - -Changes since version 0.1.23: + +Changes since version 0.1.23: - bugfix: there was resource leak problems in closing local port forwardings. - FIXED. -- bugfix: there was a session crash problems in using aes-cbc cipher. FIXED. + FIXED. +- bugfix: there was a session crash problems in using aes-cbc cipher. FIXED. - change: ChannelSession.setPtySize was redefined. - feature: added SocketFactory for remote port forwarding. - Session.setPortForwardingR(int rport, String host, int lport, + Session.setPortForwardingR(int rport, String host, int lport, SocketFactory sf) -- feature: added ServerSocketFactory for local port forwarding. +- feature: added ServerSocketFactory for local port forwarding. Session.setPortForwardingL(String boundaddress, int lport, String host, int rport, ServerSocketFactory ssf) -Changes since version 0.1.22: +Changes since version 0.1.22: - bugfix: there was a freeze problem at fails on key-exchanging. FIXED. - bugfix: race-condition forcefully disconnects session in closing channels. - FIXED. + FIXED. + - -Changes since version 0.1.21: +Changes since version 0.1.21: - bugfix: there is a bug in read() method implementation for the - input-stream returned from ChannelSftp.get(). FIXED. + input-stream returned from ChannelSftp.get(). FIXED. - bugfix: at fail on requesting for the remote port forwarding, - an exception should be thrown. FIXED. + an exception should be thrown. FIXED. - bugfix: SSH_MSG_CHANNEL_OPEN request for the X11 forwarding should not be accepted if clients don not expect it. FIXED. - bugfix: there is a problem in transferring large data(mote than 1GB) to sshd from recent OpenSSH(3.6.1 or later). FIXED. - For security concerns, those sshd will re-key periodically and + For security concerns, those sshd will re-key periodically and jsch had failed to handle it. - bugfix: 'exec', 'shell' and 'sftp' channels will fail if the acceptable packet size by remote sshd is not so large. FIXED. -- bugfix: there are problems in 'InputStream ChannelSftp.get(String)' +- bugfix: there are problems in 'InputStream ChannelSftp.get(String)' and 'OutputStream put(String)'. FIXED. -- feature: added boolean flag 'dontclose' to +- feature: added boolean flag 'dontclose' to * setInputStream(), * setOutputStream() and - * setExtOutputStream() + * setExtOutputStream() methods of Channel class. - feature: added 'com.jcraft.jsch.ChannelSubsystem' - feature: allowed to control the compression level in the packet compression. @@ -398,11 +698,11 @@ Changes since version 0.1.21: will be used instead of Thread.sleep. -Changes since version 0.1.20: -- known issue: there are problems in 'InputStream ChannelSftp.get(String)' +Changes since version 0.1.20: +- known issue: there are problems in 'InputStream ChannelSftp.get(String)' and 'OutputStream put(String)'. They will be re-implemented in the next release. -- bugfix: EOF packets should not be sent twice. This bug had crashed +- bugfix: EOF packets should not be sent twice. This bug had crashed the session on every channel close. FIXED. - bugfix: at the fail on opening connection to remote sshd, a misleading exception "invalid server's version string" @@ -412,37 +712,37 @@ Changes since version 0.1.20: - bugfix: fixed bugs in file name globbing on sftp. - change: to transfer packets efficiently, the size of internal buffer for each channel has been increased. -- change: ChannelSftp.ls will return a vector of +- change: ChannelSftp.ls will return a vector of com.jcraft.jsch.ChannelSftp.LsEntry. Sorry for inconveniences. -- feature: added ForwardedTCPIPDaemon. Refer to 'examples/Daemon.java', +- feature: added ForwardedTCPIPDaemon. Refer to 'examples/Daemon.java', which demonstrates to provide network services like inetd. - feature: ChannelExec.setPty() method to request for assigning pseudo tty. - feature: added ciphers "aes128-cbc", "aes192-cbc" and "aes256-cbc". Refer to 'examples/AES.java'. -- feature: local port-forwarding settings can be dynamically deleted +- feature: local port-forwarding settings can be dynamically deleted by the bound address. - feature: added 'Channel.isClosed()'. Channel.getExitStatus() should be invoked after Channel.isClosed()==true. - -Changes since version 0.1.19: + +Changes since version 0.1.19: - ClassCastException while calling ChannelExec.finalize() method. FIXED. Thanks to wswiatek at ais dot pl. - -Changes since version 0.1.18: + +Changes since version 0.1.18: - fixed problems related to thread-safety. Thanks to Eric Meek at cs dot utk dot edu. -- At the lost of the network connectivity to the remote SSHD, clients +- At the lost of the network connectivity to the remote SSHD, clients connected to the local port were never made aware of the disconnection. FIXED. -- fixed confusions in handling EOFs from local input stream and +- fixed confusions in handling EOFs from local input stream and the input stream for remote process. - 'com.jcraft.jsch.jce.AES128CBC' is added, but it is not be functional in this release. It will work in the next release. - Some sshd(Foxit-WAC-Serve) waits for SSH_MSG_NEWKEYS request before - sending it. FIXED. -- fixed a problem in connecting to Cisco Devices. + sending it. FIXED. +- fixed a problem in connecting to Cisco Devices. Thanks to Jason Jeffords at comcast dot net. - changed the method 'add' of 'HostKeyRepository' interface. - 'UIKeyborarInteracetive' will ignore empty prompt by sshd. @@ -450,31 +750,31 @@ Changes since version 0.1.18: - added '-p' for scp command in 'examples/ScpTo.java' to preserve modification times, access times, and modes from the original file. - -Changes since version 0.1.17: + +Changes since version 0.1.17: - added 'com.jcraft.jsch.HostKeyRepository' interface. It will allow you to handle host keys in your own repository (for example, RDB) instead of using 'known_hosts' file. - added methods to get the finger-print of host keys. - refer to 'examples/KnownHosts.java'. + refer to 'examples/KnownHosts.java'. - improved 'known_hosts' file handling. - comment lines will be kept. - SSH1 host keys will be kept. - - each hostname can have multiple host keys. + - each hostname can have multiple host keys. - fixed a crash bug in processing private keys which have too long key-bits. - -Changes since version 0.1.16: + +Changes since version 0.1.16: - 'com.jcraft.jsch.jce.DHG1' and 'com.jcraft.jsch.jce.DHGEX' are moved to - 'com.jcraft.jsch' package. + 'com.jcraft.jsch' package. - added APIs to handle hostkeys included in 'known_hosts', JSch.getHostKeys(), JSch.removeHostKey() - allowing to set timeout value in opening sockets, Session.connect(int timeout) - -Changes since version 0.1.15: + +Changes since version 0.1.15: - adding support of setting mtime for remote files on sftp channel. - setKnownHosts method of JSch class will accept InputStream. - implementation of Basic password authentication for HTTP proxy. @@ -483,15 +783,15 @@ Changes since version 0.1.15: - methods in SftpATTRS class has been public. - working around SIGBLOB bug hidden in older sshd. - -Changes since version 0.1.14: + +Changes since version 0.1.14: - fixed a crash bug in accepting keep-alive messages. -- the parent directory of 'known_hosts' file will be created +- the parent directory of 'known_hosts' file will be created if it does not exist. - the Subsystem channel support was removed. - -Changes since version 0.1.13: + +Changes since version 0.1.13: - added 'setClientVersion' method to Session class. - fixed hung-up problem on SftpChannel in connecting to the sshd, which does not support sftp. @@ -502,36 +802,36 @@ Changes since version 0.1.13: - RuntimeExceptions will be thrown from jsch APIs. - SSH_MSG_CHANNEL_SUCCESS and SSH_MSG_CHANNEL_FAILURE requests have been supported. - - -Changes since version 0.1.12: + + +Changes since version 0.1.12: - added the partial authentication support. - allowing to change the passphrase of a private key file instead of creating a new private key. -- added 'examples/ChangePassphrase.java' +- added 'examples/ChangePassphrase.java' - the interface 'UIKeyboardInteractive' has been modified. - -Changes since version 0.1.11: + +Changes since version 0.1.11: - RSA keypair generation. - added the method 'getFingerPrint' to KeyPair class, which will return the finger print of the public key. - fixed a bug in generating non-ciphered private key. - -Changes since version 0.1.10: + +Changes since version 0.1.10: - fixed a bug in the password authentication, sneaked in 0.1.9. By this bug, the password authentication had failed every time. - -Changes since version 0.1.9: + +Changes since version 0.1.9: - username and password can be in UTF-8 encoding. - DSA keypair generation. - added 'examples/KeyGen.java', which demonstrates the DSA keypair generation. - -Changes since version 0.1.8: + +Changes since version 0.1.8: - fixed crash problems on the local port forwarding. - fixed crash problems on the remote port forwarding. - added setErrStream() and getErrStream() to ChannelExec. @@ -540,10 +840,10 @@ Changes since version 0.1.8: - added 'examples/UserAuthKI.java', which demonstrates keyboard-interactive authentication. - -Changes since version 0.1.7: + +Changes since version 0.1.7: - added APIs for sftp resume downloads and uploads. - The author greatly appreciates + The author greatly appreciates elpernotador(webmaster at unlix dot com dot ar), who motivated him to hack this functionality. - 'examples/Sftp.java' demonstrates sftp resume functionality. @@ -553,96 +853,96 @@ Changes since version 0.1.7: - fixed a freeze bug in 'Inputstream get(String src)' method of 'ChannelSftp' class. - -Changes since version 0.1.6: + +Changes since version 0.1.6: - added 'int getExitStatus()' method to 'Channel' class. - fixed crash bugs in closing channels for port forwarding. - fixed glitches in managing forwarded ports. - -Changes since version 0.1.5: + +Changes since version 0.1.5: - fixed crash bugs in port forwarding. - modified to use "ssh-rsa" for key-exchanging by the default. - the port forwarding setting can be canceled dynamically. - fixed a freeze bug in getting an empty file on sftp channel. - -Changes since version 0.1.4: + +Changes since version 0.1.4: - fixed a bug in managing local window size. The local window should be consumed by CHANNEL_EXTENDED_DATA packet. - checking the availability of the ssh session in opening channels. - In some case, ssh session had been freezed. + In some case, ssh session had been freezed. - java.io.File.separator will be refereed in generating local pathname on sftp channel. - absolute local pathname will be handled correctly on sftp channel. - -Changes since version 0.1.3: + +Changes since version 0.1.3: - fixed a serious bug, which had leaked resources related to - ChannelExec. + ChannelExec. - added the older SFTP protocol(version 0, 1, 2) support. - fixed a problem in the authentication step for FSecure's sshd. - fixed a bug, which had broken Diffie-Hellman key exchange in some case. -- implemented the file name globbing for local files on sftp session. +- implemented the file name globbing for local files on sftp session. - fixed a bug in the file name globbing. - added an interface 'SftpProgressMonitor'. - modified 'examples/Sftp.java' to demonstrate displaying progress-bar - in transferring files. - - -Changes since version 0.1.2: + in transferring files. + + +Changes since version 0.1.2: - modified 'build.xml' to allow Ant users to compile jsch with debug support (i.e. line-number tables) by overriding the property javac.debug on the command line. - added a property 'StrictHostKeyChecking'. - added 'UserAuthNone' class to request a list of authentication methods on - remote sshd. + remote sshd. - channels will be managed in each sessions. - added 'ChannelSubsystem', which allows users to use their own implementations for subsystems. - added 'isEOF()' method to 'Channel' class. - supported key pair files in DOS file format. - -Changes since version 0.1.1: + +Changes since version 0.1.1: - added the file name globbing support on sftp session. - fixed a bug in the public key authentication. When there was not a public key in ~/.ssh/, that problem occurred. - improved the 'setTimeout' method. - fixed a typo in 'LICENSE.txt' - -Changes since version 0.1.0: + +Changes since version 0.1.0: - added 'rekey' method to 'Session' class for key re-exchanging. - added 'rekey' and 'compression' command to 'examples/Sftp.java'. - added new 'get' and 'put' methods to 'ChannelSftp'. Those methods will operate I/O streams. -- methods in 'ChannelSftp' will throw 'SftpException' +- methods in 'ChannelSftp' will throw 'SftpException' - 'ChannelSftp.Ssh_exp_name' is added for the output of 'ls'. Thanks to Graeme Vetterlein. - added 'setTimeout' and 'getTimeout' methods to 'Session' class. - guess will be done in the algorithm negotiation step. - FSecure's DSA private key has been supported partially. - hostkeys will be saved into 'known_hosts' file. -- fixed a bug in 'Util.toBase64' method. +- fixed a bug in 'Util.toBase64' method. - 'Identity' will reject unrecognized keys. -- 'build.xml' will check if jzlib is available or not. - Thanks to Stefan Bodewig. +- 'build.xml' will check if jzlib is available or not. + Thanks to Stefan Bodewig. - added javadoc target in 'build.xml'. Thanks to Robert Anderson. - - -Changes since version 0.0.13: + + +Changes since version 0.0.13: - fixed a bug in connecting to Fsecure's sshd on Windows. -- the license is changed to BSD style. +- the license is changed to BSD style. -Changes since version 0.0.12: +Changes since version 0.0.12: - fixed a bug in verifying DAS signatures. -- added 'SftpATTR' class, which allow you to get attributes of remote files on +- added 'SftpATTR' class, which allow you to get attributes of remote files on sftp channel, and 'stat', 'lstat' method are added to 'ChannelSftp' class. -- added 'getInputStream' and 'getOutputStream' methods Channel class, which - return passive I/O streams. +- added 'getInputStream' and 'getOutputStream' methods Channel class, which + return passive I/O streams. - 'setIdentity' method is deleted from 'Session' class and 'addIdentity' method is added to 'JSch' class - 'setUserName' method is deleted from 'Session' class and @@ -650,8 +950,8 @@ Changes since version 0.0.12: - 'isConnected' method is added to 'Session' class. - 'UserInfo' interface is changed. - -Changes since version 0.0.11: + +Changes since version 0.0.11: - taking care of remote window size. - adding 'disconnect' method to 'Channel' and 'Session' classes. - signal sending support. @@ -666,9 +966,9 @@ Changes since version 0.0.11: package. - fixed a bug in handling 'SSH_MSG_CHANNEL_REQUET' request. - fixed a bug in sending multiple requests on a single session. - - -Changes since version 0.0.10: + + +Changes since version 0.0.10: - Diffie-Hellman key exchange 'diffie-hellman-group1-sha1' is supported. Refer to 'src/com/jcraft/jsch/jce/DHG1.java'. Thanks to Mitsugu Kitano, whose feedback was very helpful. @@ -679,47 +979,47 @@ Changes since version 0.0.10: - 'examples/Sftp.java' is updated. 'chgrp','chown','chmod' commands are supported. - -Changes since version 0.0.9: + +Changes since version 0.0.9: - SSH File Transfer Protocol is supported partially. - 'examples/Sftp.java' is added. This example is a tiny sftp command and supports 'cd','put','get','rm',etc. -- 'close' method is added to Channel interface. +- 'close' method is added to Channel interface. - build.xml for examples is added. Thanks to Ronald Broberg. - -Changes since version 0.0.8: + +Changes since version 0.0.8: - the tunneling through a SOCKS5 proxy is supported. - 'examples/ScpFrom.java' is added. - 'com.jcraft.jsch.UserInfo' interface is modified. - -Changes since version 0.0.7: + +Changes since version 0.0.7: - Packet comression is supported. - 'examples/Compression.java' is added. - JZlib is included. - -Changes since version 0.0.6: + +Changes since version 0.0.6: - RSA host key is supported. - RSA public key authentication is supported. -Changes since version 0.0.5: +Changes since version 0.0.5: - DSA public key authentication is supported. - examples/UserAuthPubKey.java is added. - examples/ScpTo.java is added. - -Changes since version 0.0.4: + +Changes since version 0.0.4: - 3des-cbc is supported. - hmac-sha1 is supported. - hmac-md5-96 is supported. -- hmac-sha1-96 is supported. - +- hmac-sha1-96 is supported. + -Changes since version 0.0.3: +Changes since version 0.0.3: - port forwarding, similar to the -L option of SSH. - examples/PortForwardingL.java is added. - examples/StreamForwarding.java is added. @@ -727,17 +1027,17 @@ Changes since version 0.0.3: - stream forwarding is added. - ChannelSftp class is added for implementing filexfer. - interfaces for jsch users are changed. - -Changes since version 0.0.2: -- remote exec is supported. + +Changes since version 0.0.2: +- remote exec is supported. - examples/Exec.java is added. - build.xml and some scripts for Ant are added. (lbruand) - Const class is added. (lbruand) - + Changes since version 0.0.1: - the tunneling via HTTP proxy is supported. - port forwarding like option -R of ssh command. the given port on the remote host will be forwarded to the given host - and port on the local side. + and port on the local side. diff --git a/LICENSE.txt b/LICENSE.txt index 2a5daa8..303096b 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2,7 +2,7 @@ JSch 0.0.* was released under the GNU LGPL license. Later, we have switched over to a BSD-style license. ------------------------------------------------------------------------------ -Copyright (c) 2002-2010 Atsuhiko Yamanaka, JCraft,Inc. +Copyright (c) 2002-2015 Atsuhiko Yamanaka, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README b/README index a52886e..d00a219 100644 --- a/README +++ b/README @@ -6,7 +6,7 @@ http://www.jcraft.com/jsch/ -Last modified: Wed Nov 1 14:43:31 UTC 2006 +Last modified: Thu Mar 18 13:58:16 UTC 2015 Description @@ -50,14 +50,21 @@ Features o J2SE 1.2.2 and later and Bouncycastle's JCE implementation that can be obtained at http://www.bouncycastle.org/ * SSH2 protocol support. -* Key exchange: diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1 +* Key exchange: diffie-hellman-group-exchange-sha1, + diffie-hellman-group1-sha1, + diffie-hellman-group14-sha1, + diffie-hellman-group-exchange-sha256, + ecdh-sha2-nistp256, + ecdh-sha2-nistp384, + ecdh-sha2-nistp521 * Cipher: blowfish-cbc,3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc 3des-ctr,aes128-ctr,aes192-ctr,aes256-ctc, arcfour,arcfour128,arcfour256 * MAC: hmac-md5,hmac-md5-96,hmac-sha1,hmac-sha1-96 -* Host key type: ssh-dss, ssh-rsa +* Host key type: ssh-dss,ssh-rsa, + ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521 * Userauth: password -* Userauth: publickey(DSA,RSA) +* Userauth: publickey(DSA,RSA,ECDSA) * Userauth: keyboard-interactive * Userauth: gssapi-with-mic * X11 forwarding. @@ -72,6 +79,7 @@ Features * envrironment variable passing. * remote exec. * generating DSA and RSA key pairs. +* supporting private keys in OpenSSL(traditional SSLeay) and PKCS#8 format. * SSH File Transfer Protocol(version 0, 1, 2, 3) * partial authentication * packet compression: zlib, zlib@openssh.com diff --git a/build.xml b/build.xml index 4c4b8a3..2184647 100644 --- a/build.xml +++ b/build.xml @@ -5,14 +5,17 @@ sshd server and use port forwarding, X11 forwarding, file transfer, etc., and you can integrate its functionality into your own Java programs - - + + + + + @@ -27,22 +30,39 @@ you can integrate its functionality into your own Java programs description="compile the source " > - + classname="com.jcraft.jzlib.ZStream"> + + + + - - - - - + + + + 0) continue; System.out.println("exit-status: "+channel.getExitStatus()); break; } diff --git a/examples/KeyGen.java b/examples/KeyGen.java index 7349949..e935649 100644 --- a/examples/KeyGen.java +++ b/examples/KeyGen.java @@ -1,23 +1,54 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This progam will demonstrate the DSA keypair generation. + * $ CLASSPATH=.:../build javac KeyGen.java + * $ CLASSPATH=.:../build java KeyGen rsa output_keyfile comment + * or + * $ CLASSPATH=.:../build java KeyGen dsa output_keyfile comment + * You will be asked a passphrase for output_keyfile. + * If everything works fine, you will get the DSA or RSA keypair, + * output_keyfile and output_keyfile+".pub". + * The private key and public key are in the OpenSSH format. + * + */ import com.jcraft.jsch.*; import javax.swing.*; class KeyGen{ public static void main(String[] arg){ + int key_size = 1024; if(arg.length<3){ System.err.println( "usage: java KeyGen rsa output_keyfile comment\n"+ -" java KeyGen dsa output_keyfile comment"); +" java KeyGen dsa output_keyfile comment\n"+ +" java KeyGen ecdsa-sha2-256 output_keyfile comment\n"+ +" java KeyGen ecdsa-sha2-384 output_keyfile comment\n"+ +" java KeyGen ecdsa-sha2-521 output_keyfile comment"); System.exit(-1); } String _type=arg[0]; int type=0; if(_type.equals("rsa")){type=KeyPair.RSA;} else if(_type.equals("dsa")){type=KeyPair.DSA;} + else if(_type.equals("ecdsa-sha2-nistp256")){ + type=KeyPair.ECDSA; + key_size=256; + } + else if(_type.equals("ecdsa-sha2-nistp384")){ + type=KeyPair.ECDSA; + key_size=384; + } + else if(_type.equals("ecdsa-sha2-nistp521")){ + type=KeyPair.ECDSA; + key_size=521; + } else { System.err.println( "usage: java KeyGen rsa output_keyfile comment\n"+ -" java KeyGen dsa output_keyfile comment"); +" java KeyGen dsa output_keyfile comment\n"+ +" java KeyGen ecdsa-sha2-256 output_keyfile comment\n"+ +" java KeyGen ecdsa-sha2-384 output_keyfile comment\n"+ +" java KeyGen ecdsa-sha2-521 output_keyfile comment"); System.exit(-1); } String filename=arg[1]; @@ -36,7 +67,7 @@ public static void main(String[] arg){ } try{ - KeyPair kpair=KeyPair.genKeyPair(jsch, type); + KeyPair kpair=KeyPair.genKeyPair(jsch, type, key_size); kpair.setPassphrase(passphrase); kpair.writePrivateKey(filename); kpair.writePublicKey(filename+".pub", comment); diff --git a/examples/KnownHosts.java b/examples/KnownHosts.java index c119349..0f53006 100644 --- a/examples/KnownHosts.java +++ b/examples/KnownHosts.java @@ -1,4 +1,14 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program will demonstrate the 'known_hosts' file handling. + * $ CLASSPATH=.:../build javac KnownHosts.java + * $ CLASSPATH=.:../build java KnownHosts + * You will be asked username, hostname, a path for 'known_hosts' and passwd. + * If everything works fine, you will get the shell prompt. + * In current implementation, jsch only reads 'known_hosts' for checking + * and does not modify it. + * + */ import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; diff --git a/examples/Logger.java b/examples/Logger.java index b98f119..5abefff 100644 --- a/examples/Logger.java +++ b/examples/Logger.java @@ -1,4 +1,8 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program will demonstrate how to enable logging mechanism and + * get logging messages. + */ import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; diff --git a/examples/OpenSSHConfig.java b/examples/OpenSSHConfig.java new file mode 100644 index 0000000..537f95e --- /dev/null +++ b/examples/OpenSSHConfig.java @@ -0,0 +1,137 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program demonsrates how to use OpenSSHConfig class. + * $ CLASSPATH=.:../build javac OpenSSHConfig.java + * $ CLASSPATH=.:../build java OpenSSHConfig + * You will be asked username, hostname and passwd. + * If everything works fine, you will get the shell prompt. Output may + * be ugly because of lacks of terminal-emulation, but you can issue commands. + * + */ +import com.jcraft.jsch.*; +import java.awt.*; +import javax.swing.*; + +public class OpenSSHConfig { + public static void main(String[] arg){ + + try{ + JSch jsch=new JSch(); + + String host=null; + if(arg.length>0){ + host=arg[0]; + } + else{ + host=JOptionPane.showInputDialog("Enter username@hostname", + System.getProperty("user.name")+ + "@localhost"); + } + String user=host.substring(0, host.indexOf('@')); + host=host.substring(host.indexOf('@')+1); + + String config = + "Port 22\n"+ + "\n"+ + "Host foo\n"+ + " User "+user+"\n"+ + " Hostname "+host+"\n"+ + "Host *\n"+ + " ConnectTime 30000\n"+ + " PreferredAuthentications keyboard-interactive,password,publickey\n"+ + " #ForwardAgent yes\n"+ + " #StrictHostKeyChecking no\n"+ + " #IdentityFile ~/.ssh/id_rsa\n"+ + " #UserKnownHostsFile ~/.ssh/known_hosts"; + + System.out.println("Generated configurations:"); + System.out.println(config); + + ConfigRepository configRepository = + com.jcraft.jsch.OpenSSHConfig.parse(config); + //com.jcraft.jsch.OpenSSHConfig.parseFile("~/.ssh/config"); + + jsch.setConfigRepository(configRepository); + + // "foo" is from "Host foo" in the above config. + Session session=jsch.getSession("foo"); + + String passwd = JOptionPane.showInputDialog("Enter password"); + session.setPassword(passwd); + + UserInfo ui = new MyUserInfo(){ + public void showMessage(String message){ + JOptionPane.showMessageDialog(null, message); + } + public boolean promptYesNo(String message){ + Object[] options={ "yes", "no" }; + int foo=JOptionPane.showOptionDialog(null, + message, + "Warning", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, options, options[0]); + return foo==0; + } + + // If password is not given before the invocation of Session#connect(), + // implement also following methods, + // * UserInfo#getPassword(), + // * UserInfo#promptPassword(String message) and + // * UIKeyboardInteractive#promptKeyboardInteractive() + + }; + + session.setUserInfo(ui); + + session.connect(); // making a connection with timeout as defined above. + + Channel channel=session.openChannel("shell"); + + channel.setInputStream(System.in); + /* + // a hack for MS-DOS prompt on Windows. + channel.setInputStream(new FilterInputStream(System.in){ + public int read(byte[] b, int off, int len)throws IOException{ + return in.read(b, off, (len>1024?1024:len)); + } + }); + */ + + channel.setOutputStream(System.out); + + /* + // Choose the pty-type "vt102". + ((ChannelShell)channel).setPtyType("vt102"); + */ + + /* + // Set environment variable "LANG" as "ja_JP.eucJP". + ((ChannelShell)channel).setEnv("LANG", "ja_JP.eucJP"); + */ + + //channel.connect(); + channel.connect(3*1000); + } + catch(Exception e){ + System.out.println(e); + } + } + + public static abstract class MyUserInfo + implements UserInfo, UIKeyboardInteractive{ + public String getPassword(){ return null; } + public boolean promptYesNo(String str){ return false; } + public String getPassphrase(){ return null; } + public boolean promptPassphrase(String message){ return false; } + public boolean promptPassword(String message){ return false; } + public void showMessage(String message){ } + public String[] promptKeyboardInteractive(String destination, + String name, + String instruction, + String[] prompt, + boolean[] echo){ + return null; + } + } +} diff --git a/examples/PortForwardingL.java b/examples/PortForwardingL.java index bc560bb..a34f238 100644 --- a/examples/PortForwardingL.java +++ b/examples/PortForwardingL.java @@ -1,4 +1,15 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program will demonstrate the port forwarding like option -L of + * ssh command; the given port on the local host will be forwarded to + * the given remote host and port on the remote side. + * $ CLASSPATH=.:../build javac PortForwardingL.java + * $ CLASSPATH=.:../build java PortForwardingL + * You will be asked username, hostname, port:host:hostport and passwd. + * If everything works fine, you will get the shell prompt. + * Try the port on localhost. + * + */ import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; diff --git a/examples/PortForwardingR.java b/examples/PortForwardingR.java index 81aa980..56b18ec 100644 --- a/examples/PortForwardingR.java +++ b/examples/PortForwardingR.java @@ -1,4 +1,15 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program will demonstrate the port forwarding like option -R of + * ssh command; the given port on the remote host will be forwarded to + * the given host and port on the local side. + * $ CLASSPATH=.:../build javac PortForwardingR.java + * $ CLASSPATH=.:../build java PortForwardingR + * You will be asked username, hostname, port:host:hostport and passwd. + * If everything works fine, you will get the shell prompt. + * Try the port on remote host. + * + */ import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; diff --git a/examples/README b/examples/README index c9fd725..9632d28 100644 --- a/examples/README +++ b/examples/README @@ -38,6 +38,13 @@ This directory contains some examples, which demonstrate how to use JSch You will be asked username, hostname, proxy-server and passwd. If everything works fine, you will get the shell prompt. +- ViaSOCKS.java + This program will demonstrate the ssh session via SOCKS proxy. + $ CLASSPATH=.:../build javac ViaSOCKS.java + $ CLASSPATH=.:../build java ViaSOCKS + You will be asked username, hostname, proxy-server and passwd. + If everything works fine, you will get the shell prompt. + - PortForwardingR.java This program will demonstrate the port forwarding like option -R of ssh command; the given port on the remote host will be forwarded to @@ -158,3 +165,18 @@ or - Logger.java This program will demonstrate how to enable logging mechanism and get logging messages. + +- Subsystem.java + This program will demonstrate how to use the Subsystem channel. + +- Sudo.java + This program will demonstrate how to exec 'sudo' on the remote. + +- ScpToNoneCipher.java + This program will demonstrate how to enable none cipher. + +- JumpHosts.java + This program will demonstrate SSH through jump hosts. + +- OpenSSHConfig.java + This program will demonstrate how OpenSSH's config is supported. diff --git a/examples/ScpFrom.java b/examples/ScpFrom.java index baeea48..75ca5b7 100644 --- a/examples/ScpFrom.java +++ b/examples/ScpFrom.java @@ -1,4 +1,13 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program will demonstrate the file transfer from remote to local + * $ CLASSPATH=.:../build javac ScpFrom.java + * $ CLASSPATH=.:../build java ScpFrom user@remotehost:file1 file2 + * You will be asked passwd. + * If everything works fine, a file 'file1' on 'remotehost' will copied to + * local 'file1'. + * + */ import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; diff --git a/examples/ScpTo.java b/examples/ScpTo.java index 6a63c8b..87db9c8 100644 --- a/examples/ScpTo.java +++ b/examples/ScpTo.java @@ -1,4 +1,13 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program will demonstrate the file transfer from local to remote. + * $ CLASSPATH=.:../build javac ScpTo.java + * $ CLASSPATH=.:../build java ScpTo file1 user@remotehost:file2 + * You will be asked passwd. + * If everything works fine, a local file 'file1' will copied to + * 'file2' on 'remotehost'. + * + */ import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; @@ -48,7 +57,7 @@ public static void main(String[] arg){ File _lfile = new File(lfile); if(ptimestamp){ - command="T "+(_lfile.lastModified()/1000)+" 0"; + command="T"+(_lfile.lastModified()/1000)+" 0"; // The access time should be sent here, // but it is not accessible with JavaAPI ;-< command+=(" "+(_lfile.lastModified()/1000)+" 0\n"); diff --git a/examples/ScpToNoneCipher.java b/examples/ScpToNoneCipher.java index 80412da..209c4c3 100644 --- a/examples/ScpToNoneCipher.java +++ b/examples/ScpToNoneCipher.java @@ -1,4 +1,8 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program will demonstrate how to enable none cipher. + * + */ import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; diff --git a/examples/Sftp.java b/examples/Sftp.java index bf990d4..067e0c9 100644 --- a/examples/Sftp.java +++ b/examples/Sftp.java @@ -1,4 +1,15 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program will demonstrate the sftp protocol support. + * $ CLASSPATH=.:../build javac Sftp.java + * $ CLASSPATH=.:../build java Sftp + * You will be asked username, host and passwd. + * If everything works fine, you will get a prompt 'sftp>'. + * 'help' command will show available command. + * In current implementation, the destination path for 'get' and 'put' + * commands must be a file, not a directory. + * + */ import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; @@ -234,12 +245,14 @@ public static void main(String[] arg){ } continue; } - if(cmd.equals("ln") || cmd.equals("symlink") || cmd.equals("rename")){ + if(cmd.equals("ln") || cmd.equals("symlink") || + cmd.equals("rename") || cmd.equals("hardlink")){ if(cmds.size()!=3) continue; String p1=(String)cmds.elementAt(1); String p2=(String)cmds.elementAt(2); try{ - if(cmd.equals("rename")) c.rename(p1, p2); + if(cmd.equals("hardlink")){ c.hardlink(p1, p2); } + else if(cmd.equals("rename")) c.rename(p1, p2); else c.symlink(p1, p2); } catch(SftpException e){ @@ -247,6 +260,25 @@ public static void main(String[] arg){ } continue; } + if(cmd.equals("df")){ + if(cmds.size()>2) continue; + String p1 = cmds.size()==1 ? ".": (String)cmds.elementAt(1); + SftpStatVFS stat = c.statVFS(p1); + + long size = stat.getSize(); + long used = stat.getUsed(); + long avail = stat.getAvailForNonRoot(); + long root_avail = stat.getAvail(); + long capacity = stat.getCapacity(); + + System.out.println("Size: "+size); + System.out.println("Used: "+used); + System.out.println("Avail: "+avail); + System.out.println("(root): "+root_avail); + System.out.println("%Capacity: "+capacity); + + continue; + } if(cmd.equals("stat") || cmd.equals("lstat")){ if(cmds.size()!=2) continue; String p1=(String)cmds.elementAt(1); @@ -481,10 +513,13 @@ public void end(){ "chgrp grp path Change group of file 'path' to 'grp'\n"+ "chmod mode path Change permissions of file 'path' to 'mode'\n"+ "chown own path Change owner of file 'path' to 'own'\n"+ +"df [path] Display statistics for current directory or\n"+ +" filesystem containing 'path'\n"+ "help Display this help text\n"+ "get remote-path [local-path] Download file\n"+ "get-resume remote-path [local-path] Resume to download file.\n"+ "get-append remote-path [local-path] Append remote file to local file\n"+ +"hardlink oldpath newpath Hardlink remote file\n"+ "*lls [ls-options [path]] Display local directory listing\n"+ "ln oldpath newpath Symlink remote file\n"+ "*lmkdir path Create local directory\n"+ diff --git a/examples/Shell.java b/examples/Shell.java index 9c4e8dd..425cd59 100644 --- a/examples/Shell.java +++ b/examples/Shell.java @@ -1,4 +1,13 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/** + * This program enables you to connect to sshd server and get the shell prompt. + * $ CLASSPATH=.:../build javac Shell.java + * $ CLASSPATH=.:../build java Shell + * You will be asked username, hostname and passwd. + * If everything works fine, you will get the shell prompt. Output may + * be ugly because of lacks of terminal-emulation, but you can issue commands. + * + */ import com.jcraft.jsch.*; import java.awt.*; import javax.swing.*; @@ -25,12 +34,36 @@ public static void main(String[] arg){ Session session=jsch.getSession(user, host, 22); - //session.setPassword("your password"); + String passwd = JOptionPane.showInputDialog("Enter password"); + session.setPassword(passwd); + + UserInfo ui = new MyUserInfo(){ + public void showMessage(String message){ + JOptionPane.showMessageDialog(null, message); + } + public boolean promptYesNo(String message){ + Object[] options={ "yes", "no" }; + int foo=JOptionPane.showOptionDialog(null, + message, + "Warning", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, options, options[0]); + return foo==0; + } + + // If password is not given before the invocation of Session#connect(), + // implement also following methods, + // * UserInfo#getPassword(), + // * UserInfo#promptPassword(String message) and + // * UIKeyboardInteractive#promptKeyboardInteractive() + + }; - // username and password will be given via UserInfo interface. - UserInfo ui=new MyUserInfo(); session.setUserInfo(ui); + // It must not be recommended, but if you want to skip host-key check, + // invoke following, // session.setConfig("StrictHostKeyChecking", "no"); //session.connect(); @@ -71,97 +104,20 @@ public int read(byte[] b, int off, int len)throws IOException{ } } - public static class MyUserInfo implements UserInfo, UIKeyboardInteractive{ - public String getPassword(){ return passwd; } - public boolean promptYesNo(String str){ - Object[] options={ "yes", "no" }; - int foo=JOptionPane.showOptionDialog(null, - str, - "Warning", - JOptionPane.DEFAULT_OPTION, - JOptionPane.WARNING_MESSAGE, - null, options, options[0]); - return foo==0; - } - - String passwd; - JTextField passwordField=(JTextField)new JPasswordField(20); - + public static abstract class MyUserInfo + implements UserInfo, UIKeyboardInteractive{ + public String getPassword(){ return null; } + public boolean promptYesNo(String str){ return false; } public String getPassphrase(){ return null; } - public boolean promptPassphrase(String message){ return true; } - public boolean promptPassword(String message){ - Object[] ob={passwordField}; - int result=JOptionPane.showConfirmDialog(null, ob, message, - JOptionPane.OK_CANCEL_OPTION); - if(result==JOptionPane.OK_OPTION){ - passwd=passwordField.getText(); - return true; - } - else{ - return false; - } - } - public void showMessage(String message){ - JOptionPane.showMessageDialog(null, message); - } - final GridBagConstraints gbc = - new GridBagConstraints(0,0,1,1,1,1, - GridBagConstraints.NORTHWEST, - GridBagConstraints.NONE, - new Insets(0,0,0,0),0,0); - private Container panel; + public boolean promptPassphrase(String message){ return false; } + public boolean promptPassword(String message){ return false; } + public void showMessage(String message){ } public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo){ - panel = new JPanel(); - panel.setLayout(new GridBagLayout()); - - gbc.weightx = 1.0; - gbc.gridwidth = GridBagConstraints.REMAINDER; - gbc.gridx = 0; - panel.add(new JLabel(instruction), gbc); - gbc.gridy++; - - gbc.gridwidth = GridBagConstraints.RELATIVE; - - JTextField[] texts=new JTextField[prompt.length]; - for(int i=0; i0){ + host=arg[0]; + } + else{ + host=JOptionPane.showInputDialog("Enter username@hostname", + System.getProperty("user.name")+ + "@localhost"); + } + String user=host.substring(0, host.indexOf('@')); + host=host.substring(host.indexOf('@')+1); + + Session session=jsch.getSession(user, host, 22); + + UserInfo ui=new MyUserInfo(); + session.setUserInfo(ui); + session.connect(); + + String command=JOptionPane.showInputDialog("Enter command, execed with sudo", + "printenv SUDO_USER"); + + String sudo_pass=null; + { + JTextField passwordField=(JTextField)new JPasswordField(8); + Object[] ob={passwordField}; + int result= + JOptionPane.showConfirmDialog(null, + ob, + "Enter password for sudo", + JOptionPane.OK_CANCEL_OPTION); + if(result!=JOptionPane.OK_OPTION){ + System.exit(-1); + } + sudo_pass=passwordField.getText(); + } + + Channel channel=session.openChannel("exec"); + + // man sudo + // -S The -S (stdin) option causes sudo to read the password from the + // standard input instead of the terminal device. + // -p The -p (prompt) option allows you to override the default + // password prompt and use a custom one. + ((ChannelExec)channel).setCommand("sudo -S -p '' "+command); + + + InputStream in=channel.getInputStream(); + OutputStream out=channel.getOutputStream(); + ((ChannelExec)channel).setErrStream(System.err); + + channel.connect(); + + out.write((sudo_pass+"\n").getBytes()); + out.flush(); + + byte[] tmp=new byte[1024]; + while(true){ + while(in.available()>0){ + int i=in.read(tmp, 0, 1024); + if(i<0)break; + System.out.print(new String(tmp, 0, i)); + } + if(channel.isClosed()){ + System.out.println("exit-status: "+channel.getExitStatus()); + break; + } + try{Thread.sleep(1000);}catch(Exception ee){} + } + channel.disconnect(); + session.disconnect(); + } + catch(Exception e){ + System.out.println(e); + } + } + + public static class MyUserInfo implements UserInfo, UIKeyboardInteractive{ + public String getPassword(){ return passwd; } + public boolean promptYesNo(String str){ + Object[] options={ "yes", "no" }; + int foo=JOptionPane.showOptionDialog(null, + str, + "Warning", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, options, options[0]); + return foo==0; + } + + String passwd; + JTextField passwordField=(JTextField)new JPasswordField(20); + + public String getPassphrase(){ return null; } + public boolean promptPassphrase(String message){ return true; } + public boolean promptPassword(String message){ + Object[] ob={passwordField}; + int result= + JOptionPane.showConfirmDialog(null, ob, message, + JOptionPane.OK_CANCEL_OPTION); + if(result==JOptionPane.OK_OPTION){ + passwd=passwordField.getText(); + return true; + } + else{ + return false; + } + } + public void showMessage(String message){ + JOptionPane.showMessageDialog(null, message); + } + final GridBagConstraints gbc = + new GridBagConstraints(0,0,1,1,1,1, + GridBagConstraints.NORTHWEST, + GridBagConstraints.NONE, + new Insets(0,0,0,0),0,0); + private Container panel; + public String[] promptKeyboardInteractive(String destination, + String name, + String instruction, + String[] prompt, + boolean[] echo){ + panel = new JPanel(); + panel.setLayout(new GridBagLayout()); + + gbc.weightx = 1.0; + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.gridx = 0; + panel.add(new JLabel(instruction), gbc); + gbc.gridy++; + + gbc.gridwidth = GridBagConstraints.RELATIVE; + + JTextField[] texts=new JTextField[prompt.length]; + for(int i=0; i + 4.0.0 + com.jcraft + jsch + jar + 0.1.53 + JSch + http://www.jcraft.com/jsch/ + JSch is a pure Java implementation of SSH2 + + JCraft,Inc. + http://www.jcraft.com/ + + + scm:git:http://git.jcraft.com/jsch.git + scm:git:http://git.jcraft.com/jsch.git + http://git.jcraft.com/jsch.git + + + + ymnk + Atsuhiko Yamanaka + ymnk at jcraft D0t com + http://github.com/ymnk + JCraft,Inc. + http://www.jcraft.com/ + + architect + developer + + +9 + + + + + Revised BSD + http://www.jcraft.com/jsch/LICENSE.txt + + + + + com.jcraft + jzlib + 1.0.7 + true + + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + + org.apache.maven.wagon + wagon-ssh-external + 1.0-alpha-5 + + + + + + org.sonatype.oss + oss-parent + 6 + + diff --git a/src/com/jcraft/jsch/IdentityFile.java b/src/com/jcraft/jsch/IdentityFile.java deleted file mode 100644 index 3543602..0000000 --- a/src/com/jcraft/jsch/IdentityFile.java +++ /dev/null @@ -1,914 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ -/* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package com.jcraft.jsch; - -import java.io.*; - -class IdentityFile implements Identity{ - String identity; - byte[] key; - byte[] iv; - private JSch jsch; - private HASH hash; - private byte[] encoded_data; - - private Cipher cipher; - - // DSA - private byte[] P_array; - private byte[] Q_array; - private byte[] G_array; - private byte[] pub_array; - private byte[] prv_array; - - // RSA - private byte[] n_array; // modulus - private byte[] e_array; // public exponent - private byte[] d_array; // private exponent - -// private String algname="ssh-dss"; - private String algname="ssh-rsa"; - - private static final int ERROR=0; - private static final int RSA=1; - private static final int DSS=2; - private static final int UNKNOWN=3; - - private static final int OPENSSH=0; - private static final int FSECURE=1; - private static final int PUTTY=2; - - private int type=ERROR; - private int keytype=OPENSSH; - - private byte[] publickeyblob=null; - - private boolean encrypted=true; - - static IdentityFile newInstance(String prvfile, String pubfile, JSch jsch) throws JSchException{ - byte[] prvkey=null; - byte[] pubkey=null; - - File file=null; - FileInputStream fis=null; - try{ - file=new File(prvfile); - fis=new FileInputStream(prvfile); - prvkey=new byte[(int)(file.length())]; - int len=0; - while(true){ - int i=fis.read(prvkey, len, prvkey.length-len); - if(i<=0) - break; - len+=i; - } - fis.close(); - } - catch(Exception e){ - try{ if(fis!=null) fis.close();} - catch(Exception ee){} - if(e instanceof Throwable) - throw new JSchException(e.toString(), (Throwable)e); - throw new JSchException(e.toString()); - } - - String _pubfile=pubfile; - if(pubfile==null){ - _pubfile=prvfile+".pub"; - } - - try{ - file=new File(_pubfile); - fis = new FileInputStream(_pubfile); - pubkey=new byte[(int)(file.length())]; - int len=0; - while(true){ - int i=fis.read(pubkey, len, pubkey.length-len); - if(i<=0) - break; - len+=i; - } - fis.close(); - } - catch(Exception e){ - try{ if(fis!=null) fis.close();} - catch(Exception ee){} - if(pubfile!=null){ - // The pubfile is explicitry given, but not accessible. - if(e instanceof Throwable) - throw new JSchException(e.toString(), (Throwable)e); - throw new JSchException(e.toString()); - } - } - return newInstance(prvfile, prvkey, pubkey, jsch); - } - - static IdentityFile newInstance(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{ - try{ - return new IdentityFile(name, prvkey, pubkey, jsch); - } - finally{ - Util.bzero(prvkey); - } - } - - private IdentityFile(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{ - this.identity=name; - this.jsch=jsch; - try{ - Class c; - c=Class.forName((String)jsch.getConfig("3des-cbc")); - cipher=(Cipher)(c.newInstance()); - key=new byte[cipher.getBlockSize()]; // 24 - iv=new byte[cipher.getIVSize()]; // 8 - c=Class.forName((String)jsch.getConfig("md5")); - hash=(HASH)(c.newInstance()); - hash.init(); - - byte[] buf=prvkey; - int len=buf.length; - - int i=0; - - while(i4 && // FSecure - encoded_data[0]==(byte)0x3f && - encoded_data[1]==(byte)0x6f && - encoded_data[2]==(byte)0xf9 && - encoded_data[3]==(byte)0xeb){ - - Buffer _buf=new Buffer(encoded_data); - _buf.getInt(); // 0x3f6ff9be - _buf.getInt(); - byte[]_type=_buf.getString(); - //System.err.println("type: "+new String(_type)); - byte[] _cipher=_buf.getString(); - String cipher=Util.byte2str(_cipher); - //System.err.println("cipher: "+cipher); - if(cipher.equals("3des-cbc")){ - _buf.getInt(); - byte[] foo=new byte[encoded_data.length-_buf.getOffSet()]; - _buf.getByte(foo); - encoded_data=foo; - encrypted=true; - throw new JSchException("unknown privatekey format: "+identity); - } - else if(cipher.equals("none")){ - _buf.getInt(); - //_buf.getInt(); - - encrypted=false; - - byte[] foo=new byte[encoded_data.length-_buf.getOffSet()]; - _buf.getByte(foo); - encoded_data=foo; - } - - } - - if(pubkey==null){ - return; - } - - buf=pubkey; - len=buf.length; - - if(buf.length>4 && // FSecure's public key - buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){ - i=0; - do{i++;}while(len>i && buf[i]!=0x0a); - if(len<=i) return; - while(i8){ - if(publickeyblob[8]=='d'){ - type=DSS; - } - else if(publickeyblob[8]=='r'){ - type=RSA; - } - } - } - else{ - if(buf[0]!='s'|| buf[1]!='s'|| buf[2]!='h'|| buf[3]!='-') return; - i=0; - while(i=len) return; - start=i; - while(i 8 ? 8: iv.length); - tmp=hash.digest(); - System.arraycopy(tmp, 0, hn, index, tmp.length); - index+=tmp.length; - } - System.arraycopy(hn, 0, key, 0, key.length); - } - else if(keytype==FSECURE){ - for(int index=0; index+hsize<=hn.length;){ - if(tmp!=null){ hash.update(tmp, 0, tmp.length); } - hash.update(passphrase, 0, passphrase.length); - tmp=hash.digest(); - System.arraycopy(tmp, 0, hn, index, tmp.length); - index+=tmp.length; - } - System.arraycopy(hn, 0, key, 0, key.length); - } - Util.bzero(passphrase); - } - if(decrypt()){ - encrypted=false; - return true; - } - P_array=Q_array=G_array=pub_array=prv_array=null; - return false; - } - catch(Exception e){ - if(e instanceof JSchException) throw (JSchException)e; - if(e instanceof Throwable) - throw new JSchException(e.toString(), (Throwable)e); - throw new JSchException(e.toString()); - } - } - - public byte[] getPublicKeyBlob(){ - if(publickeyblob!=null) return publickeyblob; - if(type==RSA) return getPublicKeyBlob_rsa(); - return getPublicKeyBlob_dss(); - } - - byte[] getPublicKeyBlob_rsa(){ - if(e_array==null) return null; - Buffer buf=new Buffer("ssh-rsa".length()+4+ - e_array.length+4+ - n_array.length+4); - buf.putString(Util.str2byte("ssh-rsa")); - buf.putString(e_array); - buf.putString(n_array); - return buf.buffer; - } - - byte[] getPublicKeyBlob_dss(){ - if(P_array==null) return null; - Buffer buf=new Buffer("ssh-dss".length()+4+ - P_array.length+4+ - Q_array.length+4+ - G_array.length+4+ - pub_array.length+4); - buf.putString(Util.str2byte("ssh-dss")); - buf.putString(P_array); - buf.putString(Q_array); - buf.putString(G_array); - buf.putString(pub_array); - return buf.buffer; - } - - public byte[] getSignature(byte[] data){ - if(type==RSA) return getSignature_rsa(data); - return getSignature_dss(data); - } - - byte[] getSignature_rsa(byte[] data){ - try{ - Class c=Class.forName((String)jsch.getConfig("signature.rsa")); - SignatureRSA rsa=(SignatureRSA)(c.newInstance()); - - rsa.init(); - rsa.setPrvKey(d_array, n_array); - - rsa.update(data); - byte[] sig = rsa.sign(); - Buffer buf=new Buffer("ssh-rsa".length()+4+ - sig.length+4); - buf.putString(Util.str2byte("ssh-rsa")); - buf.putString(sig); - return buf.buffer; - } - catch(Exception e){ - } - return null; - } - - byte[] getSignature_dss(byte[] data){ -/* - byte[] foo; - int i; - System.err.print("P "); - foo=P_array; - for(i=0; i0){ length=(length<<8)+(plain[index++]&0xff); } - } - - if(plain[index]!=0x02)return false; - index++; // INTEGER - length=plain[index++]&0xff; - if((length&0x80)!=0){ - int foo=length&0x7f; length=0; - while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } - } - index+=length; - -//System.err.println("int: len="+length); -//System.err.print(Integer.toHexString(plain[index-1]&0xff)+":"); -//System.err.println(""); - - index++; - length=plain[index++]&0xff; - if((length&0x80)!=0){ - int foo=length&0x7f; length=0; - while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } - } - n_array=new byte[length]; - System.arraycopy(plain, index, n_array, 0, length); - index+=length; -/* -System.err.println("int: N len="+length); -for(int i=0; i0){ length=(length<<8)+(plain[index++]&0xff); } - } - e_array=new byte[length]; - System.arraycopy(plain, index, e_array, 0, length); - index+=length; -/* -System.err.println("int: E len="+length); -for(int i=0; i0){ length=(length<<8)+(plain[index++]&0xff); } - } - d_array=new byte[length]; - System.arraycopy(plain, index, d_array, 0, length); - index+=length; -/* -System.err.println("int: D len="+length); -for(int i=0; i0){ length=(length<<8)+(plain[index++]&0xff); } - } - p_array=new byte[length]; - System.arraycopy(plain, index, p_array, 0, length); - index+=length; -/* -System.err.println("int: P len="+length); -for(int i=0; i0){ length=(length<<8)+(plain[index++]&0xff); } - } - q_array=new byte[length]; - System.arraycopy(plain, index, q_array, 0, length); - index+=length; -/* -System.err.println("int: q len="+length); -for(int i=0; i0){ length=(length<<8)+(plain[index++]&0xff); } - } - dmp1_array=new byte[length]; - System.arraycopy(plain, index, dmp1_array, 0, length); - index+=length; -/* -System.err.println("int: dmp1 len="+length); -for(int i=0; i0){ length=(length<<8)+(plain[index++]&0xff); } - } - dmq1_array=new byte[length]; - System.arraycopy(plain, index, dmq1_array, 0, length); - index+=length; -/* -System.err.println("int: dmq1 len="+length); -for(int i=0; i0){ length=(length<<8)+(plain[index++]&0xff); } - } - iqmp_array=new byte[length]; - System.arraycopy(plain, index, iqmp_array, 0, length); - index+=length; -/* -System.err.println("int: iqmp len="+length); -for(int i=0; i0){ length=(length<<8)+(plain[index++]&0xff); } - } - if(plain[index]!=0x02)return false; - index++; // INTEGER - length=plain[index++]&0xff; - if((length&0x80)!=0){ - int foo=length&0x7f; length=0; - while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } - } - index+=length; - - index++; - length=plain[index++]&0xff; - if((length&0x80)!=0){ - int foo=length&0x7f; length=0; - while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } - } - P_array=new byte[length]; - System.arraycopy(plain, index, P_array, 0, length); - index+=length; - - index++; - length=plain[index++]&0xff; - if((length&0x80)!=0){ - int foo=length&0x7f; length=0; - while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } - } - Q_array=new byte[length]; - System.arraycopy(plain, index, Q_array, 0, length); - index+=length; - - index++; - length=plain[index++]&0xff; - if((length&0x80)!=0){ - int foo=length&0x7f; length=0; - while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } - } - G_array=new byte[length]; - System.arraycopy(plain, index, G_array, 0, length); - index+=length; - - index++; - length=plain[index++]&0xff; - if((length&0x80)!=0){ - int foo=length&0x7f; length=0; - while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } - } - pub_array=new byte[length]; - System.arraycopy(plain, index, pub_array, 0, length); - index+=length; - - index++; - length=plain[index++]&0xff; - if((length&0x80)!=0){ - int foo=length&0x7f; length=0; - while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } - } - prv_array=new byte[length]; - System.arraycopy(plain, index, prv_array, 0, length); - index+=length; - } - catch(Exception e){ - //System.err.println(e); - //e.printStackTrace(); - return false; - } - return true; - } - - public boolean isEncrypted(){ - return encrypted; - } - - public String getName(){ - return identity; - } - - private byte a2b(byte c){ - if('0'<=c&&c<='9') return (byte)(c-'0'); - if('a'<=c&&c<='z') return (byte)(c-'a'+10); - return (byte)(c-'A'+10); - } - - public boolean equals(Object o){ - if(!(o instanceof IdentityFile)) return super.equals(o); - IdentityFile foo=(IdentityFile)o; - return getName().equals(foo.getName()); - } - - public void clear(){ - Util.bzero(encoded_data); - Util.bzero(prv_array); - Util.bzero(d_array); - Util.bzero(key); - Util.bzero(iv); - } - - public void finalize (){ - clear(); - } -} diff --git a/src/com/jcraft/jsch/JSch.java b/src/com/jcraft/jsch/JSch.java deleted file mode 100644 index 5c80a89..0000000 --- a/src/com/jcraft/jsch/JSch.java +++ /dev/null @@ -1,298 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ -/* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package com.jcraft.jsch; - -import java.io.InputStream; -import java.util.Vector; - -public class JSch{ - static java.util.Hashtable config=new java.util.Hashtable(); - static{ -// config.put("kex", "diffie-hellman-group-exchange-sha1"); - config.put("kex", "diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1"); - config.put("server_host_key", "ssh-rsa,ssh-dss"); -// config.put("server_host_key", "ssh-dss,ssh-rsa"); - - config.put("cipher.s2c", - "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc"); - config.put("cipher.c2s", - "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc"); - - config.put("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96"); - config.put("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96"); - config.put("compression.s2c", "none"); - // config.put("compression.s2c", "zlib@openssh.com,zlib,none"); - config.put("compression.c2s", "none"); - // config.put("compression.c2s", "zlib@openssh.com,zlib,none"); - - config.put("lang.s2c", ""); - config.put("lang.c2s", ""); - - config.put("compression_level", "6"); - - config.put("diffie-hellman-group-exchange-sha1", - "com.jcraft.jsch.DHGEX"); - config.put("diffie-hellman-group1-sha1", - "com.jcraft.jsch.DHG1"); - - config.put("dh", "com.jcraft.jsch.jce.DH"); - config.put("3des-cbc", "com.jcraft.jsch.jce.TripleDESCBC"); - config.put("blowfish-cbc", "com.jcraft.jsch.jce.BlowfishCBC"); - config.put("hmac-sha1", "com.jcraft.jsch.jce.HMACSHA1"); - config.put("hmac-sha1-96", "com.jcraft.jsch.jce.HMACSHA196"); - config.put("hmac-md5", "com.jcraft.jsch.jce.HMACMD5"); - config.put("hmac-md5-96", "com.jcraft.jsch.jce.HMACMD596"); - config.put("sha-1", "com.jcraft.jsch.jce.SHA1"); - config.put("md5", "com.jcraft.jsch.jce.MD5"); - config.put("signature.dss", "com.jcraft.jsch.jce.SignatureDSA"); - config.put("signature.rsa", "com.jcraft.jsch.jce.SignatureRSA"); - config.put("keypairgen.dsa", "com.jcraft.jsch.jce.KeyPairGenDSA"); - config.put("keypairgen.rsa", "com.jcraft.jsch.jce.KeyPairGenRSA"); - config.put("random", "com.jcraft.jsch.jce.Random"); - - config.put("none", "com.jcraft.jsch.CipherNone"); - - config.put("aes128-cbc", "com.jcraft.jsch.jce.AES128CBC"); - config.put("aes192-cbc", "com.jcraft.jsch.jce.AES192CBC"); - config.put("aes256-cbc", "com.jcraft.jsch.jce.AES256CBC"); - - config.put("aes128-ctr", "com.jcraft.jsch.jce.AES128CTR"); - config.put("aes192-ctr", "com.jcraft.jsch.jce.AES192CTR"); - config.put("aes256-ctr", "com.jcraft.jsch.jce.AES256CTR"); - config.put("3des-ctr", "com.jcraft.jsch.jce.TripleDESCTR"); - config.put("arcfour", "com.jcraft.jsch.jce.ARCFOUR"); - config.put("arcfour128", "com.jcraft.jsch.jce.ARCFOUR128"); - config.put("arcfour256", "com.jcraft.jsch.jce.ARCFOUR256"); - - config.put("userauth.none", "com.jcraft.jsch.UserAuthNone"); - config.put("userauth.password", "com.jcraft.jsch.UserAuthPassword"); - config.put("userauth.keyboard-interactive", "com.jcraft.jsch.UserAuthKeyboardInteractive"); - config.put("userauth.publickey", "com.jcraft.jsch.UserAuthPublicKey"); - config.put("userauth.gssapi-with-mic", "com.jcraft.jsch.UserAuthGSSAPIWithMIC"); - config.put("gssapi-with-mic.krb5", "com.jcraft.jsch.jgss.GSSContextKrb5"); - - config.put("zlib", "com.jcraft.jsch.jcraft.Compression"); - config.put("zlib@openssh.com", "com.jcraft.jsch.jcraft.Compression"); - - config.put("StrictHostKeyChecking", "ask"); - config.put("HashKnownHosts", "no"); - //config.put("HashKnownHosts", "yes"); - config.put("PreferredAuthentications", "gssapi-with-mic,publickey,keyboard-interactive,password"); - - config.put("CheckCiphers", "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256"); - } - java.util.Vector pool=new java.util.Vector(); - java.util.Vector identities=new java.util.Vector(); - private HostKeyRepository known_hosts=null; - - private static final Logger DEVNULL=new Logger(){ - public boolean isEnabled(int level){return false;} - public void log(int level, String message){} - }; - static Logger logger=DEVNULL; - - public JSch(){ - - try{ - String osname=(String)(System.getProperties().get("os.name")); - if(osname!=null && osname.equals("Mac OS X")){ - config.put("hmac-sha1", "com.jcraft.jsch.jcraft.HMACSHA1"); - config.put("hmac-md5", "com.jcraft.jsch.jcraft.HMACMD5"); - config.put("hmac-md5-96", "com.jcraft.jsch.jcraft.HMACMD596"); - config.put("hmac-sha1-96", "com.jcraft.jsch.jcraft.HMACSHA196"); - } - } - catch(Exception e){ - } - - } - - public Session getSession(String username, String host) throws JSchException { return getSession(username, host, 22); } - public Session getSession(String username, String host, int port) throws JSchException { - if(username==null){ - throw new JSchException("username must not be null."); - } - if(host==null){ - throw new JSchException("host must not be null."); - } - Session s=new Session(this); - s.setUserName(username); - s.setHost(host); - s.setPort(port); - //pool.addElement(s); - return s; - } - - protected void addSession(Session session){ - synchronized(pool){ - pool.addElement(session); - } - } - - protected boolean removeSession(Session session){ - synchronized(pool){ - return pool.remove(session); - } - } - public void setHostKeyRepository(HostKeyRepository hkrepo){ - known_hosts=hkrepo; - } - - public void setKnownHosts(String filename) throws JSchException{ - if(known_hosts==null) known_hosts=new KnownHosts(this); - if(known_hosts instanceof KnownHosts){ - synchronized(known_hosts){ - ((KnownHosts)known_hosts).setKnownHosts(filename); - } - } - } - - public void setKnownHosts(InputStream stream) throws JSchException{ - if(known_hosts==null) known_hosts=new KnownHosts(this); - if(known_hosts instanceof KnownHosts){ - synchronized(known_hosts){ - ((KnownHosts)known_hosts).setKnownHosts(stream); - } - } - } - - public HostKeyRepository getHostKeyRepository(){ - if(known_hosts==null) known_hosts=new KnownHosts(this); - return known_hosts; - } - - public void addIdentity(String prvkey) throws JSchException{ - addIdentity(prvkey, (byte[])null); - } - - public void addIdentity(String prvkey, String passphrase) throws JSchException{ - byte[] _passphrase=null; - if(passphrase!=null){ - _passphrase=Util.str2byte(passphrase); - } - addIdentity(prvkey, _passphrase); - if(_passphrase!=null) - Util.bzero(_passphrase); - } - - public void addIdentity(String prvkey, byte[] passphrase) throws JSchException{ - Identity identity=IdentityFile.newInstance(prvkey, null, this); - addIdentity(identity, passphrase); - } - public void addIdentity(String prvkey, String pubkey, byte[] passphrase) throws JSchException{ - Identity identity=IdentityFile.newInstance(prvkey, pubkey, this); - addIdentity(identity, passphrase); - } - - public void addIdentity(String name, byte[]prvkey, byte[]pubkey, byte[] passphrase) throws JSchException{ - Identity identity=IdentityFile.newInstance(name, prvkey, pubkey, this); - addIdentity(identity, passphrase); - } - - public void addIdentity(Identity identity, byte[] passphrase) throws JSchException{ - if(passphrase!=null){ - try{ - byte[] goo=new byte[passphrase.length]; - System.arraycopy(passphrase, 0, goo, 0, passphrase.length); - passphrase=goo; - identity.setPassphrase(passphrase); - } - finally{ - Util.bzero(passphrase); - } - } - synchronized(identities){ - if(!identities.contains(identity)){ - identities.addElement(identity); - } - } - } - - public void removeIdentity(String name) throws JSchException{ - synchronized(identities){ - for(int i=0; iclient"+ - " "+guess[PROPOSAL_ENC_ALGS_STOC]+ - " "+guess[PROPOSAL_MAC_ALGS_STOC]+ - " "+guess[PROPOSAL_COMP_ALGS_STOC]); - JSch.getLogger().log(Logger.INFO, - "kex: client->server"+ - " "+guess[PROPOSAL_ENC_ALGS_CTOS]+ - " "+guess[PROPOSAL_MAC_ALGS_CTOS]+ - " "+guess[PROPOSAL_COMP_ALGS_CTOS]); - } - -// for(int i=0; i>>4)&0x0f))); - out.write(b2a((byte)(iv[i]&0x0f))); - } - out.write(cr); - out.write(cr); - } - int i=0; - while(i0){ - len>>>=8; - i++; - } - return i; - } - - int writeLength(byte[] data, int index, int len){ - int i=countLength(len)-1; - if(i==0){ - data[index++]=(byte)len; - return index; - } - data[index++]=(byte)(0x80|i); - int j=index+i; - while(i>0){ - data[index+i-1]=(byte)(len&0xff); - len>>>=8; - i--; - } - return j; - } - - private Random genRandom(){ - if(random==null){ - try{ - Class c=Class.forName(jsch.getConfig("random")); - random=(Random)(c.newInstance()); - } - catch(Exception e){ System.err.println("connect: random "+e); } - } - return random; - } - - private HASH genHash(){ - try{ - Class c=Class.forName(jsch.getConfig("md5")); - hash=(HASH)(c.newInstance()); - hash.init(); - } - catch(Exception e){ - } - return hash; - } - private Cipher genCipher(){ - try{ - Class c; - c=Class.forName(jsch.getConfig("3des-cbc")); - cipher=(Cipher)(c.newInstance()); - } - catch(Exception e){ - } - return cipher; - } - - /* - hash is MD5 - h(0) <- hash(passphrase, iv); - h(n) <- hash(h(n-1), passphrase, iv); - key <- (h(0),...,h(n))[0,..,key.length]; - */ - synchronized byte[] genKey(byte[] passphrase, byte[] iv){ - if(cipher==null) cipher=genCipher(); - if(hash==null) hash=genHash(); - - byte[] key=new byte[cipher.getBlockSize()]; - int hsize=hash.getBlockSize(); - byte[] hn=new byte[key.length/hsize*hsize+ - (key.length%hsize==0?0:hsize)]; - try{ - byte[] tmp=null; - if(vendor==VENDOR_OPENSSH){ - for(int index=0; index+hsize<=hn.length;){ - if(tmp!=null){ hash.update(tmp, 0, tmp.length); } - hash.update(passphrase, 0, passphrase.length); - hash.update(iv, 0, iv.length); - tmp=hash.digest(); - System.arraycopy(tmp, 0, hn, index, tmp.length); - index+=tmp.length; - } - System.arraycopy(hn, 0, key, 0, key.length); - } - else if(vendor==VENDOR_FSECURE){ - for(int index=0; index+hsize<=hn.length;){ - if(tmp!=null){ hash.update(tmp, 0, tmp.length); } - hash.update(passphrase, 0, passphrase.length); - tmp=hash.digest(); - System.arraycopy(tmp, 0, hn, index, tmp.length); - index+=tmp.length; - } - System.arraycopy(hn, 0, key, 0, key.length); - } - } - catch(Exception e){ - System.err.println(e); - } - return key; - } - - public void setPassphrase(String passphrase){ - if(passphrase==null || passphrase.length()==0){ - setPassphrase((byte[])null); - } - else{ - setPassphrase(Util.str2byte(passphrase)); - } - } - public void setPassphrase(byte[] passphrase){ - if(passphrase!=null && passphrase.length==0) - passphrase=null; - this.passphrase=passphrase; - } - - private boolean encrypted=false; - private byte[] data=null; - private byte[] iv=null; - private byte[] publickeyblob=null; - - public boolean isEncrypted(){ return encrypted; } - public boolean decrypt(String _passphrase){ - if(_passphrase==null || _passphrase.length()==0){ - return !encrypted; - } - return decrypt(Util.str2byte(_passphrase)); - } - public boolean decrypt(byte[] _passphrase){ - if(!encrypted){ - return true; - } - if(_passphrase==null){ - return !encrypted; - } - byte[] bar=new byte[_passphrase.length]; - System.arraycopy(_passphrase, 0, bar, 0, bar.length); - _passphrase=bar; - byte[] foo=decrypt(data, _passphrase, iv); - Util.bzero(_passphrase); - if(parse(foo)){ - encrypted=false; - } - return !encrypted; - } - - public static KeyPair load(JSch jsch, String prvkey) throws JSchException{ - String pubkey=prvkey+".pub"; - if(!new File(pubkey).exists()){ - pubkey=null; - } - return load(jsch, prvkey, pubkey); - } - public static KeyPair load(JSch jsch, String prvkey, String pubkey) throws JSchException{ - - byte[] iv=new byte[8]; // 8 - boolean encrypted=true; - byte[] data=null; - - byte[] publickeyblob=null; - - int type=ERROR; - int vendor=VENDOR_OPENSSH; - - try{ - File file=new File(prvkey); - FileInputStream fis=new FileInputStream(prvkey); - byte[] buf=new byte[(int)(file.length())]; - int len=0; - while(true){ - int i=fis.read(buf, len, buf.length-len); - if(i<=0) - break; - len+=i; - } - fis.close(); - - int i=0; - - while(i4 && // FSecure - data[0]==(byte)0x3f && - data[1]==(byte)0x6f && - data[2]==(byte)0xf9 && - data[3]==(byte)0xeb){ - - Buffer _buf=new Buffer(data); - _buf.getInt(); // 0x3f6ff9be - _buf.getInt(); - byte[]_type=_buf.getString(); - //System.err.println("type: "+new String(_type)); - byte[] _cipher=_buf.getString(); - String cipher=Util.byte2str(_cipher); - //System.err.println("cipher: "+cipher); - if(cipher.equals("3des-cbc")){ - _buf.getInt(); - byte[] foo=new byte[data.length-_buf.getOffSet()]; - _buf.getByte(foo); - data=foo; - encrypted=true; - throw new JSchException("unknown privatekey format: "+prvkey); - } - else if(cipher.equals("none")){ - _buf.getInt(); - _buf.getInt(); - - encrypted=false; - - byte[] foo=new byte[data.length-_buf.getOffSet()]; - _buf.getByte(foo); - data=foo; - } - } - - if(pubkey!=null){ - try{ - file=new File(pubkey); - fis=new FileInputStream(pubkey); - buf=new byte[(int)(file.length())]; - len=0; - while(true){ - i=fis.read(buf, len, buf.length-len); - if(i<=0) - break; - len+=i; - } - fis.close(); - - if(buf.length>4 && // FSecure's public key - buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){ - - boolean valid=true; - i=0; - do{i++;}while(buf.length>i && buf[i]!=0x0a); - if(buf.length<=i) {valid=false;} - - while(valid){ - if(buf[i]==0x0a){ - boolean inheader=false; - for(int j=i+1; jBSIZE){ - byte[] tmp=new byte[BSIZE]; - System.arraycopy(key, 0, tmp, 0, BSIZE); - key=tmp; - } - - SecretKeySpec skey=new SecretKeySpec(key, "HmacMD5"); - mac=Mac.getInstance("HmacMD5"); - mac.init(skey); - } - - private final byte[] tmp=new byte[4]; - public void update(int i){ - tmp[0]=(byte)(i>>>24); - tmp[1]=(byte)(i>>>16); - tmp[2]=(byte)(i>>>8); - tmp[3]=(byte)i; - update(tmp, 0, 4); - } - public void update(byte foo[], int s, int l){ - mac.update(foo, s, l); - } - public void doFinal(byte[] buf, int offset){ - try{ - mac.doFinal(buf, offset); - } - catch(ShortBufferException e){ - } - } - - public String getName(){ - return name; - } -} diff --git a/src/com/jcraft/jsch/jce/HMACMD596.java b/src/com/jcraft/jsch/jce/HMACMD596.java deleted file mode 100644 index 992b65c..0000000 --- a/src/com/jcraft/jsch/jce/HMACMD596.java +++ /dev/null @@ -1,77 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ -/* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package com.jcraft.jsch.jce; - -import com.jcraft.jsch.MAC; -import javax.crypto.*; -import javax.crypto.spec.*; - -public class HMACMD596 implements MAC{ - private static final String name="hmac-md5-96"; - private static final int bsize=12; - private Mac mac; - public int getBlockSize(){return bsize;}; - public void init(byte[] key) throws Exception{ - if(key.length>16){ - byte[] tmp=new byte[16]; - System.arraycopy(key, 0, tmp, 0, 16); - key=tmp; - } - SecretKeySpec skey=new SecretKeySpec(key, "HmacMD5"); - mac=Mac.getInstance("HmacMD5"); - mac.init(skey); - } - private final byte[] tmp=new byte[4]; - public void update(int i){ - tmp[0]=(byte)(i>>>24); - tmp[1]=(byte)(i>>>16); - tmp[2]=(byte)(i>>>8); - tmp[3]=(byte)i; - update(tmp, 0, 4); - } - - public void update(byte foo[], int s, int l){ - mac.update(foo, s, l); - } - - private final byte[] _buf16=new byte[16]; - public void doFinal(byte[] buf, int offset){ - try{ - mac.doFinal(_buf16, 0); - } - catch(ShortBufferException e){ - } - System.arraycopy(_buf16, 0, buf, offset, 12); - } - - public String getName(){ - return name; - } -} diff --git a/src/com/jcraft/jsch/jce/HMACSHA196.java b/src/com/jcraft/jsch/jce/HMACSHA196.java deleted file mode 100644 index 0cc5731..0000000 --- a/src/com/jcraft/jsch/jce/HMACSHA196.java +++ /dev/null @@ -1,76 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ -/* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package com.jcraft.jsch.jce; - -import com.jcraft.jsch.MAC; -import javax.crypto.*; -import javax.crypto.spec.*; - -public class HMACSHA196 implements MAC{ - private static final String name="hmac-sha1-96"; - private static final int bsize=12; - private Mac mac; - public int getBlockSize(){return bsize;}; - public void init(byte[] key) throws Exception{ - if(key.length>20){ - byte[] tmp=new byte[20]; - System.arraycopy(key, 0, tmp, 0, 20); - key=tmp; - } - SecretKeySpec skey=new SecretKeySpec(key, "HmacSHA1"); - mac=Mac.getInstance("HmacSHA1"); - mac.init(skey); - } - private final byte[] tmp=new byte[4]; - public void update(int i){ - tmp[0]=(byte)(i>>>24); - tmp[1]=(byte)(i>>>16); - tmp[2]=(byte)(i>>>8); - tmp[3]=(byte)i; - update(tmp, 0, 4); - } - public void update(byte foo[], int s, int l){ - mac.update(foo, s, l); - } - - private final byte[] _buf20=new byte[20]; - public void doFinal(byte[] buf, int offset){ - try{ - mac.doFinal(_buf20, 0); - } - catch(ShortBufferException e){ - } - System.arraycopy(_buf20, 0, buf, offset, 12); - } - - public String getName(){ - return name; - } -} diff --git a/src/com/jcraft/jsch/Buffer.java b/src/main/java/com/jcraft/jsch/Buffer.java similarity index 85% rename from src/com/jcraft/jsch/Buffer.java rename to src/main/java/com/jcraft/jsch/Buffer.java index ff221e8..4db2e89 100644 --- a/src/com/jcraft/jsch/Buffer.java +++ b/src/main/java/com/jcraft/jsch/Buffer.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -213,13 +213,56 @@ byte getCommand(){ } void checkFreeSize(int n){ - if(buffer.length0) + notifyAll(); } int getRecipient(){ return recipient; @@ -145,58 +146,9 @@ public void connect() throws JSchException{ } public void connect(int connectTimeout) throws JSchException{ - Session _session=getSession(); - if(!_session.isConnected()){ - throw new JSchException("session is down"); - } this.connectTimeout=connectTimeout; try{ - Buffer buf=new Buffer(100); - Packet packet=new Packet(buf); - // send - // byte SSH_MSG_CHANNEL_OPEN(90) - // string channel type // - // uint32 sender channel // 0 - // uint32 initial window size // 0x100000(65536) - // uint32 maxmum packet size // 0x4000(16384) - packet.reset(); - buf.putByte((byte)90); - buf.putString(this.type); - buf.putInt(this.id); - buf.putInt(this.lwsize); - buf.putInt(this.lmpsize); - _session.write(packet); - int retry=1000; - long start=System.currentTimeMillis(); - long timeout=connectTimeout; - while(this.getRecipient()==-1 && - _session.isConnected() && - retry>0){ - if(timeout>0L){ - if((System.currentTimeMillis()-start)>timeout){ - retry=0; - continue; - } - } - try{Thread.sleep(50);}catch(Exception ee){} - retry--; - } - if(!_session.isConnected()){ - throw new JSchException("session is down"); - } - if(retry==0){ - throw new JSchException("channel is not opened."); - } - - /* - * At the failure in opening the channel on the sshd, - * 'SSH_MSG_CHANNEL_OPEN_FAILURE' will be sent from sshd and it will - * be processed in Session#run(). - */ - if(this.isClosed()){ - throw new JSchException("channel is not opened."); - } - connected=true; + sendChannelOpen(); start(); } catch(Exception e){ @@ -240,29 +192,38 @@ public void setExtOutputStream(OutputStream out, boolean dontclose){ io.setExtOutputStream(out, dontclose); } public InputStream getInputStream() throws IOException { - PipedInputStream in= + int max_input_buffer_size = 32*1024; + try { + max_input_buffer_size = + Integer.parseInt(getSession().getConfig("max_input_buffer_size")); + } + catch(Exception e){} + PipedInputStream in = new MyPipedInputStream( - 32*1024 // this value should be customizable. + 32*1024, // this value should be customizable. + max_input_buffer_size ); - io.setOutputStream(new PassiveOutputStream(in), false); + boolean resizable = 32*10240){ int _l=l; - if(l>_bufl-(14+dataLen)-32-20){ - _l=_bufl-(14+dataLen)-32-20; + if(l>_bufl-(14+dataLen)-Session.buffer_margin){ + _l=_bufl-(14+dataLen)-Session.buffer_margin; } if(_l<=0){ @@ -330,7 +291,10 @@ public void flush() throws java.io.IOException{ try{ int foo=dataLen; dataLen=0; - getSession().write(packet, channel, foo); + synchronized(channel){ + if(!channel.close) + getSession().write(packet, channel, foo); + } } catch(Exception e){ close(); @@ -362,22 +326,101 @@ public void close() throws java.io.IOException{ } class MyPipedInputStream extends PipedInputStream{ + private int BUFFER_SIZE = 1024; + private int max_buffer_size = BUFFER_SIZE; MyPipedInputStream() throws IOException{ super(); } MyPipedInputStream(int size) throws IOException{ super(); buffer=new byte[size]; + BUFFER_SIZE = size; + max_buffer_size = size; + } + MyPipedInputStream(int size, int max_buffer_size) throws IOException{ + this(size); + this.max_buffer_size = max_buffer_size; } MyPipedInputStream(PipedOutputStream out) throws IOException{ super(out); } MyPipedInputStream(PipedOutputStream out, int size) throws IOException{ super(out); buffer=new byte[size]; + BUFFER_SIZE=size; + } + + /* + * TODO: We should have our own Piped[I/O]Stream implementation. + * Before accepting data, JDK's PipedInputStream will check the existence of + * reader thread, and if it is not alive, the stream will be closed. + * That behavior may cause the problem if multiple threads make access to it. + */ + public synchronized void updateReadSide() throws IOException { + if(available() != 0){ // not empty + return; + } + in = 0; + out = 0; + buffer[in++] = 0; + read(); + } + + private int freeSpace(){ + int size = 0; + if(out < in) { + size = buffer.length-in; + } + else if(in < out){ + if(in == -1) size = buffer.length; + else size = out - in; + } + return size; + } + synchronized void checkSpace(int len) throws IOException { + int size = freeSpace(); + if(size max_buffer_size){ + foo = max_buffer_size; + } + if((foo - datasize) < len) return; + + byte[] tmp = new byte[foo]; + if(out < in) { + System.arraycopy(buffer, 0, tmp, 0, buffer.length); + } + else if(in < out){ + if(in == -1) { + } + else { + System.arraycopy(buffer, 0, tmp, 0, in); + System.arraycopy(buffer, out, + tmp, tmp.length-(buffer.length-out), + (buffer.length-out)); + out = tmp.length-(buffer.length-out); + } + } + else if(in == out){ + System.arraycopy(buffer, 0, tmp, 0, buffer.length); + in=buffer.length; + } + buffer=tmp; + } + else if(buffer.length == size && size > BUFFER_SIZE) { + int i = size/2; + if(i0) notifyAll(); @@ -413,12 +456,15 @@ void eof(){ if(eof_local)return; eof_local=true; + int i = getRecipient(); + if(i == -1) return; + try{ Buffer buf=new Buffer(100); Packet packet=new Packet(buf); packet.reset(); buf.putByte((byte)Session.SSH_MSG_CHANNEL_EOF); - buf.putInt(getRecipient()); + buf.putInt(i); synchronized(this){ if(!close) getSession().write(packet); @@ -474,12 +520,15 @@ void close(){ close=true; eof_local=eof_remote=true; + int i = getRecipient(); + if(i == -1) return; + try{ Buffer buf=new Buffer(100); Packet packet=new Packet(buf); packet.reset(); buf.putByte((byte)Session.SSH_MSG_CHANNEL_CLOSE); - buf.putInt(getRecipient()); + buf.putInt(i); synchronized(this){ getSession().write(packet); } @@ -590,8 +639,25 @@ public void close() throws IOException{ } } class PassiveOutputStream extends PipedOutputStream{ - PassiveOutputStream(PipedInputStream in) throws IOException{ + private MyPipedInputStream _sink=null; + PassiveOutputStream(PipedInputStream in, + boolean resizable_buffer) throws IOException{ super(in); + if(resizable_buffer && (in instanceof MyPipedInputStream)) { + this._sink=(MyPipedInputStream)in; + } + } + public void write(int b) throws IOException { + if(_sink != null) { + _sink.checkSpace(1); + } + super.write(b); + } + public void write(byte[] b, int off, int len) throws IOException { + if(_sink != null) { + _sink.checkSpace(len); + } + super.write(b, off, len); } } @@ -638,4 +704,69 @@ protected void sendOpenFailure(int reasoncode){ catch(Exception e){ } } + + protected Packet genChannelOpenPacket(){ + Buffer buf=new Buffer(100); + Packet packet=new Packet(buf); + // byte SSH_MSG_CHANNEL_OPEN(90) + // string channel type // + // uint32 sender channel // 0 + // uint32 initial window size // 0x100000(65536) + // uint32 maxmum packet size // 0x4000(16384) + packet.reset(); + buf.putByte((byte)90); + buf.putString(this.type); + buf.putInt(this.id); + buf.putInt(this.lwsize); + buf.putInt(this.lmpsize); + return packet; + } + + protected void sendChannelOpen() throws Exception { + Session _session=getSession(); + if(!_session.isConnected()){ + throw new JSchException("session is down"); + } + + Packet packet = genChannelOpenPacket(); + _session.write(packet); + + int retry=2000; + long start=System.currentTimeMillis(); + long timeout=connectTimeout; + if(timeout!=0L) retry = 1; + synchronized(this){ + while(this.getRecipient()==-1 && + _session.isConnected() && + retry>0){ + if(timeout>0L){ + if((System.currentTimeMillis()-start)>timeout){ + retry=0; + continue; + } + } + try{ + long t = timeout==0L ? 10L : timeout; + this.notifyme=1; + wait(t); + } + catch(java.lang.InterruptedException e){ + } + finally{ + this.notifyme=0; + } + retry--; + } + } + if(!_session.isConnected()){ + throw new JSchException("session is down"); + } + if(this.getRecipient()==-1){ // timeout + throw new JSchException("channel is not opened."); + } + if(this.open_confirmation==false){ // SSH_MSG_CHANNEL_OPEN_FAILURE + throw new JSchException("channel is not opened."); + } + connected=true; + } } diff --git a/src/com/jcraft/jsch/ChannelAgentForwarding.java b/src/main/java/com/jcraft/jsch/ChannelAgentForwarding.java similarity index 70% rename from src/com/jcraft/jsch/ChannelAgentForwarding.java rename to src/main/java/com/jcraft/jsch/ChannelAgentForwarding.java index 9fb8cb0..d93a005 100644 --- a/src/com/jcraft/jsch/ChannelAgentForwarding.java +++ b/src/main/java/com/jcraft/jsch/ChannelAgentForwarding.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -37,14 +37,24 @@ class ChannelAgentForwarding extends Channel{ static private final int LOCAL_WINDOW_SIZE_MAX=0x20000; static private final int LOCAL_MAXIMUM_PACKET_SIZE=0x4000; - private final int SSH2_AGENTC_REQUEST_IDENTITIES=11; - private final int SSH2_AGENT_IDENTITIES_ANSWER=12; - private final int SSH2_AGENTC_SIGN_REQUEST=13; - private final int SSH2_AGENT_SIGN_RESPONSE=14; - private final int SSH2_AGENTC_ADD_IDENTITY=17; - private final int SSH2_AGENTC_REMOVE_IDENTITY=18; - private final int SSH2_AGENTC_REMOVE_ALL_IDENTITIES=19; - private final int SSH2_AGENT_FAILURE=30; + private final byte SSH_AGENTC_REQUEST_RSA_IDENTITIES = 1; + private final byte SSH_AGENT_RSA_IDENTITIES_ANSWER = 2; + private final byte SSH_AGENTC_RSA_CHALLENGE = 3; + private final byte SSH_AGENT_RSA_RESPONSE = 4; + private final byte SSH_AGENT_FAILURE = 5; + private final byte SSH_AGENT_SUCCESS = 6; + private final byte SSH_AGENTC_ADD_RSA_IDENTITY = 7; + private final byte SSH_AGENTC_REMOVE_RSA_IDENTITY = 8; + private final byte SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES = 9; + + private final byte SSH2_AGENTC_REQUEST_IDENTITIES=11; + private final byte SSH2_AGENT_IDENTITIES_ANSWER=12; + private final byte SSH2_AGENTC_SIGN_REQUEST=13; + private final byte SSH2_AGENT_SIGN_RESPONSE=14; + private final byte SSH2_AGENTC_ADD_IDENTITY=17; + private final byte SSH2_AGENTC_REMOVE_IDENTITY=18; + private final byte SSH2_AGENTC_REMOVE_ALL_IDENTITIES=19; + private final byte SSH2_AGENT_FAILURE=30; boolean init=true; @@ -111,12 +121,14 @@ void write(byte[] foo, int s, int l) throws java.io.IOException { throw new java.io.IOException(e.toString()); } - Vector identities=_session.jsch.identities; + IdentityRepository irepo = _session.getIdentityRepository(); UserInfo userinfo=_session.getUserInfo(); + mbuf.reset(); + if(typ==SSH2_AGENTC_REQUEST_IDENTITIES){ - mbuf.reset(); - mbuf.putByte((byte)SSH2_AGENT_IDENTITIES_ANSWER); + mbuf.putByte(SSH2_AGENT_IDENTITIES_ANSWER); + Vector identities = irepo.getIdentities(); synchronized(identities){ int count=0; for(int i=0; i0 && - !eof_remote){ - //Thread.sleep(500); - Thread.sleep(50); - retry--; - } - } - catch(Exception ee){ - } - if(!_session.isConnected()){ - throw new JSchException("session is down"); - } - if(retry==0 || this.eof_remote){ - throw new JSchException("channel is not opened."); - } - /* - if(this.eof_remote){ // failed to open - disconnect(); - return; - } - */ - - connected=true; if(io.in!=null){ thread=new Thread(this); @@ -121,6 +70,9 @@ public void connect() throws JSchException{ } thread.start(); } + else { + sendChannelOpen(); + } } catch(Exception e){ io.close(); @@ -134,12 +86,14 @@ public void connect() throws JSchException{ public void run(){ - Buffer buf=new Buffer(rmpsize); - Packet packet=new Packet(buf); - int i=0; - try{ + sendChannelOpen(); + + Buffer buf=new Buffer(rmpsize); + Packet packet=new Packet(buf); Session _session=getSession(); + int i=0; + while(isConnected() && thread!=null && io!=null && @@ -147,26 +101,36 @@ public void run(){ i=io.in.read(buf.buffer, 14, buf.buffer.length-14 - -32 -20 // padding and mac + -Session.buffer_margin ); - if(i<=0){ eof(); break; } - if(close)break; packet.reset(); buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA); buf.putInt(recipient); buf.putInt(i); buf.skip(i); - _session.write(packet, this, i); + synchronized(this){ + if(close) + break; + _session.write(packet, this, i); + } } } catch(Exception e){ + // Whenever an exception is thrown by sendChannelOpen(), + // 'connected' is false. + if(!connected){ + connected=true; + } + disconnect(); + return; } + + eof(); disconnect(); - //System.err.println("connect end"); } public void setInputStream(InputStream in){ @@ -180,4 +144,27 @@ public void setOutputStream(OutputStream out){ public void setPort(int port){this.port=port;} public void setOrgIPAddress(String foo){this.originator_IP_address=foo;} public void setOrgPort(int foo){this.originator_port=foo;} + + protected Packet genChannelOpenPacket(){ + Buffer buf = new Buffer(50 + // 6 + 4*8 + 12 + host.length() + originator_IP_address.length() + + Session.buffer_margin); + Packet packet = new Packet(buf); + // byte SSH_MSG_CHANNEL_OPEN(90) + // string channel type // + // uint32 sender channel // 0 + // uint32 initial window size // 0x100000(65536) + // uint32 maxmum packet size // 0x4000(16384) + packet.reset(); + buf.putByte((byte)90); + buf.putString(this.type); + buf.putInt(id); + buf.putInt(lwsize); + buf.putInt(lmpsize); + buf.putString(Util.str2byte(host)); + buf.putInt(port); + buf.putString(Util.str2byte(originator_IP_address)); + buf.putInt(originator_port); + return packet; + } } diff --git a/src/com/jcraft/jsch/ChannelExec.java b/src/main/java/com/jcraft/jsch/ChannelExec.java similarity index 97% rename from src/com/jcraft/jsch/ChannelExec.java rename to src/main/java/com/jcraft/jsch/ChannelExec.java index df8869c..8f6be68 100644 --- a/src/com/jcraft/jsch/ChannelExec.java +++ b/src/main/java/com/jcraft/jsch/ChannelExec.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/ChannelForwardedTCPIP.java b/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java similarity index 62% rename from src/com/jcraft/jsch/ChannelForwardedTCPIP.java rename to src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java index faafa17..32dcb5d 100644 --- a/src/com/jcraft/jsch/ChannelForwardedTCPIP.java +++ b/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -31,10 +31,11 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import java.net.*; import java.io.*; +import java.util.Vector; public class ChannelForwardedTCPIP extends Channel{ - static java.util.Vector pool=new java.util.Vector(); + private static Vector pool = new Vector(); static private final int LOCAL_WINDOW_SIZE_MAX=0x20000; //static private final int LOCAL_WINDOW_SIZE_MAX=0x100000; @@ -42,12 +43,9 @@ public class ChannelForwardedTCPIP extends Channel{ static private final int TIMEOUT=10*1000; - SocketFactory factory=null; private Socket socket=null; private ForwardedTCPIPDaemon daemon=null; - String target; - int lport; - int rport; + private Config config = null; ChannelForwardedTCPIP(){ super(); @@ -60,8 +58,9 @@ public class ChannelForwardedTCPIP extends Channel{ public void run(){ try{ - if(lport==-1){ - Class c=Class.forName(target); + if(config instanceof ConfigDaemon){ + ConfigDaemon _config = (ConfigDaemon)config; + Class c=Class.forName(_config.target); daemon=(ForwardedTCPIPDaemon)c.newInstance(); PipedOutputStream out=new PipedOutputStream(); @@ -70,15 +69,14 @@ public void run(){ ), false); daemon.setChannel(this, getInputStream(), out); - Object[] foo=getPort(getSession(), rport); - daemon.setArg((Object[])foo[3]); - + daemon.setArg(_config.arg); new Thread(daemon).start(); } else{ - socket=(factory==null) ? - Util.createSocket(target, lport, TIMEOUT) : - factory.createSocket(target, lport); + ConfigLHost _config = (ConfigLHost)config; + socket=(_config.factory==null) ? + Util.createSocket(_config.target, _config.lport, TIMEOUT) : + _config.factory.createSocket(_config.target, _config.lport); socket.setTcpNoDelay(true); io.setInputStream(socket.getInputStream()); io.setOutputStream(socket.getOutputStream()); @@ -97,25 +95,29 @@ public void run(){ Packet packet=new Packet(buf); int i=0; try{ + Session _session = getSession(); while(thread!=null && io!=null && io.in!=null){ i=io.in.read(buf.buffer, 14, buf.buffer.length-14 - -32 -20 // padding and mac + -Session.buffer_margin ); if(i<=0){ eof(); break; } packet.reset(); - if(close)break; buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA); buf.putInt(recipient); buf.putInt(i); buf.skip(i); - getSession().write(packet, this, i); + synchronized(this){ + if(close) + break; + _session.write(packet, this, i); + } } } catch(Exception e){ @@ -150,32 +152,29 @@ void getData(Buffer buf){ // session has been already down. } - synchronized(pool){ - for(int i=0; i=6){ - this.factory=((SocketFactory)foo[5]); - } - break; - } - if(target==null){ - //System.err.println("??"); + this.config = getPort(_session, Util.byte2str(addr), port); + if(this.config == null) + this.config = getPort(_session, null, port); + + if(this.config == null){ + if(JSch.getLogger().isEnabled(Logger.ERROR)){ + JSch.getLogger().log(Logger.ERROR, + "ChannelForwardedTCPIP: "+Util.byte2str(addr)+":"+port+" is not registered."); } } } - static Object[] getPort(Session session, int rport){ + private static Config getPort(Session session, String address_to_bind, int rport){ synchronized(pool){ for(int i=0; iname and value are needed to be passed - * to the remote in your faivorite encoding,use - * {@link #setEnv(byte[], byte[])}. + * to the remote in your favorite encoding, + * use {@link #setEnv(byte[], byte[])}. + * Refer to RFC4254 6.4 Environment Variable Passing. * * @param name A name for environment variable. * @param value A value for environment variable. - * @see RFC4254 6.4 Environment Variable Passing */ public void setEnv(String name, String value){ setEnv(Util.str2byte(name), Util.str2byte(value)); @@ -99,11 +99,11 @@ public void setEnv(String name, String value){ /** * Set the environment variable. + * Refer to RFC4254 6.4 Environment Variable Passing. * * @param name A name of environment variable. * @param value A value of environment variable. * @see #setEnv(String, String) - * @see RFC4254 6.4 Environment Variable Passing */ public void setEnv(byte[] name, byte[] value){ synchronized(this){ @@ -119,9 +119,9 @@ private Hashtable getEnv(){ /** * Allocate a Pseudo-Terminal. + * Refer to RFC4254 6.2. Requesting a Pseudo-Terminal. * * @param enable - * @see RFC4254 6.2. Requesting a Pseudo-Terminal */ public void setPty(boolean enable){ pty=enable; @@ -138,12 +138,12 @@ public void setTerminalMode(byte[] terminal_mode){ /** * Change the window dimension interactively. - * + * Refer to RFC4254 6.7. Window Dimension Change Message. + * * @param col terminal width, columns * @param row terminal height, rows * @param wp terminal width, pixels * @param hp terminal height, pixels - * @see RFC4254 6.7. Window Dimension Change Message */ public void setPtySize(int col, int row, int wp, int hp){ setPtyType(this.ttype, col, row, wp, hp); @@ -245,7 +245,7 @@ public void run(){ i=io.in.read(buf.buffer, 14, buf.buffer.length-14 - -32 -20 // padding and mac + -Session.buffer_margin ); if(i==0)continue; if(i==-1){ diff --git a/src/com/jcraft/jsch/ChannelSftp.java b/src/main/java/com/jcraft/jsch/ChannelSftp.java similarity index 75% rename from src/com/jcraft/jsch/ChannelSftp.java rename to src/main/java/com/jcraft/jsch/ChannelSftp.java index b575f90..0711f9e 100644 --- a/src/com/jcraft/jsch/ChannelSftp.java +++ b/src/main/java/com/jcraft/jsch/ChannelSftp.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -35,6 +35,9 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING public class ChannelSftp extends ChannelSession{ + static private final int LOCAL_MAXIMUM_PACKET_SIZE=32*1024; + static private final int LOCAL_WINDOW_SIZE_MAX=(64*LOCAL_MAXIMUM_PACKET_SIZE); + private static final byte SSH_FXP_INIT= 1; private static final byte SSH_FXP_VERSION= 2; private static final byte SSH_FXP_OPEN= 3; @@ -131,8 +134,13 @@ is not supported for the server (it may be generated locally by private boolean interactive=false; private int seq=1; private int[] ackid=new int[1]; + private Buffer buf; - private Packet packet=new Packet(buf); + private Packet packet; + + // The followings will be used in file uploading. + private Buffer obuf; + private Packet opacket; private int client_version=3; private int server_version=3; @@ -141,6 +149,11 @@ is not supported for the server (it may be generated locally by private java.util.Hashtable extensions=null; private InputStream io_in=null; + private boolean extension_posix_rename = false; + private boolean extension_statvfs = false; + // private boolean extension_fstatvfs = false; + private boolean extension_hardlink = false; + /* 10. Changes from previous protocol versions The SSH File Transfer Protocol has changed over time, before it's @@ -169,6 +182,40 @@ is not supported for the server (it may be generated locally by private String fEncoding=UTF8; private boolean fEncoding_is_utf8=true; + private RequestQueue rq = new RequestQueue(16); + + /** + * Specify how many requests may be sent at any one time. + * Increasing this value may slightly improve file transfer speed but will + * increase memory usage. The default is 16 requests. + * + * @param bulk_requests how many requests may be outstanding at any one time. + */ + public void setBulkRequests(int bulk_requests) throws JSchException { + if(bulk_requests>0) + rq = new RequestQueue(bulk_requests); + else + throw new JSchException("setBulkRequests: "+ + bulk_requests+" must be greater than 0."); + } + + /** + * This method will return the value how many requests may be + * sent at any one time. + * + * @return how many requests may be sent at any one time. + */ + public int getBulkRequests(){ + return rq.size(); + } + + public ChannelSftp(){ + super(); + setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX); + setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX); + setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE); + } + void init(){ } @@ -177,7 +224,7 @@ public void start() throws JSchException{ PipedOutputStream pos=new PipedOutputStream(); io.setOutputStream(pos); - PipedInputStream pis=new MyPipedInputStream(pos, 32*1024); + PipedInputStream pis=new MyPipedInputStream(pos, rmpsize); io.setInputStream(pis); io_in=io.in; @@ -196,8 +243,12 @@ public void start() throws JSchException{ System.err.println("rwsize: "+rwsize); */ - buf=new Buffer(rmpsize); + buf=new Buffer(lmpsize); packet=new Packet(buf); + + obuf=new Buffer(rmpsize); + opacket=new Packet(obuf); + int i=0; int length; int type; @@ -217,8 +268,8 @@ public void start() throws JSchException{ type=header.type; // 2 -> SSH_FXP_VERSION server_version=header.rid; //System.err.println("SFTP protocol server-version="+server_version); + extensions=new java.util.Hashtable(); if(length>0){ - extensions=new java.util.Hashtable(); // extension data fill(buf, length); byte[] extension_name=null; @@ -233,6 +284,28 @@ public void start() throws JSchException{ } } + if(extensions.get("posix-rename@openssh.com")!=null && + extensions.get("posix-rename@openssh.com").equals("1")){ + extension_posix_rename = true; + } + + if(extensions.get("statvfs@openssh.com")!=null && + extensions.get("statvfs@openssh.com").equals("2")){ + extension_statvfs = true; + } + + /* + if(extensions.get("fstatvfs@openssh.com")!=null && + extensions.get("fstatvfs@openssh.com").equals("2")){ + extension_fstatvfs = true; + } + */ + + if(extensions.get("hardlink@openssh.com")!=null && + extensions.get("hardlink@openssh.com").equals("1")){ + extension_hardlink = true; + } + lcwd=new File(".").getCanonicalPath(); } catch(Exception e){ @@ -261,8 +334,9 @@ public void lcd(String path) throws SftpException{ public void cd(String path) throws SftpException{ try{ - path=remoteAbsolutePath(path); + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); path=isUnique(path); byte[] str=_realpath(path); @@ -297,12 +371,25 @@ public void put(String src, String dst, SftpProgressMonitor monitor) throws SftpException{ put(src, dst, monitor, OVERWRITE); } + + /** + * Sends data from src file to dst file. + * The mode should be OVERWRITE, + * RESUME or APPEND. + * + * @param src source file + * @param dst destination file + * @param monitor progress monitor + * @param mode how data should be added to dst + */ public void put(String src, String dst, SftpProgressMonitor monitor, int mode) throws SftpException{ - src=localAbsolutePath(src); - dst=remoteAbsolutePath(dst); try{ + ((MyPipedInputStream)io_in).updateReadSide(); + + src=localAbsolutePath(src); + dst=remoteAbsolutePath(dst); Vector v=glob_remote(dst); int vsize=v.size(); @@ -411,9 +498,22 @@ public void put(InputStream src, String dst, SftpProgressMonitor monitor) throws SftpException{ put(src, dst, monitor, OVERWRITE); } + + /** + * Sends data from the input stream src to dst file. + * The mode should be OVERWRITE, + * RESUME or APPEND. + * + * @param src input stream + * @param dst destination file + * @param monitor progress monitor + * @param mode how data should be added to dst + */ public void put(InputStream src, String dst, SftpProgressMonitor monitor, int mode) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + dst=remoteAbsolutePath(dst); Vector v=glob_remote(dst); @@ -431,14 +531,22 @@ public void put(InputStream src, String dst, dst=(String)(v.elementAt(0)); } - if(isRemoteDir(dst)){ - throw new SftpException(SSH_FX_FAILURE, dst+" is a directory"); + if(monitor!=null){ + monitor.init(SftpProgressMonitor.PUT, + "-", dst, + SftpProgressMonitor.UNKNOWN_SIZE); } _put(src, dst, monitor, mode); } catch(Exception e){ - if(e instanceof SftpException) throw (SftpException)e; + if(e instanceof SftpException) { + if(((SftpException)e).id == SSH_FX_FAILURE && + isRemoteDir(dst)) { + throw new SftpException(SSH_FX_FAILURE, dst+" is a directory"); + } + throw (SftpException)e; + } if(e instanceof Throwable) throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e); throw new SftpException(SSH_FX_FAILURE, e.toString()); @@ -446,8 +554,10 @@ public void put(InputStream src, String dst, } public void _put(InputStream src, String dst, - SftpProgressMonitor monitor, int mode) throws SftpException{ + SftpProgressMonitor monitor, int mode) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + byte[] dstb=Util.str2byte(dst, fEncoding); long skip=0; if(mode==RESUME || mode==APPEND){ @@ -488,10 +598,9 @@ public void _put(InputStream src, String dst, boolean dontcopy=true; - if(!dontcopy){ - data=new byte[buf.buffer.length - -(5+13+21+handle.length - +32 +20 // padding and mac + if(!dontcopy){ // This case will not work anymore. + data=new byte[obuf.buffer.length + -(5+13+21+handle.length+Session.buffer_margin ) ]; } @@ -502,23 +611,26 @@ public void _put(InputStream src, String dst, } int startid=seq; - int _ackid=seq; int ackcount=0; + int _s=0; + int _datalen=0; + + if(!dontcopy){ // This case will not work anymore. + _datalen=data.length; + } + else{ + data=obuf.buffer; + _s=5+13+21+handle.length; + _datalen=obuf.buffer.length-_s-Session.buffer_margin; + } + + int bulk_requests = rq.size(); + while(true){ int nread=0; - int s=0; - int datalen=0; int count=0; - - if(!dontcopy){ - datalen=data.length-s; - } - else{ - data=buf.buffer; - s=5+13+21+handle.length; - datalen=buf.buffer.length -s - -32 -20; // padding and mac - } + int s=_s; + int datalen=_datalen; do{ nread=src.read(data, s, datalen); @@ -531,20 +643,18 @@ public void _put(InputStream src, String dst, while(datalen>0 && nread>0); if(count<=0)break; - int _i=count; - while(_i>0){ - _i-=sendWRITE(handle, offset, data, 0, _i); + int foo=count; + while(foo>0){ if((seq-1)==startid || - io_in.available()>=1024){ - while(io_in.available()>0){ + ((seq-startid)-ackcount)>=bulk_requests){ + while(((seq-startid)-ackcount)>=bulk_requests){ if(checkStatus(ackid, header)){ - _ackid=ackid[0]; + int _ackid = ackid[0]; if(startid>_ackid || _ackid>seq-1){ if(_ackid==seq){ System.err.println("ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid); } else{ - //throw new SftpException(SSH_FX_FAILURE, "ack error:"); throw new SftpException(SSH_FX_FAILURE, "ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid); } } @@ -555,6 +665,16 @@ public void _put(InputStream src, String dst, } } } + if(dontcopy){ + foo-=sendWRITE(handle, offset, data, 0, foo); + if(data!=obuf.buffer){ + data=obuf.buffer; + _datalen=obuf.buffer.length-_s-Session.buffer_margin; + } + } + else { + foo-=sendWRITE(handle, offset, data, _s, foo); + } } offset+=count; if(monitor!=null && !monitor.count(count)){ @@ -588,10 +708,23 @@ public OutputStream put(String dst, final int mode) throws SftpException{ public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode) throws SftpException{ return put(dst, monitor, mode, 0); } + + /** + * Sends data from the output stream to dst file. + * The mode should be OVERWRITE, + * RESUME or APPEND. + * + * @param dst destination file + * @param monitor progress monitor + * @param mode how data should be added to dst + * @param offset data will be added at offset + * @return output stream, which accepts data to be transferred. + */ public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset) throws SftpException{ - dst=remoteAbsolutePath(dst); try{ + ((MyPipedInputStream)io_in).updateReadSide(); + dst=remoteAbsolutePath(dst); dst=isUnique(dst); if(isRemoteDir(dst)){ @@ -611,6 +744,12 @@ public OutputStream put(String dst, final SftpProgressMonitor monitor, final int } } + if(monitor!=null){ + monitor.init(SftpProgressMonitor.PUT, + "-", dst, + SftpProgressMonitor.UNKNOWN_SIZE); + } + if(mode==OVERWRITE){ sendOPENW(dstb); } else{ sendOPENA(dstb); } @@ -756,12 +895,14 @@ public void get(String src, String dst, SftpProgressMonitor monitor, int mode) throws SftpException{ // System.out.println("get: "+src+" "+dst); - src=remoteAbsolutePath(src); - dst=localAbsolutePath(dst); - boolean _dstExist = false; String _dst=null; try{ + ((MyPipedInputStream)io_in).updateReadSide(); + + src=remoteAbsolutePath(src); + dst=localAbsolutePath(dst); + Vector v=glob_remote(src); int vsize=v.size(); if(vsize==0){ @@ -796,6 +937,15 @@ else if(vsize>1){ if(i==-1) dstsb.append(_src); else dstsb.append(_src.substring(i + 1)); _dst=dstsb.toString(); + if(_dst.indexOf("..")!=-1){ + String dstc = (new java.io.File(dst)).getCanonicalPath(); + String _dstc = (new java.io.File(_dst)).getCanonicalPath(); + if(!(_dstc.length()>dstc.length() && + _dstc.substring(0, dstc.length()+1).equals(dstc+file_separator))){ + throw new SftpException(SSH_FX_FAILURE, + "writing to an unexpected file "+_src); + } + } dstsb.delete(dst.length(), _dst.length()); } else{ @@ -822,7 +972,7 @@ else if(vsize>1){ } } - FileOutputStream fos=null; + FileOutputStream fos=null; _dstExist = _dstFile.exists(); try{ if(mode==OVERWRITE){ @@ -865,8 +1015,9 @@ public void get(String src, OutputStream dst, SftpProgressMonitor monitor, int mode, long skip) throws SftpException{ //System.err.println("get: "+src+", "+dst); try{ - src=remoteAbsolutePath(src); + ((MyPipedInputStream)io_in).updateReadSide(); + src=remoteAbsolutePath(src); src=isUnique(src); if(monitor!=null){ @@ -917,18 +1068,36 @@ private void _get(String src, OutputStream dst, offset+=skip; } - int request_len=0; + int request_max=1; + rq.init(); + long request_offset=offset; + + int request_len = buf.buffer.length-13; + if(server_version==0){ request_len=1024; } + loop: while(true){ - request_len=buf.buffer.length-13; - if(server_version==0){ request_len=1024; } - sendREAD(handle, offset, request_len); + while(rq.count() < request_max){ + sendREAD(handle, request_offset, request_len, rq); + request_offset += request_len; + } header=header(buf, header); length=header.length; type=header.type; + RequestQueue.Request rr = null; + try{ + rr = rq.get(header.rid); + } + catch(RequestQueue.OutOfOrderException e){ + request_offset = e.offset; + skip(header.length); + rq.cancel(header, buf); + continue; + } + if(type==SSH_FXP_STATUS){ fill(buf, length); int i=buf.getInt(); @@ -944,19 +1113,31 @@ private void _get(String src, OutputStream dst, buf.rewind(); fill(buf.buffer, 0, 4); length-=4; - int i=buf.getInt(); // length of data - int foo=i; + int length_of_data = buf.getInt(); // length of data + + /** + Since sftp protocol version 6, "end-of-file" has been defined, + + byte SSH_FXP_DATA + uint32 request-id + string data + bool end-of-file [optional] + + but some sftpd server will send such a field in the sftp protocol 3 ;-( + */ + int optional_data = length - length_of_data; + int foo = length_of_data; while(foo>0){ int bar=foo; if(bar>buf.buffer.length){ bar=buf.buffer.length; } - i=io_in.read(buf.buffer, 0, bar); - if(i<0){ + int data_len = io_in.read(buf.buffer, 0, bar); + if(data_len<0){ break loop; } - int data_len=i; + dst.write(buf.buffer, 0, data_len); offset+=data_len; @@ -964,12 +1145,9 @@ private void _get(String src, OutputStream dst, if(monitor!=null){ if(!monitor.count(data_len)){ - while(foo>0){ - i=io_in.read(buf.buffer, - 0, - (buf.buffer.length0){ + skip(optional_data); } break loop; } @@ -977,10 +1155,27 @@ private void _get(String src, OutputStream dst, } //System.err.println("length: "+length); // length should be 0 + + if(optional_data>0){ + skip(optional_data); + } + + if(length_of_data=rrq.length) tail -= rrq.length; + rrq[tail].id=id; + rrq[tail].offset=offset; + rrq[tail].length=length; + count++; + } + + Request get(int id) throws OutOfOrderException, SftpException { + count -= 1; + int i = head; + head++; + if(head==rrq.length) head=0; + if(rrq[i].id != id){ + long offset = getOffset(); + boolean find = false; + for(int j = 0; jrrq[i].offset) + result=rrq[i].offset; + } + + return result; + } + } + public InputStream get(String src) throws SftpException{ return get(src, null, 0L); } @@ -1011,8 +1306,11 @@ public InputStream get(String src, final SftpProgressMonitor monitor, final int return get(src, monitor, 0L); } public InputStream get(String src, final SftpProgressMonitor monitor, final long skip) throws SftpException{ - src=remoteAbsolutePath(src); + try{ + ((MyPipedInputStream)io_in).updateReadSide(); + + src=remoteAbsolutePath(src); src=isUnique(src); byte[] srcb=Util.str2byte(src, fEncoding); @@ -1041,6 +1339,8 @@ public InputStream get(String src, final SftpProgressMonitor monitor, final long final byte[] handle=buf.getString(); // handle + rq.init(); + java.io.InputStream in=new java.io.InputStream(){ long offset=skip; boolean closed=false; @@ -1048,6 +1348,8 @@ public InputStream get(String src, final SftpProgressMonitor monitor, final long byte[] _data=new byte[1]; byte[] rest_byte=new byte[1024]; Header header=new Header(); + int request_max=1; + long request_offset=offset; public int read() throws java.io.IOException{ if(closed)return -1; @@ -1096,14 +1398,41 @@ public int read(byte[] d, int s, int len) throws java.io.IOException{ len=1024; } - try{sendREAD(handle, offset, len);} - catch(Exception e){ throw new IOException("error"); } + if(rq.count()==0 + || true // working around slow transfer speed for + // some sftp servers including Titan FTP. + ) { + int request_len = buf.buffer.length-13; + if(server_version==0){ request_len=1024; } + + while(rq.count() < request_max){ + try{ + sendREAD(handle, request_offset, request_len, rq); + } + catch(Exception e){ throw new IOException("error"); } + request_offset += request_len; + } + } header=header(buf, header); rest_length=header.length; int type=header.type; int id=header.rid; + RequestQueue.Request rr = null; + try{ + rr = rq.get(header.rid); + } + catch(RequestQueue.OutOfOrderException e){ + request_offset = e.offset; + skip(header.length); + rq.cancel(header, buf); + return 0; + } + catch(SftpException e){ + throw new IOException("error: "+e.toString()); + } + if(type!=SSH_FXP_STATUS && type!=SSH_FXP_DATA){ throw new IOException("error"); } @@ -1118,29 +1447,43 @@ public int read(byte[] d, int s, int len) throws java.io.IOException{ //throwStatusError(buf, i); throw new IOException("error"); } + buf.rewind(); fill(buf.buffer, 0, 4); - int i=buf.getInt(); rest_length-=4; - - offset+=rest_length; - int foo=i; + int length_of_data = buf.getInt(); rest_length-=4; + + /** + Since sftp protocol version 6, "end-of-file" has been defined, + + byte SSH_FXP_DATA + uint32 request-id + string data + bool end-of-file [optional] + + but some sftpd server will send such a field in the sftp protocol 3 ;-( + */ + int optional_data = rest_length - length_of_data; + + offset += length_of_data; + int foo = length_of_data; if(foo>0){ - int bar=rest_length; + int bar=foo; if(bar>len){ bar=len; } - i=io_in.read(d, s, bar); + int i=io_in.read(d, s, bar); if(i<0){ return -1; } - rest_length-=i; + foo-=i; + rest_length=foo; - if(rest_length>0){ - if(rest_byte.length0){ + if(rest_byte.length0){ j=io_in.read(rest_byte, _s, _len); @@ -1150,6 +1493,25 @@ public int read(byte[] d, int s, int len) throws java.io.IOException{ } } + if(optional_data>0){ + io_in.skip(optional_data); + } + + if(length_of_datapath. + * Each files and directories will be passed to + * LsEntrySelector#select(LsEntry) method, and if that method + * returns LsEntrySelector#BREAK, the operation will be + * canceled immediately. + * + * @see ChannelSftp.LsEntrySelector + * @since 0.1.47 + */ + public void ls(String path, LsEntrySelector selector) throws SftpException{ //System.out.println("ls: "+path); try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); byte[] pattern=null; java.util.Vector v=new java.util.Vector(); @@ -1246,9 +1633,11 @@ public java.util.Vector ls(String path) throws SftpException{ throwStatusError(buf, i); } + int cancel = LsEntrySelector.CONTINUE; byte[] handle=buf.getString(); // handle - while(true){ + while(cancel==LsEntrySelector.CONTINUE){ + sendREADDIR(handle); header=header(buf, header); @@ -1290,6 +1679,11 @@ public java.util.Vector ls(String path) throws SftpException{ } SftpATTRS attrs=SftpATTRS.getATTR(buf); + if(cancel==LsEntrySelector.BREAK){ + count--; + continue; + } + boolean find=false; String f=null; if(pattern==null){ @@ -1320,7 +1714,8 @@ else if(!pattern_has_wildcard){ else{ l=Util.byte2str(longname, fEncoding); } - v.addElement(new LsEntry(f, l, attrs)); + + cancel = selector.select(new LsEntry(f, l, attrs)); } count--; @@ -1345,7 +1740,6 @@ else if(!pattern_has_wildcard){ } */ - return v; } catch(Exception e){ if(e instanceof SftpException) throw (SftpException)e; @@ -1354,14 +1748,16 @@ else if(!pattern_has_wildcard){ throw new SftpException(SSH_FX_FAILURE, ""); } } + public String readlink(String path) throws SftpException{ try{ - if(server_version<3){ throw new SftpException(SSH_FX_OP_UNSUPPORTED, "The remote sshd is too old to support symlink operation."); } + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); path=isUnique(path); @@ -1402,6 +1798,7 @@ public String readlink(String path) throws SftpException{ } return null; } + public void symlink(String oldpath, String newpath) throws SftpException{ if(server_version<3){ throw new SftpException(SSH_FX_OP_UNSUPPORTED, @@ -1409,10 +1806,19 @@ public void symlink(String oldpath, String newpath) throws SftpException{ } try{ - oldpath=remoteAbsolutePath(oldpath); + ((MyPipedInputStream)io_in).updateReadSide(); + + String _oldpath=remoteAbsolutePath(oldpath); newpath=remoteAbsolutePath(newpath); - oldpath=isUnique(oldpath); + _oldpath=isUnique(_oldpath); + if(oldpath.charAt(0)!='/'){ // relative path + String cwd=getCwd(); + oldpath=_oldpath.substring(cwd.length()+(cwd.endsWith("/")?0:1)); + } + else { + oldpath=_oldpath; + } if(isPattern(newpath)){ throw new SftpException(SSH_FX_FAILURE, newpath); @@ -1445,6 +1851,58 @@ public void symlink(String oldpath, String newpath) throws SftpException{ } } + public void hardlink(String oldpath, String newpath) throws SftpException{ + if(!extension_hardlink){ + throw new SftpException(SSH_FX_OP_UNSUPPORTED, + "hardlink@openssh.com is not supported"); + } + + try{ + ((MyPipedInputStream)io_in).updateReadSide(); + + String _oldpath=remoteAbsolutePath(oldpath); + newpath=remoteAbsolutePath(newpath); + + _oldpath=isUnique(_oldpath); + if(oldpath.charAt(0)!='/'){ // relative path + String cwd=getCwd(); + oldpath=_oldpath.substring(cwd.length()+(cwd.endsWith("/")?0:1)); + } + else { + oldpath=_oldpath; + } + + if(isPattern(newpath)){ + throw new SftpException(SSH_FX_FAILURE, newpath); + } + newpath=Util.unquote(newpath); + + sendHARDLINK(Util.str2byte(oldpath, fEncoding), + Util.str2byte(newpath, fEncoding)); + + Header header=new Header(); + header=header(buf, header); + int length=header.length; + int type=header.type; + + fill(buf, length); + + if(type!=SSH_FXP_STATUS){ + throw new SftpException(SSH_FX_FAILURE, ""); + } + + int i=buf.getInt(); + if(i==SSH_FX_OK) return; + throwStatusError(buf, i); + } + catch(Exception e){ + if(e instanceof SftpException) throw (SftpException)e; + if(e instanceof Throwable) + throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); + throw new SftpException(SSH_FX_FAILURE, ""); + } + } + public void rename(String oldpath, String newpath) throws SftpException{ if(server_version<2){ throw new SftpException(SSH_FX_OP_UNSUPPORTED, @@ -1452,6 +1910,8 @@ public void rename(String oldpath, String newpath) throws SftpException{ } try{ + ((MyPipedInputStream)io_in).updateReadSide(); + oldpath=remoteAbsolutePath(oldpath); newpath=remoteAbsolutePath(newpath); @@ -1498,6 +1958,8 @@ public void rename(String oldpath, String newpath) throws SftpException{ } public void rm(String path) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); Vector v=glob_remote(path); @@ -1555,6 +2017,8 @@ private boolean isRemoteDir(String path){ public void chgrp(int gid, String path) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); Vector v=glob_remote(path); @@ -1579,6 +2043,8 @@ public void chgrp(int gid, String path) throws SftpException{ public void chown(int uid, String path) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); Vector v=glob_remote(path); @@ -1603,6 +2069,8 @@ public void chown(int uid, String path) throws SftpException{ public void chmod(int permissions, String path) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); Vector v=glob_remote(path); @@ -1627,6 +2095,8 @@ public void chmod(int permissions, String path) throws SftpException{ public void setMtime(String path, int mtime) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); Vector v=glob_remote(path); @@ -1651,6 +2121,8 @@ public void setMtime(String path, int mtime) throws SftpException{ public void rmdir(String path) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); Vector v=glob_remote(path); @@ -1688,6 +2160,8 @@ public void rmdir(String path) throws SftpException{ public void mkdir(String path) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); sendMKDIR(Util.str2byte(path, fEncoding), null); @@ -1717,8 +2191,9 @@ public void mkdir(String path) throws SftpException{ public SftpATTRS stat(String path) throws SftpException{ try{ - path=remoteAbsolutePath(path); + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); path=isUnique(path); return _stat(path); @@ -1767,10 +2242,71 @@ private SftpATTRS _stat(String path) throws SftpException{ return _stat(Util.str2byte(path, fEncoding)); } - public SftpATTRS lstat(String path) throws SftpException{ + public SftpStatVFS statVFS(String path) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); + path=isUnique(path); + + return _statVFS(path); + } + catch(Exception e){ + if(e instanceof SftpException) throw (SftpException)e; + if(e instanceof Throwable) + throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); + throw new SftpException(SSH_FX_FAILURE, ""); + } + //return null; + } + private SftpStatVFS _statVFS(byte[] path) throws SftpException{ + if(!extension_statvfs){ + throw new SftpException(SSH_FX_OP_UNSUPPORTED, + "statvfs@openssh.com is not supported"); + } + + try{ + + sendSTATVFS(path); + + Header header=new Header(); + header=header(buf, header); + int length=header.length; + int type=header.type; + + fill(buf, length); + + if(type != (SSH_FXP_EXTENDED_REPLY&0xff)){ + if(type==SSH_FXP_STATUS){ + int i=buf.getInt(); + throwStatusError(buf, i); + } + throw new SftpException(SSH_FX_FAILURE, ""); + } + else { + SftpStatVFS stat = SftpStatVFS.getStatVFS(buf); + return stat; + } + } + catch(Exception e){ + if(e instanceof SftpException) throw (SftpException)e; + if(e instanceof Throwable) + throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); + throw new SftpException(SSH_FX_FAILURE, ""); + } + //return null; + } + + private SftpStatVFS _statVFS(String path) throws SftpException{ + return _statVFS(Util.str2byte(path, fEncoding)); + } + + public SftpATTRS lstat(String path) throws SftpException{ + try{ + ((MyPipedInputStream)io_in).updateReadSide(); + + path=remoteAbsolutePath(path); path=isUnique(path); return _lstat(path); @@ -1845,6 +2381,8 @@ private byte[] _realpath(String path) throws SftpException, IOException, Excepti public void setStat(String path, SftpATTRS attr) throws SftpException{ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + path=remoteAbsolutePath(path); Vector v=glob_remote(path); @@ -1894,6 +2432,8 @@ private void _setStat(String path, SftpATTRS attr) throws SftpException{ public String getHome() throws SftpException { if(home==null){ try{ + ((MyPipedInputStream)io_in).updateReadSide(); + byte[] _home=_realpath(""); home=Util.byte2str(_home, fEncoding); } @@ -1965,6 +2505,14 @@ private void sendREALPATH(byte[] path) throws Exception{ private void sendSTAT(byte[] path) throws Exception{ sendPacketPath(SSH_FXP_STAT, path); } + private void sendSTATVFS(byte[] path) throws Exception{ + sendPacketPath((byte)0, path, "statvfs@openssh.com"); + } + /* + private void sendFSTATVFS(byte[] handle) throws Exception{ + sendPacketPath((byte)0, handle, "fstatvfs@openssh.com"); + } + */ private void sendLSTAT(byte[] path) throws Exception{ sendPacketPath(SSH_FXP_LSTAT, path); } @@ -1997,6 +2545,9 @@ private void sendRMDIR(byte[] path) throws Exception{ private void sendSYMLINK(byte[] p1, byte[] p2) throws Exception{ sendPacketPath(SSH_FXP_SYMLINK, p1, p2); } + private void sendHARDLINK(byte[] p1, byte[] p2) throws Exception{ + sendPacketPath((byte)0, p1, p2, "hardlink@openssh.com"); + } private void sendREADLINK(byte[] path) throws Exception{ sendPacketPath(SSH_FXP_READLINK, path); } @@ -2007,7 +2558,8 @@ private void sendREADDIR(byte[] path) throws Exception{ sendPacketPath(SSH_FXP_READDIR, path); } private void sendRENAME(byte[] p1, byte[] p2) throws Exception{ - sendPacketPath(SSH_FXP_RENAME, p1, p2); + sendPacketPath(SSH_FXP_RENAME, p1, p2, + extension_posix_rename ? "posix-rename@openssh.com" : null); } private void sendCLOSE(byte[] path) throws Exception{ sendPacketPath(SSH_FXP_CLOSE, path); @@ -2031,50 +2583,74 @@ private void sendOPEN(byte[] path, int mode) throws Exception{ getSession().write(packet, this, 17+path.length+4); } private void sendPacketPath(byte fxp, byte[] path) throws Exception{ + sendPacketPath(fxp, path, (String)null); + } + private void sendPacketPath(byte fxp, byte[] path, String extension) throws Exception{ packet.reset(); - putHEAD(fxp, 9+path.length); - buf.putInt(seq++); + int len = 9+path.length; + if(extension == null) { + putHEAD(fxp, len); + buf.putInt(seq++); + } + else { + len+=(4+extension.length()); + putHEAD(SSH_FXP_EXTENDED, len); + buf.putInt(seq++); + buf.putString(Util.str2byte(extension)); + } buf.putString(path); // path - getSession().write(packet, this, 9+path.length+4); + getSession().write(packet, this, len+4); } + private void sendPacketPath(byte fxp, byte[] p1, byte[] p2) throws Exception{ + sendPacketPath(fxp, p1, p2, null); + } + private void sendPacketPath(byte fxp, byte[] p1, byte[] p2, String extension) throws Exception{ packet.reset(); - putHEAD(fxp, 13+p1.length+p2.length); - buf.putInt(seq++); + int len = 13+p1.length+p2.length; + if(extension==null){ + putHEAD(fxp, len); + buf.putInt(seq++); + } + else { + len+=(4+extension.length()); + putHEAD(SSH_FXP_EXTENDED, len); + buf.putInt(seq++); + buf.putString(Util.str2byte(extension)); + } buf.putString(p1); buf.putString(p2); - getSession().write(packet, this, 13+p1.length+p2.length+4); + getSession().write(packet, this, len+4); } private int sendWRITE(byte[] handle, long offset, byte[] data, int start, int length) throws Exception{ int _length=length; - packet.reset(); - if(buf.buffer.length 3 && + if(3 <= sversion && sversion <= 5 && !encoding.equals(UTF8)){ - throw new SftpException(SSH_FX_FAILURE, + throw new SftpException(SSH_FX_FAILURE, "The encoding can not be changed for this sftp server."); } if(encoding.equals(UTF8)){ @@ -2454,4 +3030,26 @@ public int compareTo(Object o) throws ClassCastException{ throw new ClassCastException("a decendent of LsEntry must be given."); } } + + /** + * This interface will be passed as an argument for ls method. + * + * @see ChannelSftp.LsEntry + * @see #ls(String, ChannelSftp.LsEntrySelector) + * @since 0.1.47 + */ + public interface LsEntrySelector { + public final int CONTINUE = 0; + public final int BREAK = 1; + + /** + *

The select method will be invoked in ls + * method for each file entry. If this method returns BREAK, + * ls will be canceled. + * + * @param entry one of entry from ls + * @return if BREAK is returned, the 'ls' operation will be canceled. + */ + public int select(LsEntry entry); + } } diff --git a/src/com/jcraft/jsch/ChannelShell.java b/src/main/java/com/jcraft/jsch/ChannelShell.java similarity index 97% rename from src/com/jcraft/jsch/ChannelShell.java rename to src/main/java/com/jcraft/jsch/ChannelShell.java index b956e1d..bafcc39 100644 --- a/src/com/jcraft/jsch/ChannelShell.java +++ b/src/main/java/com/jcraft/jsch/ChannelShell.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/ChannelSubsystem.java b/src/main/java/com/jcraft/jsch/ChannelSubsystem.java similarity index 96% rename from src/com/jcraft/jsch/ChannelSubsystem.java rename to src/main/java/com/jcraft/jsch/ChannelSubsystem.java index e485177..697b927 100644 --- a/src/com/jcraft/jsch/ChannelSubsystem.java +++ b/src/main/java/com/jcraft/jsch/ChannelSubsystem.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2005-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2005-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -34,7 +34,7 @@ public class ChannelSubsystem extends ChannelSession{ boolean pty=false; boolean want_reply=true; String subsystem=""; - public void setXForwarding(boolean foo){ xforwading=true; } + public void setXForwarding(boolean foo){ xforwading=foo; } public void setPty(boolean foo){ pty=foo; } public void setWantReply(boolean foo){ want_reply=foo; } public void setSubsystem(String foo){ subsystem=foo; } diff --git a/src/com/jcraft/jsch/ChannelX11.java b/src/main/java/com/jcraft/jsch/ChannelX11.java similarity index 95% rename from src/com/jcraft/jsch/ChannelX11.java rename to src/main/java/com/jcraft/jsch/ChannelX11.java index e469a73..c69121c 100644 --- a/src/com/jcraft/jsch/ChannelX11.java +++ b/src/main/java/com/jcraft/jsch/ChannelX11.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -99,6 +99,13 @@ static byte[] getFakedCookie(Session session){ } } + static void removeFakedCookie(Session session){ + synchronized(faked_cookie_hex_pool){ + faked_cookie_hex_pool.remove(session); + faked_cookie_pool.remove(session); + } + } + ChannelX11(){ super(); @@ -150,9 +157,7 @@ public void run(){ io.in!=null){ i=io.in.read(buf.buffer, 14, - buf.buffer.length-14 - -32 -20 // padding and mac - ); + buf.buffer.length-14-Session.buffer_margin); if(i<=0){ eof(); break; diff --git a/src/com/jcraft/jsch/Cipher.java b/src/main/java/com/jcraft/jsch/Cipher.java similarity index 96% rename from src/com/jcraft/jsch/Cipher.java rename to src/main/java/com/jcraft/jsch/Cipher.java index b7ac84c..da1e941 100644 --- a/src/com/jcraft/jsch/Cipher.java +++ b/src/main/java/com/jcraft/jsch/Cipher.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/CipherNone.java b/src/main/java/com/jcraft/jsch/CipherNone.java similarity index 96% rename from src/com/jcraft/jsch/CipherNone.java rename to src/main/java/com/jcraft/jsch/CipherNone.java index ff50c5b..9d4e530 100644 --- a/src/com/jcraft/jsch/CipherNone.java +++ b/src/main/java/com/jcraft/jsch/CipherNone.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/Compression.java b/src/main/java/com/jcraft/jsch/Compression.java similarity index 93% rename from src/com/jcraft/jsch/Compression.java rename to src/main/java/com/jcraft/jsch/Compression.java index 091073c..96cf535 100644 --- a/src/com/jcraft/jsch/Compression.java +++ b/src/main/java/com/jcraft/jsch/Compression.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -33,6 +33,6 @@ public interface Compression{ static public final int INFLATER=0; static public final int DEFLATER=1; void init(int type, int level); - int compress(byte[] buf, int start, int len); + byte[] compress(byte[] buf, int start, int[] len); byte[] uncompress(byte[] buf, int start, int[] len); } diff --git a/src/com/jcraft/jsch/HostKeyRepository.java b/src/main/java/com/jcraft/jsch/ConfigRepository.java similarity index 65% rename from src/com/jcraft/jsch/HostKeyRepository.java rename to src/main/java/com/jcraft/jsch/ConfigRepository.java index aae6c98..ca79903 100644 --- a/src/com/jcraft/jsch/HostKeyRepository.java +++ b/src/main/java/com/jcraft/jsch/ConfigRepository.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2004-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2013-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -29,16 +29,27 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING package com.jcraft.jsch; -public interface HostKeyRepository{ - final int OK=0; - final int NOT_INCLUDED=1; - final int CHANGED=2; - - int check(String host, byte[] key); - void add(HostKey hostkey, UserInfo ui); - void remove(String host, String type); - void remove(String host, String type, byte[] key); - String getKnownHostsRepositoryID(); - HostKey[] getHostKey(); - HostKey[] getHostKey(String host, String type); +public interface ConfigRepository { + + public Config getConfig(String host); + + public interface Config { + public String getHostname(); + public String getUser(); + public int getPort(); + public String getValue(String key); + public String[] getValues(String key); + } + + static final Config defaultConfig = new Config() { + public String getHostname() {return null;} + public String getUser() {return null;} + public int getPort() {return -1;} + public String getValue(String key) {return null;} + public String[] getValues(String key) {return null;} + }; + + static final ConfigRepository nullConfig = new ConfigRepository(){ + public Config getConfig(String host) { return defaultConfig; } + }; } diff --git a/src/com/jcraft/jsch/DH.java b/src/main/java/com/jcraft/jsch/DH.java similarity index 88% rename from src/com/jcraft/jsch/DH.java rename to src/main/java/com/jcraft/jsch/DH.java index 8e43021..ce79791 100644 --- a/src/com/jcraft/jsch/DH.java +++ b/src/main/java/com/jcraft/jsch/DH.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -36,4 +36,8 @@ public interface DH{ byte[] getE() throws Exception; void setF(byte[] f); byte[] getK() throws Exception; + + // checkRange() will check if e and f are in [1,p-1] + // as defined at https://tools.ietf.org/html/rfc4253#section-8 + void checkRange() throws Exception; } diff --git a/src/main/java/com/jcraft/jsch/DHEC256.java b/src/main/java/com/jcraft/jsch/DHEC256.java new file mode 100644 index 0000000..c2a7d05 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/DHEC256.java @@ -0,0 +1,37 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +public class DHEC256 extends DHECN { + public DHEC256(){ + sha_name="sha-256"; + key_size=256; + } +} diff --git a/src/main/java/com/jcraft/jsch/DHEC384.java b/src/main/java/com/jcraft/jsch/DHEC384.java new file mode 100644 index 0000000..3fdcb78 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/DHEC384.java @@ -0,0 +1,37 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +public class DHEC384 extends DHECN { + public DHEC384(){ + sha_name="sha-384"; + key_size=384; + } +} diff --git a/src/main/java/com/jcraft/jsch/DHEC521.java b/src/main/java/com/jcraft/jsch/DHEC521.java new file mode 100644 index 0000000..b9bb091 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/DHEC521.java @@ -0,0 +1,37 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +public class DHEC521 extends DHECN { + public DHEC521(){ + sha_name="sha-512"; + key_size=521; + } +} diff --git a/src/main/java/com/jcraft/jsch/DHECN.java b/src/main/java/com/jcraft/jsch/DHECN.java new file mode 100644 index 0000000..ecfaa09 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/DHECN.java @@ -0,0 +1,187 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +public abstract class DHECN extends KeyExchange{ + + private static final int SSH_MSG_KEX_ECDH_INIT = 30; + private static final int SSH_MSG_KEX_ECDH_REPLY= 31; + private int state; + + byte[] Q_C; + + byte[] V_S; + byte[] V_C; + byte[] I_S; + byte[] I_C; + + byte[] e; + + private Buffer buf; + private Packet packet; + + private ECDH ecdh; + + protected String sha_name; + protected int key_size; + + public void init(Session session, + byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ + this.session=session; + this.V_S=V_S; + this.V_C=V_C; + this.I_S=I_S; + this.I_C=I_C; + + try{ + Class c=Class.forName(session.getConfig(sha_name)); + sha=(HASH)(c.newInstance()); + sha.init(); + } + catch(Exception e){ + System.err.println(e); + } + + buf=new Buffer(); + packet=new Packet(buf); + + packet.reset(); + buf.putByte((byte)SSH_MSG_KEX_ECDH_INIT); + + try{ + Class c=Class.forName(session.getConfig("ecdh-sha2-nistp")); + ecdh=(ECDH)(c.newInstance()); + ecdh.init(key_size); + + Q_C = ecdh.getQ(); + buf.putString(Q_C); + } + catch(Exception e){ + if(e instanceof Throwable) + throw new JSchException(e.toString(), (Throwable)e); + throw new JSchException(e.toString()); + } + + if(V_S==null){ // This is a really ugly hack for Session.checkKexes ;-( + return; + } + + session.write(packet); + + if(JSch.getLogger().isEnabled(Logger.INFO)){ + JSch.getLogger().log(Logger.INFO, + "SSH_MSG_KEX_ECDH_INIT sent"); + JSch.getLogger().log(Logger.INFO, + "expecting SSH_MSG_KEX_ECDH_REPLY"); + } + + state=SSH_MSG_KEX_ECDH_REPLY; + } + + public boolean next(Buffer _buf) throws Exception{ + int i,j; + switch(state){ + case SSH_MSG_KEX_ECDH_REPLY: + // The server responds with: + // byte SSH_MSG_KEX_ECDH_REPLY + // string K_S, server's public host key + // string Q_S, server's ephemeral public key octet string + // string the signature on the exchange hash + j=_buf.getInt(); + j=_buf.getByte(); + j=_buf.getByte(); + if(j!=31){ + System.err.println("type: must be 31 "+j); + return false; + } + + K_S=_buf.getString(); + + byte[] Q_S=_buf.getString(); + + byte[][] r_s = KeyPairECDSA.fromPoint(Q_S); + + // RFC 5656, + // 4. ECDH Key Exchange + // All elliptic curve public keys MUST be validated after they are + // received. An example of a validation algorithm can be found in + // Section 3.2.2 of [SEC1]. If a key fails validation, + // the key exchange MUST fail. + if(!ecdh.validate(r_s[0], r_s[1])){ + return false; + } + + K = ecdh.getSecret(r_s[0], r_s[1]); + K=normalize(K); + + byte[] sig_of_H=_buf.getString(); + + //The hash H is computed as the HASH hash of the concatenation of the + //following: + // string V_C, client's identification string (CR and LF excluded) + // string V_S, server's identification string (CR and LF excluded) + // string I_C, payload of the client's SSH_MSG_KEXINIT + // string I_S, payload of the server's SSH_MSG_KEXINIT + // string K_S, server's public host key + // string Q_C, client's ephemeral public key octet string + // string Q_S, server's ephemeral public key octet string + // mpint K, shared secret + + // This value is called the exchange hash, and it is used to authenti- + // cate the key exchange. + buf.reset(); + buf.putString(V_C); buf.putString(V_S); + buf.putString(I_C); buf.putString(I_S); + buf.putString(K_S); + buf.putString(Q_C); buf.putString(Q_S); + buf.putMPInt(K); + byte[] foo=new byte[buf.getLength()]; + buf.getByte(foo); + + sha.update(foo, 0, foo.length); + H=sha.digest(); + + i=0; + j=0; + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + String alg=Util.byte2str(K_S, i, j); + i+=j; + + boolean result = verify(alg, K_S, i, sig_of_H); + + state=STATE_END; + return result; + } + return false; + } + + public int getState(){return state; } +} diff --git a/src/com/jcraft/jsch/DHG1.java b/src/main/java/com/jcraft/jsch/DHG1.java similarity index 67% rename from src/com/jcraft/jsch/DHG1.java rename to src/main/java/com/jcraft/jsch/DHG1.java index 3e8b807..4829478 100644 --- a/src/com/jcraft/jsch/DHG1.java +++ b/src/main/java/com/jcraft/jsch/DHG1.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -55,25 +55,15 @@ public class DHG1 extends KeyExchange{ private static final int SSH_MSG_KEXDH_INIT= 30; private static final int SSH_MSG_KEXDH_REPLY= 31; - static final int RSA=0; - static final int DSS=1; - private int type=0; - private int state; DH dh; -// HASH sha; - -// byte[] K; -// byte[] H; byte[] V_S; byte[] V_C; byte[] I_S; byte[] I_C; -// byte[] K_S; - byte[] e; private Buffer buf; @@ -87,8 +77,6 @@ public void init(Session session, this.I_S=I_S; this.I_C=I_C; -// sha=new SHA1(); -// sha.init(); try{ Class c=Class.forName(session.getConfig("sha-1")); sha=(HASH)(c.newInstance()); @@ -155,25 +143,15 @@ public boolean next(Buffer _buf) throws Exception{ } K_S=_buf.getString(); - // K_S is server_key_blob, which includes .... - // string ssh-dss - // impint p of dsa - // impint q of dsa - // impint g of dsa - // impint pub_key of dsa - //System.err.print("K_S: "); //dump(K_S, 0, K_S.length); + byte[] f=_buf.getMPInt(); byte[] sig_of_H=_buf.getString(); - /* -for(int ii=0; ii "); //dump(H, 0, H.length); + + i=0; + j=0; + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + String alg=Util.byte2str(K_S, i, j); + i+=j; + + boolean result = verify(alg, K_S, i, sig_of_H); + + state=STATE_END; + return result; + } + return false; + } + + public int getState(){return state; } +} diff --git a/src/com/jcraft/jsch/DHGEX.java b/src/main/java/com/jcraft/jsch/DHGEX.java similarity index 66% rename from src/com/jcraft/jsch/DHGEX.java rename to src/main/java/com/jcraft/jsch/DHGEX.java index 79d994a..8a6b2f8 100644 --- a/src/com/jcraft/jsch/DHGEX.java +++ b/src/main/java/com/jcraft/jsch/DHGEX.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -37,21 +37,11 @@ public class DHGEX extends KeyExchange{ private static final int SSH_MSG_KEX_DH_GEX_REQUEST= 34; static int min=1024; - -// static int min=512; static int preferred=1024; - static int max=1024; - -// static int preferred=1024; -// static int max=2000; - - static final int RSA=0; - static final int DSS=1; - private int type=0; + int max=1024; private int state; -// com.jcraft.jsch.DH dh; DH dh; byte[] V_S; @@ -65,7 +55,8 @@ public class DHGEX extends KeyExchange{ private byte[] p; private byte[] g; private byte[] e; - //private byte[] f; + + protected String hash="sha-1"; public void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ @@ -76,7 +67,7 @@ public void init(Session session, this.I_C=I_C; try{ - Class c=Class.forName(session.getConfig("sha-1")); + Class c=Class.forName(session.getConfig(hash)); sha=(HASH)(c.newInstance()); sha.init(); } @@ -89,11 +80,13 @@ public void init(Session session, try{ Class c=Class.forName(session.getConfig("dh")); + // Since JDK8, SunJCE has lifted the keysize restrictions + // from 1024 to 2048 for DH. + preferred = max = check2048(c, max); dh=(com.jcraft.jsch.DH)(c.newInstance()); dh.init(); } catch(Exception e){ -// System.err.println(e); throw e; } @@ -131,18 +124,9 @@ public boolean next(Buffer _buf) throws Exception{ p=_buf.getMPInt(); g=_buf.getMPInt(); - /* -for(int iii=0; iiihost is included with the key. + * + * @return #NOT_INCLUDED, #OK or #CHANGED + * @see #NOT_INCLUDED + * @see #OK + * @see #CHANGED + */ + int check(String host, byte[] key); + + /** + * Adds a host key hostkey + * + * @param hostkey a host key to be added + * @param ui a user interface for showing messages or promping inputs. + * @see UserInfo + */ + void add(HostKey hostkey, UserInfo ui); + + /** + * Removes a host key if there exists mached key with + * host, type. + * + * @see #remove(String host, String type, byte[] key) + */ + void remove(String host, String type); + + /** + * Removes a host key if there exists a matched key with + * host, type and key. + */ + void remove(String host, String type, byte[] key); + + /** + * Returns id of this repository. + * + * @return identity in String + */ + String getKnownHostsRepositoryID(); + + /** + * Retuns a list for host keys managed in this repository. + * + * @see #getHostKey(String host, String type) + */ + HostKey[] getHostKey(); + + /** + * Retuns a list for host keys managed in this repository. + * + * @param host a hostname used in searching host keys. + * If null is given, every host key will be listed. + * @param type a key type used in searching host keys, + * and it should be "ssh-dss" or "ssh-rsa". + * If null is given, a key type type will not be ignored. + */ + HostKey[] getHostKey(String host, String type); +} diff --git a/src/com/jcraft/jsch/IO.java b/src/main/java/com/jcraft/jsch/IO.java similarity index 98% rename from src/com/jcraft/jsch/IO.java rename to src/main/java/com/jcraft/jsch/IO.java index 87ef8ad..a354bff 100644 --- a/src/com/jcraft/jsch/IO.java +++ b/src/main/java/com/jcraft/jsch/IO.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/com/jcraft/jsch/Identity.java b/src/main/java/com/jcraft/jsch/Identity.java new file mode 100644 index 0000000..70005a8 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/Identity.java @@ -0,0 +1,83 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +public interface Identity{ + + /** + * Decrypts this identity with the specified pass-phrase. + * @param passphrase the pass-phrase for this identity. + * @return true if the decryption is succeeded + * or this identity is not cyphered. + */ + public boolean setPassphrase(byte[] passphrase) throws JSchException; + + /** + * Returns the public-key blob. + * @return the public-key blob + */ + public byte[] getPublicKeyBlob(); + + /** + * Signs on data with this identity, and returns the result. + * @param data data to be signed + * @return the signature + */ + public byte[] getSignature(byte[] data); + + /** + * @deprecated The decryption should be done automatically in #setPassphase(byte[] passphrase) + * @see #setPassphrase(byte[] passphrase) + */ + public boolean decrypt(); + + /** + * Returns the name of the key algorithm. + * @return "ssh-rsa" or "ssh-dss" + */ + public String getAlgName(); + + /** + * Returns the name of this identity. + * It will be useful to identify this object in the {@link IdentityRepository}. + */ + public String getName(); + + /** + * Returns true if this identity is cyphered. + * @return true if this identity is cyphered. + */ + public boolean isEncrypted(); + + /** + * Disposes internally allocated data, like byte array for the private key. + */ + public void clear(); +} diff --git a/src/main/java/com/jcraft/jsch/IdentityFile.java b/src/main/java/com/jcraft/jsch/IdentityFile.java new file mode 100644 index 0000000..e3d5d7b --- /dev/null +++ b/src/main/java/com/jcraft/jsch/IdentityFile.java @@ -0,0 +1,130 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +import java.io.*; + +class IdentityFile implements Identity{ + private JSch jsch; + private KeyPair kpair; + private String identity; + + static IdentityFile newInstance(String prvfile, String pubfile, JSch jsch) throws JSchException{ + KeyPair kpair = KeyPair.load(jsch, prvfile, pubfile); + return new IdentityFile(jsch, prvfile, kpair); + } + + static IdentityFile newInstance(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{ + + KeyPair kpair = KeyPair.load(jsch, prvkey, pubkey); + return new IdentityFile(jsch, name, kpair); + } + + private IdentityFile(JSch jsch, String name, KeyPair kpair) throws JSchException{ + this.jsch = jsch; + this.identity = name; + this.kpair = kpair; + } + + /** + * Decrypts this identity with the specified pass-phrase. + * @param passphrase the pass-phrase for this identity. + * @return true if the decryption is succeeded + * or this identity is not cyphered. + */ + public boolean setPassphrase(byte[] passphrase) throws JSchException{ + return kpair.decrypt(passphrase); + } + + /** + * Returns the public-key blob. + * @return the public-key blob + */ + public byte[] getPublicKeyBlob(){ + return kpair.getPublicKeyBlob(); + } + + /** + * Signs on data with this identity, and returns the result. + * @param data data to be signed + * @return the signature + */ + public byte[] getSignature(byte[] data){ + return kpair.getSignature(data); + } + + /** + * @deprecated This method should not be invoked. + * @see #setPassphrase(byte[] passphrase) + */ + public boolean decrypt(){ + throw new RuntimeException("not implemented"); + } + + /** + * Returns the name of the key algorithm. + * @return "ssh-rsa" or "ssh-dss" + */ + public String getAlgName(){ + return new String(kpair.getKeyTypeName()); + } + + /** + * Returns the name of this identity. + * It will be useful to identify this object in the {@link IdentityRepository}. + */ + public String getName(){ + return identity; + } + + /** + * Returns true if this identity is cyphered. + * @return true if this identity is cyphered. + */ + public boolean isEncrypted(){ + return kpair.isEncrypted(); + } + + /** + * Disposes internally allocated data, like byte array for the private key. + */ + public void clear(){ + kpair.dispose(); + kpair = null; + } + + /** + * Returns an instance of {@link KeyPair} used in this {@link Identity}. + * @return an instance of {@link KeyPair} used in this {@link Identity}. + */ + public KeyPair getKeyPair(){ + return kpair; + } +} diff --git a/src/main/java/com/jcraft/jsch/IdentityRepository.java b/src/main/java/com/jcraft/jsch/IdentityRepository.java new file mode 100644 index 0000000..a24bc42 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/IdentityRepository.java @@ -0,0 +1,115 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2012-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +import java.util.Vector; + +public interface IdentityRepository { + public static final int UNAVAILABLE=0; + public static final int NOTRUNNING=1; + public static final int RUNNING=2; + public String getName(); + public int getStatus(); + public Vector getIdentities(); + public boolean add(byte[] identity); + public boolean remove(byte[] blob); + public void removeAll(); + + /** + * JSch will accept ciphered keys, but some implementations of + * IdentityRepository can not. For example, IdentityRepository for + * ssh-agent and pageant only accept plain keys. The following class has + * been introduced to cache ciphered keys for them, and pass them + * whenever they are de-ciphered. + */ + static class Wrapper implements IdentityRepository { + private IdentityRepository ir; + private Vector cache = new Vector(); + private boolean keep_in_cache = false; + Wrapper(IdentityRepository ir){ + this(ir, false); + } + Wrapper(IdentityRepository ir, boolean keep_in_cache){ + this.ir = ir; + this.keep_in_cache = keep_in_cache; + } + public String getName() { + return ir.getName(); + } + public int getStatus() { + return ir.getStatus(); + } + public boolean add(byte[] identity) { + return ir.add(identity); + } + public boolean remove(byte[] blob) { + return ir.remove(blob); + } + public void removeAll() { + cache.removeAllElements(); + ir.removeAll(); + } + public Vector getIdentities() { + Vector result = new Vector(); + for(int i = 0; i< cache.size(); i++){ + Identity identity = (Identity)(cache.elementAt(i)); + result.add(identity); + } + Vector tmp = ir.getIdentities(); + for(int i = 0; i< tmp.size(); i++){ + result.add(tmp.elementAt(i)); + } + return result; + } + void add(Identity identity) { + if(!keep_in_cache && + !identity.isEncrypted() && (identity instanceof IdentityFile)) { + try { + ir.add(((IdentityFile)identity).getKeyPair().forSSHAgent()); + } + catch(JSchException e){ + // an exception will not be thrown. + } + } + else + cache.addElement(identity); + } + void check() { + if(cache.size() > 0){ + Object[] identities = cache.toArray(); + for(int i = 0; i < identities.length; i++){ + Identity identity = (Identity)(identities[i]); + cache.removeElement(identity); + add(identity); + } + } + } + } +} diff --git a/src/main/java/com/jcraft/jsch/JSch.java b/src/main/java/com/jcraft/jsch/JSch.java new file mode 100644 index 0000000..3b3e7a1 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/JSch.java @@ -0,0 +1,591 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +import java.io.InputStream; +import java.util.Vector; + +public class JSch{ + /** + * The version number. + */ + public static final String VERSION = "0.1.54"; + + static java.util.Hashtable config=new java.util.Hashtable(); + static{ + config.put("kex", "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"); + config.put("server_host_key", "ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521"); + config.put("cipher.s2c", + "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc"); + config.put("cipher.c2s", + "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc"); + + config.put("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96"); + config.put("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96"); + config.put("compression.s2c", "none"); + config.put("compression.c2s", "none"); + + config.put("lang.s2c", ""); + config.put("lang.c2s", ""); + + config.put("compression_level", "6"); + + config.put("diffie-hellman-group-exchange-sha1", + "com.jcraft.jsch.DHGEX"); + config.put("diffie-hellman-group1-sha1", + "com.jcraft.jsch.DHG1"); + config.put("diffie-hellman-group14-sha1", + "com.jcraft.jsch.DHG14"); // available since JDK8. + config.put("diffie-hellman-group-exchange-sha256", + "com.jcraft.jsch.DHGEX256"); // available since JDK1.4.2. + // On JDK8, 2048bits will be used. + config.put("ecdsa-sha2-nistp256", "com.jcraft.jsch.jce.SignatureECDSA"); + config.put("ecdsa-sha2-nistp384", "com.jcraft.jsch.jce.SignatureECDSA"); + config.put("ecdsa-sha2-nistp521", "com.jcraft.jsch.jce.SignatureECDSA"); + + config.put("ecdh-sha2-nistp256", "com.jcraft.jsch.DHEC256"); + config.put("ecdh-sha2-nistp384", "com.jcraft.jsch.DHEC384"); + config.put("ecdh-sha2-nistp521", "com.jcraft.jsch.DHEC521"); + + config.put("ecdh-sha2-nistp", "com.jcraft.jsch.jce.ECDHN"); + + config.put("dh", "com.jcraft.jsch.jce.DH"); + config.put("3des-cbc", "com.jcraft.jsch.jce.TripleDESCBC"); + config.put("blowfish-cbc", "com.jcraft.jsch.jce.BlowfishCBC"); + config.put("hmac-sha1", "com.jcraft.jsch.jce.HMACSHA1"); + config.put("hmac-sha1-96", "com.jcraft.jsch.jce.HMACSHA196"); + config.put("hmac-sha2-256", "com.jcraft.jsch.jce.HMACSHA256"); + // The "hmac-sha2-512" will require the key-length 2048 for DH, + // but Sun's JCE has not allowed to use such a long key. + //config.put("hmac-sha2-512", "com.jcraft.jsch.jce.HMACSHA512"); + config.put("hmac-md5", "com.jcraft.jsch.jce.HMACMD5"); + config.put("hmac-md5-96", "com.jcraft.jsch.jce.HMACMD596"); + config.put("sha-1", "com.jcraft.jsch.jce.SHA1"); + config.put("sha-256", "com.jcraft.jsch.jce.SHA256"); + config.put("sha-384", "com.jcraft.jsch.jce.SHA384"); + config.put("sha-512", "com.jcraft.jsch.jce.SHA512"); + config.put("md5", "com.jcraft.jsch.jce.MD5"); + config.put("signature.dss", "com.jcraft.jsch.jce.SignatureDSA"); + config.put("signature.rsa", "com.jcraft.jsch.jce.SignatureRSA"); + config.put("signature.ecdsa", "com.jcraft.jsch.jce.SignatureECDSA"); + config.put("keypairgen.dsa", "com.jcraft.jsch.jce.KeyPairGenDSA"); + config.put("keypairgen.rsa", "com.jcraft.jsch.jce.KeyPairGenRSA"); + config.put("keypairgen.ecdsa", "com.jcraft.jsch.jce.KeyPairGenECDSA"); + config.put("random", "com.jcraft.jsch.jce.Random"); + + config.put("none", "com.jcraft.jsch.CipherNone"); + + config.put("aes128-cbc", "com.jcraft.jsch.jce.AES128CBC"); + config.put("aes192-cbc", "com.jcraft.jsch.jce.AES192CBC"); + config.put("aes256-cbc", "com.jcraft.jsch.jce.AES256CBC"); + + config.put("aes128-ctr", "com.jcraft.jsch.jce.AES128CTR"); + config.put("aes192-ctr", "com.jcraft.jsch.jce.AES192CTR"); + config.put("aes256-ctr", "com.jcraft.jsch.jce.AES256CTR"); + config.put("3des-ctr", "com.jcraft.jsch.jce.TripleDESCTR"); + config.put("arcfour", "com.jcraft.jsch.jce.ARCFOUR"); + config.put("arcfour128", "com.jcraft.jsch.jce.ARCFOUR128"); + config.put("arcfour256", "com.jcraft.jsch.jce.ARCFOUR256"); + + config.put("userauth.none", "com.jcraft.jsch.UserAuthNone"); + config.put("userauth.password", "com.jcraft.jsch.UserAuthPassword"); + config.put("userauth.keyboard-interactive", "com.jcraft.jsch.UserAuthKeyboardInteractive"); + config.put("userauth.publickey", "com.jcraft.jsch.UserAuthPublicKey"); + config.put("userauth.gssapi-with-mic", "com.jcraft.jsch.UserAuthGSSAPIWithMIC"); + config.put("gssapi-with-mic.krb5", "com.jcraft.jsch.jgss.GSSContextKrb5"); + + config.put("zlib", "com.jcraft.jsch.jcraft.Compression"); + config.put("zlib@openssh.com", "com.jcraft.jsch.jcraft.Compression"); + + config.put("pbkdf", "com.jcraft.jsch.jce.PBKDF"); + + config.put("StrictHostKeyChecking", "ask"); + config.put("HashKnownHosts", "no"); + + config.put("PreferredAuthentications", "gssapi-with-mic,publickey,keyboard-interactive,password"); + + config.put("CheckCiphers", "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256"); + config.put("CheckKexes", "diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521"); + config.put("CheckSignatures", "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521"); + + config.put("MaxAuthTries", "6"); + config.put("ClearAllForwardings", "no"); + } + + private java.util.Vector sessionPool = new java.util.Vector(); + + private IdentityRepository defaultIdentityRepository = + new LocalIdentityRepository(this); + + private IdentityRepository identityRepository = defaultIdentityRepository; + + private ConfigRepository configRepository = null; + + /** + * Sets the identityRepository, which will be referred + * in the public key authentication. + * + * @param identityRepository if null is given, + * the default repository, which usually refers to ~/.ssh/, will be used. + * + * @see #getIdentityRepository() + */ + public synchronized void setIdentityRepository(IdentityRepository identityRepository){ + if(identityRepository == null){ + this.identityRepository = defaultIdentityRepository; + } + else{ + this.identityRepository = identityRepository; + } + } + + public synchronized IdentityRepository getIdentityRepository(){ + return this.identityRepository; + } + + public ConfigRepository getConfigRepository() { + return this.configRepository; + } + + public void setConfigRepository(ConfigRepository configRepository) { + this.configRepository = configRepository; + } + + private HostKeyRepository known_hosts=null; + + private static final Logger DEVNULL=new Logger(){ + public boolean isEnabled(int level){return false;} + public void log(int level, String message){} + }; + static Logger logger=DEVNULL; + + public JSch(){ + /* + // The JCE of Sun's Java5 on Mac OS X has the resource leak bug + // in calculating HMAC, so we need to use our own implementations. + try{ + String osname=(String)(System.getProperties().get("os.name")); + if(osname!=null && osname.equals("Mac OS X")){ + config.put("hmac-sha1", "com.jcraft.jsch.jcraft.HMACSHA1"); + config.put("hmac-md5", "com.jcraft.jsch.jcraft.HMACMD5"); + config.put("hmac-md5-96", "com.jcraft.jsch.jcraft.HMACMD596"); + config.put("hmac-sha1-96", "com.jcraft.jsch.jcraft.HMACSHA196"); + } + } + catch(Exception e){ + } + */ + } + + /** + * Instantiates the Session object with + * host. The user name and port number will be retrieved from + * ConfigRepository. If user name is not given, + * the system property "user.name" will be referred. + * + * @param host hostname + * + * @throws JSchException + * if username or host are invalid. + * + * @return the instance of Session class. + * + * @see #getSession(String username, String host, int port) + * @see com.jcraft.jsch.Session + * @see com.jcraft.jsch.ConfigRepository + */ + public Session getSession(String host) + throws JSchException { + return getSession(null, host, 22); + } + + /** + * Instantiates the Session object with + * username and host. + * The TCP port 22 will be used in making the connection. + * Note that the TCP connection must not be established + * until Session#connect(). + * + * @param username user name + * @param host hostname + * + * @throws JSchException + * if username or host are invalid. + * + * @return the instance of Session class. + * + * @see #getSession(String username, String host, int port) + * @see com.jcraft.jsch.Session + */ + public Session getSession(String username, String host) + throws JSchException { + return getSession(username, host, 22); + } + + /** + * Instantiates the Session object with given + * username, host and port. + * Note that the TCP connection must not be established + * until Session#connect(). + * + * @param username user name + * @param host hostname + * @param port port number + * + * @throws JSchException + * if username or host are invalid. + * + * @return the instance of Session class. + * + * @see #getSession(String username, String host, int port) + * @see com.jcraft.jsch.Session + */ + public Session getSession(String username, String host, int port) throws JSchException { + if(host==null){ + throw new JSchException("host must not be null."); + } + Session s = new Session(this, username, host, port); + return s; + } + + protected void addSession(Session session){ + synchronized(sessionPool){ + sessionPool.addElement(session); + } + } + + protected boolean removeSession(Session session){ + synchronized(sessionPool){ + return sessionPool.remove(session); + } + } + + /** + * Sets the hostkey repository. + * + * @param hkrepo + * + * @see com.jcraft.jsch.HostKeyRepository + * @see com.jcraft.jsch.KnownHosts + */ + public void setHostKeyRepository(HostKeyRepository hkrepo){ + known_hosts=hkrepo; + } + + /** + * Sets the instance of KnownHosts, which refers + * to filename. + * + * @param filename filename of known_hosts file. + * + * @throws JSchException + * if the given filename is invalid. + * + * @see com.jcraft.jsch.KnownHosts + */ + public void setKnownHosts(String filename) throws JSchException{ + if(known_hosts==null) known_hosts=new KnownHosts(this); + if(known_hosts instanceof KnownHosts){ + synchronized(known_hosts){ + ((KnownHosts)known_hosts).setKnownHosts(filename); + } + } + } + + /** + * Sets the instance of KnownHosts generated with + * stream. + * + * @param stream the instance of InputStream from known_hosts file. + * + * @throws JSchException + * if an I/O error occurs. + * + * @see com.jcraft.jsch.KnownHosts + */ + public void setKnownHosts(InputStream stream) throws JSchException{ + if(known_hosts==null) known_hosts=new KnownHosts(this); + if(known_hosts instanceof KnownHosts){ + synchronized(known_hosts){ + ((KnownHosts)known_hosts).setKnownHosts(stream); + } + } + } + + /** + * Returns the current hostkey repository. + * By the default, this method will the instance of KnownHosts. + * + * @return current hostkey repository. + * + * @see com.jcraft.jsch.HostKeyRepository + * @see com.jcraft.jsch.KnownHosts + */ + public HostKeyRepository getHostKeyRepository(){ + if(known_hosts==null) known_hosts=new KnownHosts(this); + return known_hosts; + } + + /** + * Sets the private key, which will be referred in + * the public key authentication. + * + * @param prvkey filename of the private key. + * + * @throws JSchException if prvkey is invalid. + * + * @see #addIdentity(String prvkey, String passphrase) + */ + public void addIdentity(String prvkey) throws JSchException{ + addIdentity(prvkey, (byte[])null); + } + + /** + * Sets the private key, which will be referred in + * the public key authentication. + * Before registering it into identityRepository, + * it will be deciphered with passphrase. + * + * @param prvkey filename of the private key. + * @param passphrase passphrase for prvkey. + * + * @throws JSchException if passphrase is not right. + * + * @see #addIdentity(String prvkey, byte[] passphrase) + */ + public void addIdentity(String prvkey, String passphrase) throws JSchException{ + byte[] _passphrase=null; + if(passphrase!=null){ + _passphrase=Util.str2byte(passphrase); + } + addIdentity(prvkey, _passphrase); + if(_passphrase!=null) + Util.bzero(_passphrase); + } + + /** + * Sets the private key, which will be referred in + * the public key authentication. + * Before registering it into identityRepository, + * it will be deciphered with passphrase. + * + * @param prvkey filename of the private key. + * @param passphrase passphrase for prvkey. + * + * @throws JSchException if passphrase is not right. + * + * @see #addIdentity(String prvkey, String pubkey, byte[] passphrase) + */ + public void addIdentity(String prvkey, byte[] passphrase) throws JSchException{ + Identity identity=IdentityFile.newInstance(prvkey, null, this); + addIdentity(identity, passphrase); + } + + /** + * Sets the private key, which will be referred in + * the public key authentication. + * Before registering it into identityRepository, + * it will be deciphered with passphrase. + * + * @param prvkey filename of the private key. + * @param pubkey filename of the public key. + * @param passphrase passphrase for prvkey. + * + * @throws JSchException if passphrase is not right. + */ + public void addIdentity(String prvkey, String pubkey, byte[] passphrase) throws JSchException{ + Identity identity=IdentityFile.newInstance(prvkey, pubkey, this); + addIdentity(identity, passphrase); + } + + /** + * Sets the private key, which will be referred in + * the public key authentication. + * Before registering it into identityRepository, + * it will be deciphered with passphrase. + * + * @param name name of the identity to be used to + retrieve it in the identityRepository. + * @param prvkey private key in byte array. + * @param pubkey public key in byte array. + * @param passphrase passphrase for prvkey. + * + */ + public void addIdentity(String name, byte[]prvkey, byte[]pubkey, byte[] passphrase) throws JSchException{ + Identity identity=IdentityFile.newInstance(name, prvkey, pubkey, this); + addIdentity(identity, passphrase); + } + + /** + * Sets the private key, which will be referred in + * the public key authentication. + * Before registering it into identityRepository, + * it will be deciphered with passphrase. + * + * @param identity private key. + * @param passphrase passphrase for identity. + * + * @throws JSchException if passphrase is not right. + */ + public void addIdentity(Identity identity, byte[] passphrase) throws JSchException{ + if(passphrase!=null){ + try{ + byte[] goo=new byte[passphrase.length]; + System.arraycopy(passphrase, 0, goo, 0, passphrase.length); + passphrase=goo; + identity.setPassphrase(passphrase); + } + finally{ + Util.bzero(passphrase); + } + } + + if(identityRepository instanceof LocalIdentityRepository){ + ((LocalIdentityRepository)identityRepository).add(identity); + } + else if(identity instanceof IdentityFile && !identity.isEncrypted()) { + identityRepository.add(((IdentityFile)identity).getKeyPair().forSSHAgent()); + } + else { + synchronized(this){ + if(!(identityRepository instanceof IdentityRepository.Wrapper)){ + setIdentityRepository(new IdentityRepository.Wrapper(identityRepository)); + } + } + ((IdentityRepository.Wrapper)identityRepository).add(identity); + } + } + + /** + * @deprecated use #removeIdentity(Identity identity) + */ + public void removeIdentity(String name) throws JSchException{ + Vector identities = identityRepository.getIdentities(); + for(int i=0; iidentity is invalid. + */ + public void removeIdentity(Identity identity) throws JSchException{ + identityRepository.remove(identity.getPublicKeyBlob()); + } + + /** + * Lists names of identities included in the identityRepository. + * + * @return names of identities + * + * @throws JSchException if identityReposory has problems. + */ + public Vector getIdentityNames() throws JSchException{ + Vector foo=new Vector(); + Vector identities = identityRepository.getIdentities(); + for(int i=0; iclient"+ + " "+guess[PROPOSAL_ENC_ALGS_STOC]+ + " "+guess[PROPOSAL_MAC_ALGS_STOC]+ + " "+guess[PROPOSAL_COMP_ALGS_STOC]); + JSch.getLogger().log(Logger.INFO, + "kex: client->server"+ + " "+guess[PROPOSAL_ENC_ALGS_CTOS]+ + " "+guess[PROPOSAL_MAC_ALGS_CTOS]+ + " "+guess[PROPOSAL_COMP_ALGS_CTOS]); + } + + return guess; + } + + public String getFingerPrint(){ + HASH hash=null; + try{ + Class c=Class.forName(session.getConfig("md5")); + hash=(HASH)(c.newInstance()); + } + catch(Exception e){ System.err.println("getFingerPrint: "+e); } + return Util.getFingerPrint(hash, getHostKey()); + } + byte[] getK(){ return K; } + byte[] getH(){ return H; } + HASH getHash(){ return sha; } + byte[] getHostKey(){ return K_S; } + + /* + * It seems JCE included in Oracle's Java7u6(and later) has suddenly changed + * its behavior. The secrete generated by KeyAgreement#generateSecret() + * may start with 0, even if it is a positive value. + */ + protected byte[] normalize(byte[] secret) { + if(secret.length > 1 && + secret[0] == 0 && (secret[1]&0x80) == 0) { + byte[] tmp=new byte[secret.length-1]; + System.arraycopy(secret, 1, tmp, 0, tmp.length); + return normalize(tmp); + } + else { + return secret; + } + } + + protected boolean verify(String alg, byte[] K_S, int index, + byte[] sig_of_H) throws Exception { + int i,j; + + i=index; + boolean result=false; + + if(alg.equals("ssh-rsa")){ + byte[] tmp; + byte[] ee; + byte[] n; + + type=RSA; + key_alg_name=alg; + + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; + ee=tmp; + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; + n=tmp; + + SignatureRSA sig=null; + try{ + Class c=Class.forName(session.getConfig("signature.rsa")); + sig=(SignatureRSA)(c.newInstance()); + sig.init(); + } + catch(Exception e){ + System.err.println(e); + } + sig.setPubKey(ee, n); + sig.update(H); + result=sig.verify(sig_of_H); + + if(JSch.getLogger().isEnabled(Logger.INFO)){ + JSch.getLogger().log(Logger.INFO, + "ssh_rsa_verify: signature "+result); + } + } + else if(alg.equals("ssh-dss")){ + byte[] q=null; + byte[] tmp; + byte[] p; + byte[] g; + byte[] f; + + type=DSS; + key_alg_name=alg; + + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; + p=tmp; + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; + q=tmp; + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; + g=tmp; + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; + f=tmp; + + SignatureDSA sig=null; + try{ + Class c=Class.forName(session.getConfig("signature.dss")); + sig=(SignatureDSA)(c.newInstance()); + sig.init(); + } + catch(Exception e){ + System.err.println(e); + } + sig.setPubKey(f, p, q, g); + sig.update(H); + result=sig.verify(sig_of_H); + + if(JSch.getLogger().isEnabled(Logger.INFO)){ + JSch.getLogger().log(Logger.INFO, + "ssh_dss_verify: signature "+result); + } + } + else if(alg.equals("ecdsa-sha2-nistp256") || + alg.equals("ecdsa-sha2-nistp384") || + alg.equals("ecdsa-sha2-nistp521")) { + byte[] tmp; + byte[] r; + byte[] s; + + // RFC 5656, + type=ECDSA; + key_alg_name=alg; + + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j; + j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + i++; + tmp=new byte[(j-1)/2]; + System.arraycopy(K_S, i, tmp, 0, tmp.length); i+=(j-1)/2; + r=tmp; + tmp=new byte[(j-1)/2]; + System.arraycopy(K_S, i, tmp, 0, tmp.length); i+=(j-1)/2; + s=tmp; + + SignatureECDSA sig=null; + try{ + Class c=Class.forName(session.getConfig("signature.ecdsa")); + sig=(SignatureECDSA)(c.newInstance()); + sig.init(); + } + catch(Exception e){ + System.err.println(e); + } + + sig.setPubKey(r, s); + + sig.update(H); + + result=sig.verify(sig_of_H); + } + else{ + System.err.println("unknown alg"); + } + + return result; + } + +} diff --git a/src/main/java/com/jcraft/jsch/KeyPair.java b/src/main/java/com/jcraft/jsch/KeyPair.java new file mode 100644 index 0000000..3e4e80e --- /dev/null +++ b/src/main/java/com/jcraft/jsch/KeyPair.java @@ -0,0 +1,1255 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +import java.io.FileOutputStream; +import java.io.FileInputStream; +import java.io.File; +import java.io.IOException; + +public abstract class KeyPair{ + public static final int ERROR=0; + public static final int DSA=1; + public static final int RSA=2; + public static final int ECDSA=3; + public static final int UNKNOWN=4; + + static final int VENDOR_OPENSSH=0; + static final int VENDOR_FSECURE=1; + static final int VENDOR_PUTTY=2; + static final int VENDOR_PKCS8=3; + + int vendor=VENDOR_OPENSSH; + + private static final byte[] cr=Util.str2byte("\n"); + + public static KeyPair genKeyPair(JSch jsch, int type) throws JSchException{ + return genKeyPair(jsch, type, 1024); + } + public static KeyPair genKeyPair(JSch jsch, int type, int key_size) throws JSchException{ + KeyPair kpair=null; + if(type==DSA){ kpair=new KeyPairDSA(jsch); } + else if(type==RSA){ kpair=new KeyPairRSA(jsch); } + else if(type==ECDSA){ kpair=new KeyPairECDSA(jsch); } + if(kpair!=null){ + kpair.generate(key_size); + } + return kpair; + } + + abstract void generate(int key_size) throws JSchException; + + abstract byte[] getBegin(); + abstract byte[] getEnd(); + abstract int getKeySize(); + + public abstract byte[] getSignature(byte[] data); + public abstract Signature getVerifier(); + + public abstract byte[] forSSHAgent() throws JSchException; + + public String getPublicKeyComment(){ + return publicKeyComment; + } + + public void setPublicKeyComment(String publicKeyComment){ + this.publicKeyComment = publicKeyComment; + } + + protected String publicKeyComment = "no comment"; + + JSch jsch=null; + private Cipher cipher; + private HASH hash; + private Random random; + + private byte[] passphrase; + + public KeyPair(JSch jsch){ + this.jsch=jsch; + } + + static byte[][] header={Util.str2byte("Proc-Type: 4,ENCRYPTED"), + Util.str2byte("DEK-Info: DES-EDE3-CBC,")}; + + abstract byte[] getPrivateKey(); + + /** + * Writes the plain private key to the given output stream. + * @param out output stream + * @see #writePrivateKey(java.io.OutputStream out, byte[] passphrase) + */ + public void writePrivateKey(java.io.OutputStream out){ + this.writePrivateKey(out, null); + } + + /** + * Writes the cyphered private key to the given output stream. + * @param out output stream + * @param passphrase a passphrase to encrypt the private key + */ + public void writePrivateKey(java.io.OutputStream out, byte[] passphrase){ + if(passphrase == null) + passphrase = this.passphrase; + + byte[] plain=getPrivateKey(); + byte[][] _iv=new byte[1][]; + byte[] encoded=encrypt(plain, _iv, passphrase); + if(encoded!=plain) + Util.bzero(plain); + byte[] iv=_iv[0]; + byte[] prv=Util.toBase64(encoded, 0, encoded.length); + + try{ + out.write(getBegin()); out.write(cr); + if(passphrase!=null){ + out.write(header[0]); out.write(cr); + out.write(header[1]); + for(int i=0; i>>4)&0x0f))); + out.write(b2a((byte)(iv[i]&0x0f))); + } + out.write(cr); + out.write(cr); + } + int i=0; + while(i0){ + len>>>=8; + i++; + } + return i; + } + + int writeLength(byte[] data, int index, int len){ + int i=countLength(len)-1; + if(i==0){ + data[index++]=(byte)len; + return index; + } + data[index++]=(byte)(0x80|i); + int j=index+i; + while(i>0){ + data[index+i-1]=(byte)(len&0xff); + len>>>=8; + i--; + } + return j; + } + + private Random genRandom(){ + if(random==null){ + try{ + Class c=Class.forName(jsch.getConfig("random")); + random=(Random)(c.newInstance()); + } + catch(Exception e){ System.err.println("connect: random "+e); } + } + return random; + } + + private HASH genHash(){ + try{ + Class c=Class.forName(jsch.getConfig("md5")); + hash=(HASH)(c.newInstance()); + hash.init(); + } + catch(Exception e){ + } + return hash; + } + private Cipher genCipher(){ + try{ + Class c; + c=Class.forName(jsch.getConfig("3des-cbc")); + cipher=(Cipher)(c.newInstance()); + } + catch(Exception e){ + } + return cipher; + } + + /* + hash is MD5 + h(0) <- hash(passphrase, iv); + h(n) <- hash(h(n-1), passphrase, iv); + key <- (h(0),...,h(n))[0,..,key.length]; + */ + synchronized byte[] genKey(byte[] passphrase, byte[] iv){ + if(cipher==null) cipher=genCipher(); + if(hash==null) hash=genHash(); + + byte[] key=new byte[cipher.getBlockSize()]; + int hsize=hash.getBlockSize(); + byte[] hn=new byte[key.length/hsize*hsize+ + (key.length%hsize==0?0:hsize)]; + try{ + byte[] tmp=null; + if(vendor==VENDOR_OPENSSH){ + for(int index=0; index+hsize<=hn.length;){ + if(tmp!=null){ hash.update(tmp, 0, tmp.length); } + hash.update(passphrase, 0, passphrase.length); + hash.update(iv, 0, iv.length > 8 ? 8: iv.length); + tmp=hash.digest(); + System.arraycopy(tmp, 0, hn, index, tmp.length); + index+=tmp.length; + } + System.arraycopy(hn, 0, key, 0, key.length); + } + else if(vendor==VENDOR_FSECURE){ + for(int index=0; index+hsize<=hn.length;){ + if(tmp!=null){ hash.update(tmp, 0, tmp.length); } + hash.update(passphrase, 0, passphrase.length); + tmp=hash.digest(); + System.arraycopy(tmp, 0, hn, index, tmp.length); + index+=tmp.length; + } + System.arraycopy(hn, 0, key, 0, key.length); + } + else if(vendor==VENDOR_PUTTY){ + Class c=Class.forName((String)jsch.getConfig("sha-1")); + HASH sha1=(HASH)(c.newInstance()); + tmp = new byte[4]; + key = new byte[20*2]; + for(int i = 0; i < 2; i++){ + sha1.init(); + tmp[3]=(byte)i; + sha1.update(tmp, 0, tmp.length); + sha1.update(passphrase, 0, passphrase.length); + System.arraycopy(sha1.digest(), 0, key, i*20, 20); + } + } + } + catch(Exception e){ + System.err.println(e); + } + return key; + } + + /** + * @deprecated use #writePrivateKey(java.io.OutputStream out, byte[] passphrase) + */ + public void setPassphrase(String passphrase){ + if(passphrase==null || passphrase.length()==0){ + setPassphrase((byte[])null); + } + else{ + setPassphrase(Util.str2byte(passphrase)); + } + } + + /** + * @deprecated use #writePrivateKey(String name, byte[] passphrase) + */ + public void setPassphrase(byte[] passphrase){ + if(passphrase!=null && passphrase.length==0) + passphrase=null; + this.passphrase=passphrase; + } + + protected boolean encrypted=false; + protected byte[] data=null; + private byte[] iv=null; + private byte[] publickeyblob=null; + + public boolean isEncrypted(){ return encrypted; } + public boolean decrypt(String _passphrase){ + if(_passphrase==null || _passphrase.length()==0){ + return !encrypted; + } + return decrypt(Util.str2byte(_passphrase)); + } + public boolean decrypt(byte[] _passphrase){ + + if(!encrypted){ + return true; + } + if(_passphrase==null){ + return !encrypted; + } + byte[] bar=new byte[_passphrase.length]; + System.arraycopy(_passphrase, 0, bar, 0, bar.length); + _passphrase=bar; + byte[] foo=decrypt(data, _passphrase, iv); + Util.bzero(_passphrase); + if(parse(foo)){ + encrypted=false; + } + return !encrypted; + } + + public static KeyPair load(JSch jsch, String prvkey) throws JSchException{ + String pubkey=prvkey+".pub"; + if(!new File(pubkey).exists()){ + pubkey=null; + } + return load(jsch, prvkey, pubkey); + } + public static KeyPair load(JSch jsch, String prvfile, String pubfile) throws JSchException{ + + byte[] prvkey=null; + byte[] pubkey=null; + + try{ + prvkey = Util.fromFile(prvfile); + } + catch(IOException e){ + throw new JSchException(e.toString(), (Throwable)e); + } + + String _pubfile=pubfile; + if(pubfile==null){ + _pubfile=prvfile+".pub"; + } + + try{ + pubkey = Util.fromFile(_pubfile); + } + catch(IOException e){ + if(pubfile!=null){ + throw new JSchException(e.toString(), (Throwable)e); + } + } + + try { + return load(jsch, prvkey, pubkey); + } + finally { + Util.bzero(prvkey); + } + } + + public static KeyPair load(JSch jsch, byte[] prvkey, byte[] pubkey) throws JSchException{ + + byte[] iv=new byte[8]; // 8 + boolean encrypted=true; + byte[] data=null; + + byte[] publickeyblob=null; + + int type=ERROR; + int vendor=VENDOR_OPENSSH; + String publicKeyComment = ""; + Cipher cipher=null; + + // prvkey from "ssh-add" command on the remote. + if(pubkey==null && + prvkey!=null && + (prvkey.length>11 && + prvkey[0]==0 && prvkey[1]==0 && prvkey[2]==0 && + (prvkey[3]==7 || prvkey[3]==19))){ + + Buffer buf=new Buffer(prvkey); + buf.skip(prvkey.length); // for using Buffer#available() + String _type = new String(buf.getString()); // ssh-rsa or ssh-dss + buf.rewind(); + + KeyPair kpair=null; + if(_type.equals("ssh-rsa")){ + kpair=KeyPairRSA.fromSSHAgent(jsch, buf); + } + else if(_type.equals("ssh-dss")){ + kpair=KeyPairDSA.fromSSHAgent(jsch, buf); + } + else if(_type.equals("ecdsa-sha2-nistp256") || + _type.equals("ecdsa-sha2-nistp384") || + _type.equals("ecdsa-sha2-nistp512")){ + kpair=KeyPairECDSA.fromSSHAgent(jsch, buf); + } + else{ + throw new JSchException("privatekey: invalid key "+new String(prvkey, 4, 7)); + } + return kpair; + } + + try{ + byte[] buf=prvkey; + + if(buf!=null){ + KeyPair ppk = loadPPK(jsch, buf); + if(ppk !=null) + return ppk; + } + + int len = (buf!=null ? buf.length : 0); + int i=0; + + // skip garbage lines. + while(i= len) + throw new JSchException("invalid privatekey: "+prvkey); + if(buf[i]=='D'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=DSA; } + else if(buf[i]=='R'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=RSA; } + else if(buf[i]=='E'&& buf[i+1]=='C'){ type=ECDSA; } + else if(buf[i]=='S'&& buf[i+1]=='S'&& buf[i+2]=='H'){ // FSecure + type=UNKNOWN; + vendor=VENDOR_FSECURE; + } + else if(i+6 < len && + buf[i]=='P' && buf[i+1]=='R' && + buf[i+2]=='I' && buf[i+3]=='V' && + buf[i+4]=='A' && buf[i+5]=='T' && buf[i+6]=='E'){ + type=UNKNOWN; + vendor=VENDOR_PKCS8; + encrypted=false; + i+=3; + } + else if(i+8 < len && + buf[i]=='E' && buf[i+1]=='N' && + buf[i+2]=='C' && buf[i+3]=='R' && + buf[i+4]=='Y' && buf[i+5]=='P' && buf[i+6]=='T' && + buf[i+7]=='E' && buf[i+8]=='D'){ + type=UNKNOWN; + vendor=VENDOR_PKCS8; + i+=5; + } + else{ + throw new JSchException("invalid privatekey: "+prvkey); + } + i+=3; + continue; + } + if(buf[i]=='A'&& i+7 0) + data=Util.fromBase64(_buf, start, i-start); + + Util.bzero(_buf); + } + + if(data!=null && + data.length>4 && // FSecure + data[0]==(byte)0x3f && + data[1]==(byte)0x6f && + data[2]==(byte)0xf9 && + data[3]==(byte)0xeb){ + + Buffer _buf=new Buffer(data); + _buf.getInt(); // 0x3f6ff9be + _buf.getInt(); + byte[]_type=_buf.getString(); + //System.err.println("type: "+new String(_type)); + String _cipher=Util.byte2str(_buf.getString()); + //System.err.println("cipher: "+_cipher); + if(_cipher.equals("3des-cbc")){ + _buf.getInt(); + byte[] foo=new byte[data.length-_buf.getOffSet()]; + _buf.getByte(foo); + data=foo; + encrypted=true; + throw new JSchException("unknown privatekey format: "+prvkey); + } + else if(_cipher.equals("none")){ + _buf.getInt(); + _buf.getInt(); + + encrypted=false; + + byte[] foo=new byte[data.length-_buf.getOffSet()]; + _buf.getByte(foo); + data=foo; + } + } + + if(pubkey!=null){ + try{ + buf=pubkey; + len=buf.length; + if(buf.length>4 && // FSecure's public key + buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){ + + boolean valid=true; + i=0; + do{i++;}while(buf.length>i && buf[i]!=0x0a); + if(buf.length<=i) {valid=false;} + + while(valid){ + if(buf[i]==0x0a){ + boolean inheader=false; + for(int j=i+1; j7){ + if(buf[4]=='d'){ type=DSA; } + else if(buf[4]=='r'){ type=RSA; } + } + i=0; + while(i0 && buf[i-1]==0x0d) i--; + if(start7){ + type=ECDSA; + } + i=0; + while(i0 && buf[i-1]==0x0d) i--; + if(start0){ + while(buf.length > i){ + if(buf[i++] == 0x0d){ + if(data == null){ + data = new byte[i - index - 1]; + System.arraycopy(buf, index, data, 0, i - index - 1); + } + else { + byte[] tmp = new byte[data.length + i - index - 1]; + System.arraycopy(data, 0, tmp, 0, data.length); + System.arraycopy(buf, index, tmp, data.length, i - index -1); + for(int j = 0; j < data.length; j++) data[j] = 0; // clear + data = tmp; + } + break; + } + } + if(buf[i]==0x0a) + i++; + index=i; + } + + if(data != null) + buffer.index = index; + + return data; + } + + private static boolean parseHeader(Buffer buffer, java.util.Hashtable v){ + byte[] buf = buffer.buffer; + int index = buffer.index; + String key = null; + String value = null; + for(int i = index; i < buf.length; i++){ + if(buf[i] == 0x0d){ + break; + } + if(buf[i] == ':'){ + key = new String(buf, index, i - index); + i++; + if(i < buf.length && buf[i] == ' '){ + i++; + } + index = i; + break; + } + } + + if(key == null) + return false; + + for(int i = index; i < buf.length; i++){ + if(buf[i] == 0x0d){ + value = new String(buf, index, i - index); + i++; + if(i < buf.length && buf[i] == 0x0a){ + i++; + } + index = i; + break; + } + } + + if(value != null){ + v.put(key, value); + buffer.index = index; + } + + return (key != null && value != null); + } + + void copy(KeyPair kpair){ + this.publickeyblob=kpair.publickeyblob; + this.vendor=kpair.vendor; + this.publicKeyComment=kpair.publicKeyComment; + this.cipher=kpair.cipher; + } + + class ASN1Exception extends Exception { + } + + class ASN1 { + byte[] buf; + int start; + int length; + ASN1(byte[] buf) throws ASN1Exception { + this(buf, 0, buf.length); + } + ASN1(byte[] buf, int start, int length) throws ASN1Exception { + this.buf = buf; + this.start = start; + this.length = length; + if(start+length>buf.length) + throw new ASN1Exception(); + } + int getType() { + return buf[start]&0xff; + } + boolean isSEQUENCE() { + return getType()==(0x30&0xff); + } + boolean isINTEGER() { + return getType()==(0x02&0xff); + } + boolean isOBJECT() { + return getType()==(0x06&0xff); + } + boolean isOCTETSTRING() { + return getType()==(0x04&0xff); + } + private int getLength(int[] indexp) { + int index=indexp[0]; + int length=buf[index++]&0xff; + if((length&0x80)!=0) { + int foo=length&0x7f; length=0; + while(foo-->0){ length=(length<<8)+(buf[index++]&0xff); } + } + indexp[0]=index; + return length; + } + byte[] getContent() { + int[] indexp=new int[1]; + indexp[0]=start+1; + int length = getLength(indexp); + int index=indexp[0]; + byte[] tmp = new byte[length]; + System.arraycopy(buf, index, tmp, 0, tmp.length); + return tmp; + } + ASN1[] getContents() throws ASN1Exception { + int typ = buf[start]; + int[] indexp=new int[1]; + indexp[0]=start+1; + int length = getLength(indexp); + if(typ == 0x05){ + return new ASN1[0]; + } + int index=indexp[0]; + java.util.Vector values = new java.util.Vector(); + while(length>0) { + index++; length--; + int tmp=index; + indexp[0]=index; + int l=getLength(indexp); + index=indexp[0]; + length-=(index-tmp); + values.addElement(new ASN1(buf, tmp-1, 1+(index-tmp)+l)); + index+=l; + length-=l; + } + ASN1[] result = new ASN1[values.size()]; + for(int i = 0; i =64 ? 521 : + (prv_array.length>=48 ? 384 : 256); + } + + void generate(int key_size) throws JSchException{ + this.key_size=key_size; + try{ + Class c=Class.forName(jsch.getConfig("keypairgen.ecdsa")); + KeyPairGenECDSA keypairgen=(KeyPairGenECDSA)(c.newInstance()); + keypairgen.init(key_size); + prv_array=keypairgen.getD(); + r_array=keypairgen.getR(); + s_array=keypairgen.getS(); + name=Util.str2byte(names[prv_array.length>=64 ? 2 : + (prv_array.length>=48 ? 1 : 0)]); + keypairgen=null; + } + catch(Exception e){ + if(e instanceof Throwable) + throw new JSchException(e.toString(), (Throwable)e); + throw new JSchException(e.toString()); + } + } + + private static final byte[] begin = + Util.str2byte("-----BEGIN EC PRIVATE KEY-----"); + private static final byte[] end = + Util.str2byte("-----END EC PRIVATE KEY-----"); + + byte[] getBegin(){ return begin; } + byte[] getEnd(){ return end; } + + byte[] getPrivateKey(){ + + byte[] tmp = new byte[1]; tmp[0]=1; + + byte[] oid = oids[ + (r_array.length>=64) ? 2 : + ((r_array.length>=48) ? 1 : 0) + ]; + + byte[] point = toPoint(r_array, s_array); + + int bar = ((point.length+1)&0x80)==0 ? 3 : 4; + byte[] foo = new byte[point.length+bar]; + System.arraycopy(point, 0, foo, bar, point.length); + foo[0]=0x03; // BITSTRING + if(bar==3){ + foo[1]=(byte)(point.length+1); + } + else { + foo[1]=(byte)0x81; + foo[2]=(byte)(point.length+1); + } + point = foo; + + int content= + 1+countLength(tmp.length) + tmp.length + + 1+countLength(prv_array.length) + prv_array.length + + 1+countLength(oid.length) + oid.length + + 1+countLength(point.length) + point.length; + + int total= + 1+countLength(content)+content; // SEQUENCE + + byte[] plain=new byte[total]; + int index=0; + index=writeSEQUENCE(plain, index, content); + index=writeINTEGER(plain, index, tmp); + index=writeOCTETSTRING(plain, index, prv_array); + index=writeDATA(plain, (byte)0xa0, index, oid); + index=writeDATA(plain, (byte)0xa1, index, point); + + return plain; + } + + boolean parse(byte[] plain){ + try{ + + if(vendor==VENDOR_FSECURE){ + /* + if(plain[0]!=0x30){ // FSecure + return true; + } + return false; + */ + return false; + } + else if(vendor==VENDOR_PUTTY){ + /* + Buffer buf=new Buffer(plain); + buf.skip(plain.length); + + try { + byte[][] tmp = buf.getBytes(1, ""); + prv_array = tmp[0]; + } + catch(JSchException e){ + return false; + } + + return true; + */ + return false; + } + + int index=0; + int length=0; + + if(plain[index]!=0x30)return false; + index++; // SEQUENCE + length=plain[index++]&0xff; + if((length&0x80)!=0){ + int foo=length&0x7f; length=0; + while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } + } + + if(plain[index]!=0x02)return false; + index++; // INTEGER + + length=plain[index++]&0xff; + if((length&0x80)!=0){ + int foo=length&0x7f; length=0; + while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } + } + + index+=length; + index++; // 0x04 + + length=plain[index++]&0xff; + if((length&0x80)!=0){ + int foo=length&0x7f; length=0; + while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } + } + + prv_array=new byte[length]; + System.arraycopy(plain, index, prv_array, 0, length); + + index+=length; + + index++; // 0xa0 + + length=plain[index++]&0xff; + if((length&0x80)!=0){ + int foo=length&0x7f; length=0; + while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } + } + + byte[] oid_array=new byte[length]; + System.arraycopy(plain, index, oid_array, 0, length); + index+=length; + + for(int i = 0; i0){ length=(length<<8)+(plain[index++]&0xff); } + } + + byte[] Q_array=new byte[length]; + System.arraycopy(plain, index, Q_array, 0, length); + index+=length; + + byte[][] tmp = fromPoint(Q_array); + r_array = tmp[0]; + s_array = tmp[1]; + + if(prv_array!=null) + key_size = prv_array.length>=64 ? 521 : + (prv_array.length>=48 ? 384 : 256); + } + catch(Exception e){ + //System.err.println(e); + //e.printStackTrace(); + return false; + } + return true; + } + + public byte[] getPublicKeyBlob(){ + byte[] foo = super.getPublicKeyBlob(); + + if(foo!=null) return foo; + + if(r_array==null) return null; + + byte[][] tmp = new byte[3][]; + tmp[0] = Util.str2byte("ecdsa-sha2-"+new String(name)); + tmp[1] = name; + tmp[2] = new byte[1+r_array.length+s_array.length]; + tmp[2][0] = 4; // POINT_CONVERSION_UNCOMPRESSED + System.arraycopy(r_array, 0, tmp[2], 1, r_array.length); + System.arraycopy(s_array, 0, tmp[2], 1+r_array.length, s_array.length); + + return Buffer.fromBytes(tmp).buffer; + } + + byte[] getKeyTypeName(){ + return Util.str2byte("ecdsa-sha2-"+new String(name)); + } + public int getKeyType(){ + return ECDSA; + } + public int getKeySize(){ + return key_size; + } + + public byte[] getSignature(byte[] data){ + try{ + Class c=Class.forName((String)jsch.getConfig("signature.ecdsa")); + SignatureECDSA ecdsa=(SignatureECDSA)(c.newInstance()); + ecdsa.init(); + ecdsa.setPrvKey(prv_array); + + ecdsa.update(data); + byte[] sig = ecdsa.sign(); + + byte[][] tmp = new byte[2][]; + tmp[0] = Util.str2byte("ecdsa-sha2-"+new String(name)); + tmp[1] = sig; + return Buffer.fromBytes(tmp).buffer; + } + catch(Exception e){ + //System.err.println("e "+e); + } + return null; + } + + public Signature getVerifier(){ + try{ + Class c=Class.forName((String)jsch.getConfig("signature.ecdsa")); + final SignatureECDSA ecdsa=(SignatureECDSA)(c.newInstance()); + ecdsa.init(); + + if(r_array == null && s_array == null && getPublicKeyBlob()!=null){ + Buffer buf = new Buffer(getPublicKeyBlob()); + buf.getString(); // ecdsa-sha2-nistp256 + buf.getString(); // nistp256 + byte[][] tmp = fromPoint(buf.getString()); + r_array = tmp[0]; + s_array = tmp[1]; + } + ecdsa.setPubKey(r_array, s_array); + return ecdsa; + } + catch(Exception e){ + //System.err.println("e "+e); + } + return null; + } + + static KeyPair fromSSHAgent(JSch jsch, Buffer buf) throws JSchException { + + byte[][] tmp = buf.getBytes(5, "invalid key format"); + + byte[] name = tmp[1]; // nistp256 + byte[][] foo = fromPoint(tmp[2]); + byte[] r_array = foo[0]; + byte[] s_array = foo[1]; + + byte[] prv_array = tmp[3]; + KeyPairECDSA kpair = new KeyPairECDSA(jsch, + name, + r_array, s_array, + prv_array); + kpair.publicKeyComment = new String(tmp[4]); + kpair.vendor=VENDOR_OPENSSH; + return kpair; + } + + public byte[] forSSHAgent() throws JSchException { + if(isEncrypted()){ + throw new JSchException("key is encrypted."); + } + Buffer buf = new Buffer(); + buf.putString(Util.str2byte("ecdsa-sha2-"+new String(name))); + buf.putString(name); + buf.putString(toPoint(r_array, s_array)); + buf.putString(prv_array); + buf.putString(Util.str2byte(publicKeyComment)); + byte[] result = new byte[buf.getLength()]; + buf.getByte(result, 0, result.length); + return result; + } + + static byte[] toPoint(byte[] r_array, byte[] s_array) { + byte[] tmp = new byte[1+r_array.length+s_array.length]; + tmp[0]=0x04; + System.arraycopy(r_array, 0, tmp, 1, r_array.length); + System.arraycopy(s_array, 0, tmp, 1+r_array.length, s_array.length); + return tmp; + } + + static byte[][] fromPoint(byte[] point) { + int i = 0; + while(point[i]!=4) i++; + i++; + byte[][] tmp = new byte[2][]; + byte[] r_array = new byte[(point.length-i)/2]; + byte[] s_array = new byte[(point.length-i)/2]; + // point[0] == 0x04 == POINT_CONVERSION_UNCOMPRESSED + System.arraycopy(point, i, r_array, 0, r_array.length); + System.arraycopy(point, i+r_array.length, s_array, 0, s_array.length); + tmp[0] = r_array; + tmp[1] = s_array; + + return tmp; + } + + public void dispose(){ + super.dispose(); + Util.bzero(prv_array); + } +} diff --git a/src/com/jcraft/jsch/KeyPairGenDSA.java b/src/main/java/com/jcraft/jsch/KeyPairGenDSA.java similarity index 96% rename from src/com/jcraft/jsch/KeyPairGenDSA.java rename to src/main/java/com/jcraft/jsch/KeyPairGenDSA.java index 1656163..2bd78b2 100644 --- a/src/com/jcraft/jsch/KeyPairGenDSA.java +++ b/src/main/java/com/jcraft/jsch/KeyPairGenDSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/com/jcraft/jsch/KeyPairGenECDSA.java b/src/main/java/com/jcraft/jsch/KeyPairGenECDSA.java new file mode 100644 index 0000000..30f00c7 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/KeyPairGenECDSA.java @@ -0,0 +1,37 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +public interface KeyPairGenECDSA{ + void init(int key_size) throws Exception; + byte[] getD(); + byte[] getR(); + byte[] getS(); +} diff --git a/src/com/jcraft/jsch/KeyPairGenRSA.java b/src/main/java/com/jcraft/jsch/KeyPairGenRSA.java similarity index 96% rename from src/com/jcraft/jsch/KeyPairGenRSA.java rename to src/main/java/com/jcraft/jsch/KeyPairGenRSA.java index eb2a5f3..0d00eef 100644 --- a/src/com/jcraft/jsch/KeyPairGenRSA.java +++ b/src/main/java/com/jcraft/jsch/KeyPairGenRSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java b/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java new file mode 100644 index 0000000..d9a3da1 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java @@ -0,0 +1,363 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2013-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +import java.util.Vector; +import java.math.BigInteger; + +public class KeyPairPKCS8 extends KeyPair { + private static final byte[] rsaEncryption = { + (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, + (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01 + }; + + private static final byte[] dsaEncryption = { + (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0xce, + (byte)0x38, (byte)0x04, (byte)0x1 + }; + + private static final byte[] pbes2 = { + (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, + (byte)0x0d, (byte)0x01, (byte)0x05, (byte)0x0d + }; + + private static final byte[] pbkdf2 = { + (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, + (byte)0x0d, (byte)0x01, (byte)0x05, (byte)0x0c + }; + + private static final byte[] aes128cbc = { + (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65, + (byte)0x03, (byte)0x04, (byte)0x01, (byte)0x02 + }; + + private static final byte[] aes192cbc = { + (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65, + (byte)0x03, (byte)0x04, (byte)0x01, (byte)0x16 + }; + + private static final byte[] aes256cbc = { + (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65, + (byte)0x03, (byte)0x04, (byte)0x01, (byte)0x2a + }; + + private static final byte[] pbeWithMD5AndDESCBC = { + (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, + (byte)0x0d, (byte)0x01, (byte)0x05, (byte)0x03 + }; + + private KeyPair kpair = null; + + public KeyPairPKCS8(JSch jsch){ + super(jsch); + } + + void generate(int key_size) throws JSchException{ + } + + private static final byte[] begin=Util.str2byte("-----BEGIN DSA PRIVATE KEY-----"); + private static final byte[] end=Util.str2byte("-----END DSA PRIVATE KEY-----"); + + byte[] getBegin(){ return begin; } + byte[] getEnd(){ return end; } + + byte[] getPrivateKey(){ + return null; + } + + boolean parse(byte[] plain){ + + /* from RFC5208 + PrivateKeyInfo ::= SEQUENCE { + version Version, + privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + privateKey PrivateKey, + attributes [0] IMPLICIT Attributes OPTIONAL + } + Version ::= INTEGER + PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + PrivateKey ::= OCTET STRING + Attributes ::= SET OF Attribute + } + */ + + try{ + Vector values = new Vector(); + + ASN1[] contents = null; + ASN1 asn1 = new ASN1(plain); + contents = asn1.getContents(); + + ASN1 privateKeyAlgorithm = contents[1]; + ASN1 privateKey = contents[2]; + + contents = privateKeyAlgorithm.getContents(); + byte[] privateKeyAlgorithmID = contents[0].getContent(); + contents = contents[1].getContents(); + if(contents.length>0){ + for(int i = 0; i < contents.length; i++){ + values.addElement(contents[i].getContent()); + } + } + + byte[] _data = privateKey.getContent(); + + KeyPair _kpair = null; + if(Util.array_equals(privateKeyAlgorithmID, rsaEncryption)){ + _kpair = new KeyPairRSA(jsch); + _kpair.copy(this); + if(_kpair.parse(_data)){ + kpair = _kpair; + } + } + else if(Util.array_equals(privateKeyAlgorithmID, dsaEncryption)){ + asn1 = new ASN1(_data); + if(values.size() == 0) { // embedded DSA parameters format + /* + SEQUENCE + SEQUENCE + INTEGER // P_array + INTEGER // Q_array + INTEGER // G_array + INTEGER // prv_array + */ + contents = asn1.getContents(); + byte[] bar = contents[1].getContent(); + contents = contents[0].getContents(); + for(int i = 0; i < contents.length; i++){ + values.addElement(contents[i].getContent()); + } + values.addElement(bar); + } + else { + /* + INTEGER // prv_array + */ + values.addElement(asn1.getContent()); + } + + byte[] P_array = (byte[])values.elementAt(0); + byte[] Q_array = (byte[])values.elementAt(1); + byte[] G_array = (byte[])values.elementAt(2); + byte[] prv_array = (byte[])values.elementAt(3); + // Y = g^X mode p + byte[] pub_array = + (new BigInteger(G_array)). + modPow(new BigInteger(prv_array), new BigInteger(P_array)). + toByteArray(); + + KeyPairDSA _key = new KeyPairDSA(jsch, + P_array, Q_array, G_array, + pub_array, prv_array); + plain = _key.getPrivateKey(); + + _kpair = new KeyPairDSA(jsch); + _kpair.copy(this); + if(_kpair.parse(plain)){ + kpair = _kpair; + } + } + } + catch(ASN1Exception e){ + return false; + } + catch(Exception e){ + //System.err.println(e); + return false; + } + return kpair != null; + } + + public byte[] getPublicKeyBlob(){ + return kpair.getPublicKeyBlob(); + } + + byte[] getKeyTypeName(){ return kpair.getKeyTypeName();} + public int getKeyType(){return kpair.getKeyType();} + + public int getKeySize(){ + return kpair.getKeySize(); + } + + public byte[] getSignature(byte[] data){ + return kpair.getSignature(data); + } + + public Signature getVerifier(){ + return kpair.getVerifier(); + } + + public byte[] forSSHAgent() throws JSchException { + return kpair.forSSHAgent(); + } + + public boolean decrypt(byte[] _passphrase){ + if(!isEncrypted()){ + return true; + } + if(_passphrase==null){ + return !isEncrypted(); + } + + /* + SEQUENCE + SEQUENCE + OBJECT :PBES2 + SEQUENCE + SEQUENCE + OBJECT :PBKDF2 + SEQUENCE + OCTET STRING [HEX DUMP]:E4E24ADC9C00BD4D + INTEGER :0800 + SEQUENCE + OBJECT :aes-128-cbc + OCTET STRING [HEX DUMP]:5B66E6B3BF03944C92317BC370CC3AD0 + OCTET STRING [HEX DUMP]: + +or + + SEQUENCE + SEQUENCE + OBJECT :pbeWithMD5AndDES-CBC + SEQUENCE + OCTET STRING [HEX DUMP]:DBF75ECB69E3C0FC + INTEGER :0800 + OCTET STRING [HEX DUMP] + */ + + try{ + + ASN1[] contents = null; + ASN1 asn1 = new ASN1(data); + + contents = asn1.getContents(); + + byte[] _data = contents[1].getContent(); + + ASN1 pbes = contents[0]; + contents = pbes.getContents(); + byte[] pbesid = contents[0].getContent(); + ASN1 pbesparam = contents[1]; + + byte[] salt = null; + int iterations = 0; + byte[] iv = null; + byte[] encryptfuncid = null; + + if(Util.array_equals(pbesid, pbes2)){ + contents = pbesparam.getContents(); + ASN1 pbkdf = contents[0]; + ASN1 encryptfunc = contents[1]; + contents = pbkdf.getContents(); + byte[] pbkdfid = contents[0].getContent(); + ASN1 pbkdffunc = contents[1]; + contents = pbkdffunc.getContents(); + salt = contents[0].getContent(); + iterations = + Integer.parseInt((new BigInteger(contents[1].getContent())).toString()); + + contents = encryptfunc.getContents(); + encryptfuncid = contents[0].getContent(); + iv = contents[1].getContent(); + } + else if(Util.array_equals(pbesid, pbeWithMD5AndDESCBC)){ + // not supported + return false; + } + else { + return false; + } + + Cipher cipher=getCipher(encryptfuncid); + if(cipher==null) return false; + + byte[] key=null; + try{ + Class c=Class.forName((String)jsch.getConfig("pbkdf")); + PBKDF tmp=(PBKDF)(c.newInstance()); + key = tmp.getKey(_passphrase, salt, iterations, cipher.getBlockSize()); + } + catch(Exception ee){ + } + + if(key==null){ + return false; + } + + cipher.init(Cipher.DECRYPT_MODE, key, iv); + Util.bzero(key); + byte[] plain=new byte[_data.length]; + cipher.update(_data, 0, _data.length, plain, 0); + if(parse(plain)){ + encrypted=false; + return true; + } + } + catch(ASN1Exception e){ + // System.err.println(e); + } + catch(Exception e){ + // System.err.println(e); + } + + return false; + } + + Cipher getCipher(byte[] id){ + Cipher cipher=null; + String name = null; + try{ + if(Util.array_equals(id, aes128cbc)){ + name="aes128-cbc"; + } + else if(Util.array_equals(id, aes192cbc)){ + name="aes192-cbc"; + } + else if(Util.array_equals(id, aes256cbc)){ + name="aes256-cbc"; + } + Class c=Class.forName((String)jsch.getConfig(name)); + cipher=(Cipher)(c.newInstance()); + } + catch(Exception e){ + if(JSch.getLogger().isEnabled(Logger.FATAL)){ + String message=""; + if(name==null){ + message="unknown oid: "+Util.toHex(id); + } + else { + message="function "+name+" is not supported"; + } + JSch.getLogger().log(Logger.FATAL, "PKCS8: "+message); + } + } + return cipher; + } +} diff --git a/src/com/jcraft/jsch/KeyPairRSA.java b/src/main/java/com/jcraft/jsch/KeyPairRSA.java similarity index 61% rename from src/com/jcraft/jsch/KeyPairRSA.java rename to src/main/java/com/jcraft/jsch/KeyPairRSA.java index 9f52f28..2111cd3 100644 --- a/src/com/jcraft/jsch/KeyPairRSA.java +++ b/src/main/java/com/jcraft/jsch/KeyPairRSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -29,22 +29,36 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING package com.jcraft.jsch; +import java.math.BigInteger; + public class KeyPairRSA extends KeyPair{ - private byte[] prv_array; - private byte[] pub_array; - private byte[] n_array; + private byte[] n_array; // modulus p multiply q + private byte[] pub_array; // e + private byte[] prv_array; // d e^-1 mod (p-1)(q-1) private byte[] p_array; // prime p private byte[] q_array; // prime q - private byte[] ep_array; // prime exponent p - private byte[] eq_array; // prime exponent q - private byte[] c_array; // coefficient + private byte[] ep_array; // prime exponent p dmp1 == prv mod (p-1) + private byte[] eq_array; // prime exponent q dmq1 == prv mod (q-1) + private byte[] c_array; // coefficient iqmp == modinv(q, p) == q^-1 mod p - //private int key_size=0; private int key_size=1024; public KeyPairRSA(JSch jsch){ + this(jsch, null, null, null); + } + + public KeyPairRSA(JSch jsch, + byte[] n_array, + byte[] pub_array, + byte[] prv_array){ super(jsch); + this.n_array = n_array; + this.pub_array = pub_array; + this.prv_array = prv_array; + if(n_array!=null){ + key_size = (new java.math.BigInteger(n_array)).bitLength(); + } } void generate(int key_size) throws JSchException{ @@ -110,17 +124,32 @@ byte[] getPrivateKey(){ } boolean parse(byte [] plain){ - /* - byte[] p_array; - byte[] q_array; - byte[] dmp1_array; - byte[] dmq1_array; - byte[] iqmp_array; - */ + try{ int index=0; int length=0; + if(vendor==VENDOR_PUTTY){ + Buffer buf = new Buffer(plain); + buf.skip(plain.length); + + try { + byte[][] tmp = buf.getBytes(4, ""); + prv_array = tmp[0]; + p_array = tmp[1]; + q_array = tmp[2]; + c_array = tmp[3]; + } + catch(JSchException e){ + return false; + } + + getEPArray(); + getEQArray(); + + return true; + } + if(vendor==VENDOR_FSECURE){ if(plain[index]!=0x30){ // FSecure Buffer buf=new Buffer(plain); @@ -130,11 +159,35 @@ boolean parse(byte [] plain){ byte[] u_array=buf.getMPIntBits(); p_array=buf.getMPIntBits(); q_array=buf.getMPIntBits(); + if(n_array!=null){ + key_size = (new java.math.BigInteger(n_array)).bitLength(); + } + + getEPArray(); + getEQArray(); + getCArray(); + return true; } return false; } + /* + Key must be in the following ASN.1 DER encoding, + RSAPrivateKey ::= SEQUENCE { + version Version, + modulus INTEGER, -- n + publicExponent INTEGER, -- e + privateExponent INTEGER, -- d + prime1 INTEGER, -- p + prime2 INTEGER, -- q + exponent1 INTEGER, -- d mod (p-1) + exponent2 INTEGER, -- d mod (q-1) + coefficient INTEGER, -- (inverse of q) mod p + otherPrimeInfos OtherPrimeInfos OPTIONAL + } + */ + index++; // SEQUENCE length=plain[index++]&0xff; if((length&0x80)!=0){ @@ -151,10 +204,6 @@ boolean parse(byte [] plain){ } index+=length; -//System.err.println("int: len="+length); -//System.err.print(Integer.toHexString(plain[index-1]&0xff)+":"); -//System.err.println(""); - index++; length=plain[index++]&0xff; if((length&0x80)!=0){ @@ -164,13 +213,7 @@ boolean parse(byte [] plain){ n_array=new byte[length]; System.arraycopy(plain, index, n_array, 0, length); index+=length; -/* -System.err.println("int: N len="+length); -for(int i=0; i=bufl || host.length()==0){ + addInvalidLine(Util.byte2str(buf, 0, bufl)); + continue loop; + } + + while(j=bufl){ addInvalidLine(Util.byte2str(buf, 0, bufl)); continue loop; } + while(j1){ + HostKey[] tmp = + getHostKey(host.substring(1, host.indexOf("]:")), type); + if(tmp.length > 0){ + HostKey[] bar = new HostKey[foo.length + tmp.length]; + System.arraycopy(foo, 0, bar, 0, foo.length); + System.arraycopy(tmp, 0, bar, foo.length, tmp.length); + foo = bar; + } } return foo; } @@ -343,7 +418,7 @@ protected void sync() throws IOException { } protected synchronized void sync(String foo) throws IOException { if(foo==null) return; - FileOutputStream fos=new FileOutputStream(foo); + FileOutputStream fos=new FileOutputStream(Util.checkTilde(foo)); dump(fos); fos.close(); } @@ -357,18 +432,28 @@ void dump(OutputStream out) throws IOException { for(int i=0; i0){ String data=this.host.substring(HASH_MAGIC.length()); diff --git a/src/main/java/com/jcraft/jsch/LocalIdentityRepository.java b/src/main/java/com/jcraft/jsch/LocalIdentityRepository.java new file mode 100644 index 0000000..01a37a4 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/LocalIdentityRepository.java @@ -0,0 +1,151 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2012-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +import java.util.Vector; + +class LocalIdentityRepository implements IdentityRepository { + private static final String name = "Local Identity Repository"; + + private Vector identities = new Vector(); + private JSch jsch; + + LocalIdentityRepository(JSch jsch){ + this.jsch = jsch; + } + + public String getName(){ + return name; + } + + public int getStatus(){ + return RUNNING; + } + + public synchronized Vector getIdentities() { + removeDupulicates(); + Vector v = new Vector(); + for(int i=0; i + *

  • Host
  • + *
  • User
  • + *
  • Hostname
  • + *
  • Port
  • + *
  • PreferredAuthentications
  • + *
  • IdentityFile
  • + *
  • NumberOfPasswordPrompts
  • + *
  • ConnectTimeout
  • + *
  • HostKeyAlias
  • + *
  • UserKnownHostsFile
  • + *
  • KexAlgorithms
  • + *
  • HostKeyAlgorithms
  • + *
  • Ciphers
  • + *
  • Macs
  • + *
  • Compression
  • + *
  • CompressionLevel
  • + *
  • ForwardAgent
  • + *
  • RequestTTY
  • + *
  • ServerAliveInterval
  • + *
  • LocalForward
  • + *
  • RemoteForward
  • + *
  • ClearAllForwardings
  • + * + * + * @see ConfigRepository + */ +public class OpenSSHConfig implements ConfigRepository { + + /** + * Parses the given string, and returns an instance of ConfigRepository. + * + * @param conf string, which includes OpenSSH's config + * @return an instanceof OpenSSHConfig + */ + public static OpenSSHConfig parse(String conf) throws IOException { + Reader r = new StringReader(conf); + try { + return new OpenSSHConfig(r); + } + finally { + r.close(); + } + } + + /** + * Parses the given file, and returns an instance of ConfigRepository. + * + * @param file OpenSSH's config file + * @return an instanceof OpenSSHConfig + */ + public static OpenSSHConfig parseFile(String file) throws IOException { + Reader r = new FileReader(Util.checkTilde(file)); + try { + return new OpenSSHConfig(r); + } + finally { + r.close(); + } + } + + OpenSSHConfig(Reader r) throws IOException { + _parse(r); + } + + private final Hashtable config = new Hashtable(); + private final Vector hosts = new Vector(); + + private void _parse(Reader r) throws IOException { + BufferedReader br = new BufferedReader(r); + + String host = ""; + Vector/**/ kv = new Vector(); + String l = null; + + while((l = br.readLine()) != null){ + l = l.trim(); + if(l.length() == 0 || l.startsWith("#")) + continue; + + String[] key_value = l.split("[= \t]", 2); + for(int i = 0; i < key_value.length; i++) + key_value[i] = key_value[i].trim(); + + if(key_value.length <= 1) + continue; + + if(key_value[0].equals("Host")){ + config.put(host, kv); + hosts.addElement(host); + host = key_value[1]; + kv = new Vector(); + } + else { + kv.addElement(key_value); + } + } + config.put(host, kv); + hosts.addElement(host); + } + + public Config getConfig(String host) { + return new MyConfig(host); + } + + private static final Hashtable keymap = new Hashtable(); + static { + keymap.put("kex", "KexAlgorithms"); + keymap.put("server_host_key", "HostKeyAlgorithms"); + keymap.put("cipher.c2s", "Ciphers"); + keymap.put("cipher.s2c", "Ciphers"); + keymap.put("mac.c2s", "Macs"); + keymap.put("mac.s2c", "Macs"); + keymap.put("compression.s2c", "Compression"); + keymap.put("compression.c2s", "Compression"); + keymap.put("compression_level", "CompressionLevel"); + keymap.put("MaxAuthTries", "NumberOfPasswordPrompts"); + } + + class MyConfig implements Config { + + private String host; + private Vector _configs = new Vector(); + + MyConfig(String host){ + this.host = host; + + _configs.addElement(config.get("")); + + byte[] _host = Util.str2byte(host); + if(hosts.size() > 1){ + for(int i = 1; i < hosts.size(); i++){ + String patterns[] = ((String)hosts.elementAt(i)).split("[ \t]"); + for(int j = 0; j < patterns.length; j++){ + boolean negate = false; + String foo = patterns[j].trim(); + if(foo.startsWith("!")){ + negate = true; + foo = foo.substring(1).trim(); + } + if(Util.glob(Util.str2byte(foo), _host)){ + if(!negate){ + _configs.addElement(config.get((String)hosts.elementAt(i))); + } + } + else if(negate){ + _configs.addElement(config.get((String)hosts.elementAt(i))); + } + } + } + } + } + + private String find(String key) { + if(keymap.get(key)!=null) { + key = (String)keymap.get(key); + } + key = key.toUpperCase(); + String value = null; + for(int i = 0; i < _configs.size(); i++) { + Vector v = (Vector)_configs.elementAt(i); + for(int j = 0; j < v.size(); j++) { + String[] kv = (String[])v.elementAt(j); + if(kv[0].toUpperCase().equals(key)) { + value = kv[1]; + break; + } + } + if(value != null) + break; + } + return value; + } + + private String[] multiFind(String key) { + key = key.toUpperCase(); + Vector value = new Vector(); + for(int i = 0; i < _configs.size(); i++) { + Vector v = (Vector)_configs.elementAt(i); + for(int j = 0; j < v.size(); j++) { + String[] kv = (String[])v.elementAt(j); + if(kv[0].toUpperCase().equals(key)) { + String foo = kv[1]; + if(foo != null) { + value.remove(foo); + value.addElement(foo); + } + } + } + } + String[] result = new String[value.size()]; + value.toArray(result); + return result; + } + + public String getHostname(){ return find("Hostname"); } + public String getUser(){ return find("User"); } + public int getPort(){ + String foo = find("Port"); + int port = -1; + try { + port = Integer.parseInt(foo); + } + catch(NumberFormatException e){ + // wrong format + } + return port; + } + public String getValue(String key){ + if(key.equals("compression.s2c") || + key.equals("compression.c2s")) { + String foo = find(key); + if(foo == null || foo.equals("no")) + return "none,zlib@openssh.com,zlib"; + return "zlib@openssh.com,zlib,none"; + } + return find(key); + } + public String[] getValues(String key){ return multiFind(key); } + } +} diff --git a/src/main/java/com/jcraft/jsch/PBKDF.java b/src/main/java/com/jcraft/jsch/PBKDF.java new file mode 100644 index 0000000..6910b56 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/PBKDF.java @@ -0,0 +1,34 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2013-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +public interface PBKDF { + byte[] getKey(byte[] pass, byte[] salt, int iteration, int size); +} diff --git a/src/com/jcraft/jsch/Packet.java b/src/main/java/com/jcraft/jsch/Packet.java similarity index 93% rename from src/com/jcraft/jsch/Packet.java rename to src/main/java/com/jcraft/jsch/Packet.java index 56a2dd9..3b8c50d 100644 --- a/src/com/jcraft/jsch/Packet.java +++ b/src/main/java/com/jcraft/jsch/Packet.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -68,12 +68,13 @@ void padding(int bsize){ */ } - int shift(int len, int mac){ + int shift(int len, int bsize, int mac){ int s=len+5+9; - int pad=(-s)&15; - if(pad<16)pad+=16; + int pad=(-s)&(bsize-1); + if(pad= max_auth_tries){ + if(JSch.getLogger().isEnabled(Logger.INFO)){ + JSch.getLogger().log(Logger.INFO, + "Login trials exceeds "+max_auth_tries); + } + } if(auth_cancel) throw new JSchException("Auth cancel"); throw new JSchException("Auth fail"); } - if(connectTimeout>0 || timeout>0){ + if(socket!=null && (connectTimeout>0 || timeout>0)){ socket.setSoTimeout(timeout); } @@ -475,6 +533,8 @@ public void connect(int connectTimeout) throws JSchException{ connectThread.setDaemon(daemon_thread); } connectThread.start(); + + requestPortForwarding(); } else{ // The session has been already down and @@ -484,19 +544,20 @@ public void connect(int connectTimeout) throws JSchException{ } catch(Exception e) { in_kex=false; - if(isConnected){ - try{ - packet.reset(); - buf.putByte((byte)SSH_MSG_DISCONNECT); - buf.putInt(3); - buf.putString(Util.str2byte(e.toString())); - buf.putString(Util.str2byte("en")); - write(packet); - disconnect(); - } - catch(Exception ee){ - } + try{ + if(isConnected){ + String message = e.toString(); + packet.reset(); + buf.checkFreeSize(1+4*3+message.length()+2+buffer_margin); + buf.putByte((byte)SSH_MSG_DISCONNECT); + buf.putInt(3); + buf.putString(Util.str2byte(message)); + buf.putString(Util.str2byte("en")); + write(packet); + } } + catch(Exception ee){} + try{ disconnect(); } catch(Exception ee){ } isConnected=false; //e.printStackTrace(); if(e instanceof RuntimeException) throw (RuntimeException)e; @@ -548,7 +609,8 @@ private KeyExchange receive_kexinit(Buffer buf) throws Exception { return kex; } - private boolean in_kex=false; + private volatile boolean in_kex=false; + private volatile boolean in_prompt=false; public void rekey() throws Exception { send_kexinit(); } @@ -559,15 +621,34 @@ private void send_kexinit() throws Exception { String cipherc2s=getConfig("cipher.c2s"); String ciphers2c=getConfig("cipher.s2c"); - String[] not_available=checkCiphers(getConfig("CheckCiphers")); - if(not_available!=null && not_available.length>0){ - cipherc2s=Util.diffString(cipherc2s, not_available); - ciphers2c=Util.diffString(ciphers2c, not_available); + String[] not_available_ciphers=checkCiphers(getConfig("CheckCiphers")); + if(not_available_ciphers!=null && not_available_ciphers.length>0){ + cipherc2s=Util.diffString(cipherc2s, not_available_ciphers); + ciphers2c=Util.diffString(ciphers2c, not_available_ciphers); if(cipherc2s==null || ciphers2c==null){ throw new JSchException("There are not any available ciphers."); } } + String kex=getConfig("kex"); + String[] not_available_kexes=checkKexes(getConfig("CheckKexes")); + if(not_available_kexes!=null && not_available_kexes.length>0){ + kex=Util.diffString(kex, not_available_kexes); + if(kex==null){ + throw new JSchException("There are not any available kexes."); + } + } + + String server_host_key = getConfig("server_host_key"); + String[] not_available_shks = + checkSignatures(getConfig("CheckSignatures")); + if(not_available_shks!=null && not_available_shks.length>0){ + server_host_key=Util.diffString(server_host_key, not_available_shks); + if(server_host_key==null){ + throw new JSchException("There are not any available sig algorithm."); + } + } + in_kex=true; kex_start_time=System.currentTimeMillis(); @@ -590,8 +671,8 @@ private void send_kexinit() throws Exception { synchronized(random){ random.fill(buf.buffer, buf.index, 16); buf.skip(16); } - buf.putString(Util.str2byte(getConfig("kex"))); - buf.putString(Util.str2byte(getConfig("server_host_key"))); + buf.putString(Util.str2byte(kex)); + buf.putString(Util.str2byte(server_host_key)); buf.putString(Util.str2byte(cipherc2s)); buf.putString(Util.str2byte(ciphers2c)); buf.putString(Util.str2byte(getConfig("mac.c2s"))); @@ -644,16 +725,22 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep chost=("["+chost+"]:"+port); } -// hostkey=new HostKey(chost, K_S); + HostKeyRepository hkr=getHostKeyRepository(); + + String hkh=getConfig("HashKnownHosts"); + if(hkh.equals("yes") && (hkr instanceof KnownHosts)){ + hostkey=((KnownHosts)hkr).createHashedHostKey(chost, K_S); + } + else{ + hostkey=new HostKey(chost, K_S); + } - HostKeyRepository hkr=jsch.getHostKeyRepository(); int i=0; synchronized(hkr){ i=hkr.check(chost, K_S); } boolean insert=false; - if((shkc.equals("ask") || shkc.equals("yes")) && i==HostKeyRepository.CHANGED){ String file=null; @@ -670,7 +757,7 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n"+ "Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n"+ "It is also possible that the "+key_type+" host key has just been changed.\n"+ -"The fingerprint for the "+key_type+" key sent by the remote host is\n"+ +"The fingerprint for the "+key_type+" key sent by the remote host "+chost+" is\n"+ key_fprint+".\n"+ "Please contact your system administrator.\n"+ "Add correct host key in "+file+" to get rid of this message."; @@ -690,7 +777,7 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep synchronized(hkr){ hkr.remove(chost, - (key_type.equals("DSA") ? "ssh-dss" : "ssh-rsa"), + kex.getKeyAlgorithName(), null); insert=true; } @@ -726,10 +813,32 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep insert=true; } + if(i==HostKeyRepository.OK){ + HostKey[] keys = + hkr.getHostKey(chost, kex.getKeyAlgorithName()); + String _key= Util.byte2str(Util.toBase64(K_S, 0, K_S.length)); + for(int j=0; j< keys.length; j++){ + if(keys[i].getKey().equals(_key) && + keys[j].getMarker().equals("@revoked")){ + if(userinfo!=null){ + userinfo.showMessage( +"The "+ key_type +" host key for "+ host +" is marked as revoked.\n"+ +"This could mean that a stolen key is being used to "+ +"impersonate this host."); + } + if(JSch.getLogger().isEnabled(Logger.INFO)){ + JSch.getLogger().log(Logger.INFO, + "Host '"+host+"' has provided revoked key."); + } + throw new JSchException("revoked HostKey: "+host); + } + } + } + if(i==HostKeyRepository.OK && JSch.getLogger().isEnabled(Logger.INFO)){ JSch.getLogger().log(Logger.INFO, - "Host '"+host+"' is known and mathces the "+key_type+" host key"); + "Host '"+host+"' is known and matches the "+key_type+" host key"); } if(insert && @@ -738,21 +847,11 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep "Permanently added '"+host+"' ("+key_type+") to the list of known hosts."); } - String hkh=getConfig("HashKnownHosts"); - if(hkh.equals("yes") && (hkr instanceof KnownHosts)){ - hostkey=((KnownHosts)hkr).createHashedHostKey(chost, K_S); - } - else{ - hostkey=new HostKey(chost, K_S); - } - if(insert){ synchronized(hkr){ hkr.add(hostkey, userinfo); } - } - } //public void start(){ (new Thread(this)).start(); } @@ -765,6 +864,9 @@ public Channel openChannel(String type) throws JSchException{ Channel channel=Channel.getChannel(type); addChannel(channel); channel.init(); + if(channel instanceof ChannelSession){ + applyConfigChannel((ChannelSession)channel); + } return channel; } catch(Exception e){ @@ -781,8 +883,10 @@ public void encode(Packet packet) throws Exception{ //Thread.dumpStack(); //} if(deflater!=null){ - packet.buffer.index=deflater.compress(packet.buffer.buffer, - 5, packet.buffer.index); + compress_len[0]=packet.buffer.index; + packet.buffer.buffer=deflater.compress(packet.buffer.buffer, + 5, compress_len); + packet.buffer.index=compress_len[0]; } if(c2scipher!=null){ //packet.padding(c2scipher.getIVSize()); @@ -811,6 +915,7 @@ public void encode(Packet packet) throws Exception{ } int[] uncompress_len=new int[1]; + int[] compress_len=new int[1]; private int s2ccipher_size=8; private int c2scipher_size=8; @@ -932,7 +1037,7 @@ else if(type==SSH_MSG_CHANNEL_WINDOW_ADJUST){ if(c==null){ } else{ - c.addRemoteWindowSize(buf.getInt()); + c.addRemoteWindowSize(buf.getUInt()); } } else if(type==UserAuth.SSH_MSG_USERAUTH_SUCCESS){ @@ -941,7 +1046,6 @@ else if(type==UserAuth.SSH_MSG_USERAUTH_SUCCESS){ String method; method=guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS]; initDeflater(method); - method=guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC]; initInflater(method); } @@ -999,8 +1103,6 @@ private void updateKeys(KeyExchange kex) throws Exception{ byte[] H=kex.getH(); HASH hash=kex.getHash(); -// String[] guess=kex.guess; - if(session_id==null){ session_id=new byte[H.length]; System.arraycopy(H, 0, session_id, 0, H.length); @@ -1070,6 +1172,7 @@ private void updateKeys(KeyExchange kex) throws Exception{ method=guess[KeyExchange.PROPOSAL_MAC_ALGS_STOC]; c=Class.forName(getConfig(method)); s2cmac=(MAC)(c.newInstance()); + MACs2c = expandKey(buf, K, H, MACs2c, hash, s2cmac.getBlockSize()); s2cmac.init(MACs2c); //mac_buf=new byte[s2cmac.getBlockSize()]; s2cmac_result1=new byte[s2cmac.getBlockSize()]; @@ -1096,6 +1199,7 @@ private void updateKeys(KeyExchange kex) throws Exception{ method=guess[KeyExchange.PROPOSAL_MAC_ALGS_CTOS]; c=Class.forName(getConfig(method)); c2smac=(MAC)(c.newInstance()); + MACc2s = expandKey(buf, K, H, MACc2s, hash, c2smac.getBlockSize()); c2smac.init(MACc2s); method=guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS]; @@ -1112,22 +1216,74 @@ private void updateKeys(KeyExchange kex) throws Exception{ } } + + /* + * RFC 4253 7.2. Output from Key Exchange + * If the key length needed is longer than the output of the HASH, the + * key is extended by computing HASH of the concatenation of K and H and + * the entire key so far, and appending the resulting bytes (as many as + * HASH generates) to the key. This process is repeated until enough + * key material is available; the key is taken from the beginning of + * this value. In other words: + * K1 = HASH(K || H || X || session_id) (X is e.g., "A") + * K2 = HASH(K || H || K1) + * K3 = HASH(K || H || K1 || K2) + * ... + * key = K1 || K2 || K3 || ... + */ + private byte[] expandKey(Buffer buf, byte[] K, byte[] H, byte[] key, + HASH hash, int required_length) throws Exception { + byte[] result = key; + int size = hash.getBlockSize(); + while(result.length < required_length){ + buf.reset(); + buf.putMPInt(K); + buf.putByte(H); + buf.putByte(result); + hash.update(buf.buffer, 0, buf.index); + byte[] tmp = new byte[result.length+size]; + System.arraycopy(result, 0, tmp, 0, result.length); + System.arraycopy(hash.digest(), 0, tmp, result.length, size); + Util.bzero(result); + result = tmp; + } + return result; + } + /*public*/ /*synchronized*/ void write(Packet packet, Channel c, int length) throws Exception{ long t = getTimeout(); while(true){ if(in_kex){ if(t>0L && (System.currentTimeMillis()-kex_start_time)>t){ - throw new JSchException("timeout in wating for rekeying process."); + throw new JSchException("timeout in waiting for rekeying process."); } try{Thread.sleep(10);} catch(java.lang.InterruptedException e){}; continue; } synchronized(c){ + + if(c.rwsize=length){ c.rwsize-=length; break; } + } if(c.close || !c.isConnected()){ throw new IOException("channel is broken"); @@ -1144,7 +1300,9 @@ private void updateKeys(KeyExchange kex) throws Exception{ len=length; } if(len!=length){ - s=packet.shift((int)len, (c2smac!=null ? c2smac.getBlockSize() : 0)); + s=packet.shift((int)len, + (c2scipher!=null ? c2scipher_size : 8), + (c2smac!=null ? c2smac.getBlockSize() : 0)); } command=packet.buffer.getCommand(); recipient=c.getRecipient(); @@ -1169,17 +1327,18 @@ private void updateKeys(KeyExchange kex) throws Exception{ c.rwsize-=length; break; } - try{ - c.notifyme++; - c.wait(100); - } - catch(java.lang.InterruptedException e){ - } - finally{ - c.notifyme--; - } - } + //try{ + //System.out.println("1wait: "+c.rwsize); + // c.notifyme++; + // c.wait(100); + //} + //catch(java.lang.InterruptedException e){ + //} + //finally{ + // c.notifyme--; + //} + } } _write(packet); } @@ -1188,8 +1347,11 @@ public void write(Packet packet) throws Exception{ // System.err.println("in_kex="+in_kex+" "+(packet.buffer.getCommand())); long t = getTimeout(); while(in_kex){ - if(t>0L && (System.currentTimeMillis()-kex_start_time)>t){ - throw new JSchException("timeout in wating for rekeying process."); + if(t>0L && + (System.currentTimeMillis()-kex_start_time)>t && + !in_prompt + ){ + throw new JSchException("timeout in waiting for rekeying process."); } byte command=packet.buffer.getCommand(); //System.err.println("command: "+command); @@ -1308,7 +1470,10 @@ else if(in_kex && stimeoutlport is 0, the tcp port will be allocated. + * @param lport local port for local port forwarding + * @param host host address for local port forwarding + * @param rport remote port number for local port forwarding + * @return an allocated local TCP port number + * @see #setPortForwardingL(String bind_address, int lport, String host, int rport, ServerSocketFactory ssf, int connectTimeout) + */ public int setPortForwardingL(int lport, String host, int rport) throws JSchException{ return setPortForwardingL("127.0.0.1", lport, host, rport); } - public int setPortForwardingL(String boundaddress, int lport, String host, int rport) throws JSchException{ - return setPortForwardingL(boundaddress, lport, host, rport, null); + + /** + * Registers the local port forwarding. If bind_address is an empty string + * or '*', the port should be available from all interfaces. + * If bind_address is "localhost" or + * null, the listening port will be bound for local use only. + * If lport is 0, the tcp port will be allocated. + * @param bind_address bind address for local port forwarding + * @param lport local port for local port forwarding + * @param host host address for local port forwarding + * @param rport remote port number for local port forwarding + * @return an allocated local TCP port number + * @see #setPortForwardingL(String bind_address, int lport, String host, int rport, ServerSocketFactory ssf, int connectTimeout) + */ + public int setPortForwardingL(String bind_address, int lport, String host, int rport) throws JSchException{ + return setPortForwardingL(bind_address, lport, host, rport, null); + } + + /** + * Registers the local port forwarding. + * If bind_address is an empty string or "*", + * the port should be available from all interfaces. + * If bind_address is "localhost" or + * null, the listening port will be bound for local use only. + * If lport is 0, the tcp port will be allocated. + * @param bind_address bind address for local port forwarding + * @param lport local port for local port forwarding + * @param host host address for local port forwarding + * @param rport remote port number for local port forwarding + * @param ssf socket factory + * @return an allocated local TCP port number + * @see #setPortForwardingL(String bind_address, int lport, String host, int rport, ServerSocketFactory ssf, int connectTimeout) + */ + public int setPortForwardingL(String bind_address, int lport, String host, int rport, ServerSocketFactory ssf) throws JSchException{ + return setPortForwardingL(bind_address, lport, host, rport, ssf, 0); } - public int setPortForwardingL(String boundaddress, int lport, String host, int rport, ServerSocketFactory ssf) throws JSchException{ - PortWatcher pw=PortWatcher.addPort(this, boundaddress, lport, host, rport, ssf); + + /** + * Registers the local port forwarding. + * If bind_address is an empty string + * or "*", the port should be available from all interfaces. + * If bind_address is "localhost" or + * null, the listening port will be bound for local use only. + * If lport is 0, the tcp port will be allocated. + * @param bind_address bind address for local port forwarding + * @param lport local port for local port forwarding + * @param host host address for local port forwarding + * @param rport remote port number for local port forwarding + * @param ssf socket factory + * @param connectTimeout timeout for establishing port connection + * @return an allocated local TCP port number + */ + public int setPortForwardingL(String bind_address, int lport, String host, int rport, ServerSocketFactory ssf, int connectTimeout) throws JSchException{ + PortWatcher pw=PortWatcher.addPort(this, bind_address, lport, host, rport, ssf); + pw.setConnectTimeout(connectTimeout); Thread tmp=new Thread(pw); tmp.setName("PortWatcher Thread for "+host); if(daemon_thread){ @@ -1623,44 +1854,291 @@ public int setPortForwardingL(String boundaddress, int lport, String host, int r tmp.start(); return pw.lport; } + + /** + * Cancels the local port forwarding assigned + * at local TCP port lport on loopback interface. + * + * @param lport local TCP port + */ public void delPortForwardingL(int lport) throws JSchException{ delPortForwardingL("127.0.0.1", lport); } - public void delPortForwardingL(String boundaddress, int lport) throws JSchException{ - PortWatcher.delPort(this, boundaddress, lport); + + /** + * Cancels the local port forwarding assigned + * at local TCP port lport on bind_address interface. + * + * @param bind_address bind_address of network interfaces + * @param lport local TCP port + */ + public void delPortForwardingL(String bind_address, int lport) throws JSchException{ + PortWatcher.delPort(this, bind_address, lport); } + + /** + * Lists the registered local port forwarding. + * + * @return a list of "lport:host:hostport" + */ public String[] getPortForwardingL() throws JSchException{ return PortWatcher.getPortForwarding(this); } + /** + * Registers the remote port forwarding for the loopback interface + * of the remote. + * + * @param rport remote port + * @param host host address + * @param lport local port + * @see #setPortForwardingR(String bind_address, int rport, String host, int lport, SocketFactory sf) + */ public void setPortForwardingR(int rport, String host, int lport) throws JSchException{ setPortForwardingR(null, rport, host, lport, (SocketFactory)null); } + + /** + * Registers the remote port forwarding. + * If bind_address is an empty string or "*", + * the port should be available from all interfaces. + * If bind_address is "localhost" or is not given, + * the listening port will be bound for local use only. + * Note that if GatewayPorts is "no" on the + * remote, "localhost" is always used as a bind_address. + * + * @param bind_address bind address + * @param rport remote port + * @param host host address + * @param lport local port + * @see #setPortForwardingR(String bind_address, int rport, String host, int lport, SocketFactory sf) + */ public void setPortForwardingR(String bind_address, int rport, String host, int lport) throws JSchException{ setPortForwardingR(bind_address, rport, host, lport, (SocketFactory)null); } + + /** + * Registers the remote port forwarding for the loopback interface + * of the remote. + * + * @param rport remote port + * @param host host address + * @param lport local port + * @param sf socket factory + * @see #setPortForwardingR(String bind_address, int rport, String host, int lport, SocketFactory sf) + */ public void setPortForwardingR(int rport, String host, int lport, SocketFactory sf) throws JSchException{ setPortForwardingR(null, rport, host, lport, sf); } + + // TODO: This method should return the integer value as the assigned port. + /** + * Registers the remote port forwarding. + * If bind_address is an empty string or "*", + * the port should be available from all interfaces. + * If bind_address is "localhost" or is not given, + * the listening port will be bound for local use only. + * Note that if GatewayPorts is "no" on the + * remote, "localhost" is always used as a bind_address. + * If rport is 0, the TCP port will be allocated on the remote. + * + * @param bind_address bind address + * @param rport remote port + * @param host host address + * @param lport local port + * @param sf socket factory + */ public void setPortForwardingR(String bind_address, int rport, String host, int lport, SocketFactory sf) throws JSchException{ - ChannelForwardedTCPIP.addPort(this, bind_address, rport, host, lport, sf); - setPortForwarding(bind_address, rport); + int allocated=_setPortForwardingR(bind_address, rport); + ChannelForwardedTCPIP.addPort(this, bind_address, + rport, allocated, host, lport, sf); } + /** + * Registers the remote port forwarding for the loopback interface + * of the remote. + * The TCP connection to rport on the remote will be + * forwarded to an instance of the class daemon. + * The class specified by daemon must implement + * ForwardedTCPIPDaemon. + * + * @param rport remote port + * @param daemon class name, which implements "ForwardedTCPIPDaemon" + * @see #setPortForwardingR(String bind_address, int rport, String daemon, Object[] arg) + */ public void setPortForwardingR(int rport, String daemon) throws JSchException{ setPortForwardingR(null, rport, daemon, null); } + + /** + * Registers the remote port forwarding for the loopback interface + * of the remote. + * The TCP connection to rport on the remote will be + * forwarded to an instance of the class daemon with + * the argument arg. + * The class specified by daemon must implement ForwardedTCPIPDaemon. + * + * @param rport remote port + * @param daemon class name, which implements "ForwardedTCPIPDaemon" + * @param arg arguments for "daemon" + * @see #setPortForwardingR(String bind_address, int rport, String daemon, Object[] arg) + */ public void setPortForwardingR(int rport, String daemon, Object[] arg) throws JSchException{ setPortForwardingR(null, rport, daemon, arg); } + + /** + * Registers the remote port forwarding. + * If bind_address is an empty string + * or "*", the port should be available from all interfaces. + * If bind_address is "localhost" or is not given, + * the listening port will be bound for local use only. + * Note that if GatewayPorts is "no" on the + * remote, "localhost" is always used as a bind_address. + * The TCP connection to rport on the remote will be + * forwarded to an instance of the class daemon with the + * argument arg. + * The class specified by daemon must implement ForwardedTCPIPDaemon. + * + * @param bind_address bind address + * @param rport remote port + * @param daemon class name, which implements "ForwardedTCPIPDaemon" + * @param arg arguments for "daemon" + * @see #setPortForwardingR(String bind_address, int rport, String daemon, Object[] arg) + */ public void setPortForwardingR(String bind_address, int rport, String daemon, Object[] arg) throws JSchException{ - ChannelForwardedTCPIP.addPort(this, bind_address, rport, daemon, arg); - setPortForwarding(bind_address, rport); + int allocated = _setPortForwardingR(bind_address, rport); + ChannelForwardedTCPIP.addPort(this, bind_address, + rport, allocated, daemon, arg); } + /** + * Lists the registered remote port forwarding. + * + * @return a list of "rport:host:hostport" + */ + public String[] getPortForwardingR() throws JSchException{ + return ChannelForwardedTCPIP.getPortForwarding(this); + } + + private class Forwarding { + String bind_address = null; + int port = -1; + String host = null; + int hostport = -1; + } + + /** + * The given argument may be "[bind_address:]port:host:hostport" or + * "[bind_address:]port host:hostport", which is from LocalForward command of + * ~/.ssh/config . + */ + private Forwarding parseForwarding(String conf) throws JSchException { + String[] tmp = conf.split(" "); + if(tmp.length>1){ // "[bind_address:]port host:hostport" + Vector foo = new Vector(); + for(int i=0; ibind_address is an empty string or "*", + * the port should be available from all interfaces. + * If bind_address is "localhost" or is not given, + * the listening port will be bound for local use only. + * + * @param conf configuration of local port forwarding + * @return an assigned port number + * @see #setPortForwardingL(String bind_address, int lport, String host, int rport) + */ + public int setPortForwardingL(String conf) throws JSchException { + Forwarding f = parseForwarding(conf); + return setPortForwardingL(f.bind_address, f.port, f.host, f.hostport); + } + + /** + * Registers the remote port forwarding. The argument should be + * in the format like "[bind_address:]port:host:hostport". If the + * bind_address is not given, the default is to only bind to loopback + * addresses. If the bind_address is "*" or an empty string, + * then the forwarding is requested to listen on all interfaces. + * Note that if GatewayPorts is "no" on the remote, + * "localhost" is always used for bind_address. + * If the specified remote is "0", + * the TCP port will be allocated on the remote. + * + * @param conf configuration of remote port forwarding + * @return an allocated TCP port on the remote. + * @see #setPortForwardingR(String bind_address, int rport, String host, int rport) + */ + public int setPortForwardingR(String conf) throws JSchException { + Forwarding f = parseForwarding(conf); + int allocated = _setPortForwardingR(f.bind_address, f.port); + ChannelForwardedTCPIP.addPort(this, f.bind_address, + f.port, allocated, f.host, f.hostport, null); + return allocated; + } + + /** + * Instantiates an instance of stream-forwarder to host:port. + * Set I/O stream to the given channel, and then invoke Channel#connect() method. + * + * @param host remote host, which the given stream will be plugged to. + * @param port remote port, which the given stream will be plugged to. + */ + public Channel getStreamForwarder(String host, int port) throws JSchException { + ChannelDirectTCPIP channel = new ChannelDirectTCPIP(); + channel.init(); + this.addChannel(channel); + channel.setHost(host); + channel.setPort(port); + return channel; + } + private class GlobalRequestReply{ private Thread thread=null; private int reply=-1; + private int port=0; void setThread(Thread thread){ this.thread=thread; this.reply=-1; @@ -1668,9 +2146,11 @@ void setThread(Thread thread){ Thread getThread(){ return thread; } void setReply(int reply){ this.reply=reply; } int getReply(){ return this.reply; } + int getPort(){ return this.port; } + void setPort(int port){ this.port=port; } } private GlobalRequestReply grr=new GlobalRequestReply(); - private void setPortForwarding(String bind_address, int rport) throws JSchException{ + private int _setPortForwardingR(String bind_address, int rport) throws JSchException{ synchronized(grr){ Buffer buf=new Buffer(100); // ?? Packet packet=new Packet(buf); @@ -1678,6 +2158,7 @@ private void setPortForwarding(String bind_address, int rport) throws JSchExcept String address_to_bind=ChannelForwardedTCPIP.normalize(bind_address); grr.setThread(Thread.currentThread()); + grr.setPort(rport); try{ // byte SSH_MSG_GLOBAL_REQUEST 80 @@ -1713,10 +2194,30 @@ private void setPortForwarding(String bind_address, int rport) throws JSchExcept if(reply != 1){ throw new JSchException("remote port forwarding failed for listen port "+rport); } + rport=grr.getPort(); } + return rport; } + + /** + * Cancels the remote port forwarding assigned at remote TCP port rport. + * + * @param rport remote TCP port + */ public void delPortForwardingR(int rport) throws JSchException{ - ChannelForwardedTCPIP.delPort(this, rport); + this.delPortForwardingR(null, rport); + } + + /** + * Cancels the remote port forwarding assigned at + * remote TCP port rport bound on the interface at + * bind_address. + * + * @param bind_address bind address of the interface on the remote + * @param rport remote TCP port + */ + public void delPortForwardingR(String bind_address, int rport) throws JSchException{ + ChannelForwardedTCPIP.delPort(this, bind_address, rport); } private void initDeflater(String method) throws JSchException{ @@ -1736,6 +2237,9 @@ private void initDeflater(String method) throws JSchException{ catch(Exception ee){ } deflater.init(Compression.DEFLATER, level); } + catch(NoClassDefFoundError ee){ + throw new JSchException(ee.toString(), ee); + } catch(Exception ee){ throw new JSchException(ee.toString(), ee); //System.err.println(foo+" isn't accessible."); @@ -1877,6 +2381,17 @@ public void sendKeepAliveMsg() throws Exception{ buf.putByte((byte)1); write(packet); } + + private static final byte[] nomoresessions=Util.str2byte("no-more-sessions@openssh.com"); + public void noMoreSessionChannels() throws Exception{ + Buffer buf=new Buffer(); + Packet packet=new Packet(buf); + packet.reset(); + buf.putByte((byte)SSH_MSG_GLOBAL_REQUEST); + buf.putString(nomoresessions); + buf.putByte((byte)0); + write(packet); + } private HostKey hostkey=null; public HostKey getHostKey(){ return hostkey; } @@ -1890,17 +2405,46 @@ public String getHostKeyAlias(){ return hostKeyAlias; } + /** + * Sets the interval to send a keep-alive message. If zero is + * specified, any keep-alive message must not be sent. The default interval + * is zero. + * + * @param interval the specified interval, in milliseconds. + * @see #getServerAliveInterval() + */ public void setServerAliveInterval(int interval) throws JSchException { setTimeout(interval); this.serverAliveInterval=interval; } - public void setServerAliveCountMax(int count){ - this.serverAliveCountMax=count; - } + /** + * Returns setting for the interval to send a keep-alive message. + * + * @see #setServerAliveInterval(int) + */ public int getServerAliveInterval(){ return this.serverAliveInterval; } + + /** + * Sets the number of keep-alive messages which may be sent without + * receiving any messages back from the server. If this threshold is + * reached while keep-alive messages are being sent, the connection will + * be disconnected. The default value is one. + * + * @param count the specified count + * @see #getServerAliveCountMax() + */ + public void setServerAliveCountMax(int count){ + this.serverAliveCountMax=count; + } + + /** + * Returns setting for the threshold to send keep-alive messages. + * + * @see #setServerAliveCountMax(int) + */ public int getServerAliveCountMax(){ return this.serverAliveCountMax; } @@ -1918,11 +2462,17 @@ private String[] checkCiphers(String ciphers){ "CheckCiphers: "+ciphers); } - java.util.Vector result=new java.util.Vector(); + String cipherc2s=getConfig("cipher.c2s"); + String ciphers2c=getConfig("cipher.s2c"); + + Vector result=new Vector(); String[] _ciphers=Util.split(ciphers, ","); for(int i=0; i<_ciphers.length; i++){ - if(!checkCipher(getConfig(_ciphers[i]))){ - result.addElement(_ciphers[i]); + String cipher=_ciphers[i]; + if(ciphers2c.indexOf(cipher) == -1 && cipherc2s.indexOf(cipher) == -1) + continue; + if(!checkCipher(getConfig(cipher))){ + result.addElement(cipher); } } if(result.size()==0) @@ -1953,4 +2503,336 @@ static boolean checkCipher(String cipher){ return false; } } + + private String[] checkKexes(String kexes){ + if(kexes==null || kexes.length()==0) + return null; + + if(JSch.getLogger().isEnabled(Logger.INFO)){ + JSch.getLogger().log(Logger.INFO, + "CheckKexes: "+kexes); + } + + java.util.Vector result=new java.util.Vector(); + String[] _kexes=Util.split(kexes, ","); + for(int i=0; i<_kexes.length; i++){ + if(!checkKex(this, getConfig(_kexes[i]))){ + result.addElement(_kexes[i]); + } + } + if(result.size()==0) + return null; + String[] foo=new String[result.size()]; + System.arraycopy(result.toArray(), 0, foo, 0, result.size()); + + if(JSch.getLogger().isEnabled(Logger.INFO)){ + for(int i=0; inull. + * + * @param identityRepository + * @see #getIdentityRepository() + */ + public void setIdentityRepository(IdentityRepository identityRepository){ + this.identityRepository = identityRepository; + } + + /** + * Gets the identityRepository. + * If this.identityRepository is null, + * JSch#getIdentityRepository() will be invoked. + * + * @see JSch#getIdentityRepository() + */ + IdentityRepository getIdentityRepository(){ + if(identityRepository == null) + return jsch.getIdentityRepository(); + return identityRepository; + } + + /** + * Sets the hostkeyRepository, which will be referred in checking host keys. + * + * @param hostkeyRepository + * @see #getHostKeyRepository() + */ + public void setHostKeyRepository(HostKeyRepository hostkeyRepository){ + this.hostkeyRepository = hostkeyRepository; + } + + /** + * Gets the hostkeyRepository. + * If this.hostkeyRepository is null, + * JSch#getHostKeyRepository() will be invoked. + * + * @see JSch#getHostKeyRepository() + */ + public HostKeyRepository getHostKeyRepository(){ + if(hostkeyRepository == null) + return jsch.getHostKeyRepository(); + return hostkeyRepository; + } + + /* + // setProxyCommand("ssh -l user2 host2 -o 'ProxyCommand ssh user1@host1 nc host2 22' nc %h %p") + public void setProxyCommand(String command){ + setProxy(new ProxyCommand(command)); + } + + class ProxyCommand implements Proxy { + String command; + Process p = null; + InputStream in = null; + OutputStream out = null; + ProxyCommand(String command){ + this.command = command; + } + public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws Exception { + String _command = command.replace("%h", host); + _command = _command.replace("%p", new Integer(port).toString()); + p = Runtime.getRuntime().exec(_command); + in = p.getInputStream(); + out = p.getOutputStream(); + } + public Socket getSocket() { return null; } + public InputStream getInputStream() { return in; } + public OutputStream getOutputStream() { return out; } + public void close() { + try{ + if(p!=null){ + p.getErrorStream().close(); + p.getOutputStream().close(); + p.getInputStream().close(); + p.destroy(); + p=null; + } + } + catch(IOException e){ + } + } + } + */ + + private void applyConfig() throws JSchException { + ConfigRepository configRepository = jsch.getConfigRepository(); + if(configRepository == null){ + return; + } + + ConfigRepository.Config config = + configRepository.getConfig(org_host); + + String value = null; + + value = config.getUser(); + if(value != null) + username = value; + + value = config.getHostname(); + if(value != null) + host = value; + + int port = config.getPort(); + if(port != -1) + this.port = port; + + checkConfig(config, "kex"); + checkConfig(config, "server_host_key"); + + checkConfig(config, "cipher.c2s"); + checkConfig(config, "cipher.s2c"); + checkConfig(config, "mac.c2s"); + checkConfig(config, "mac.s2c"); + checkConfig(config, "compression.c2s"); + checkConfig(config, "compression.s2c"); + checkConfig(config, "compression_level"); + + checkConfig(config, "StrictHostKeyChecking"); + checkConfig(config, "HashKnownHosts"); + checkConfig(config, "PreferredAuthentications"); + checkConfig(config, "MaxAuthTries"); + checkConfig(config, "ClearAllForwardings"); + + value = config.getValue("HostKeyAlias"); + if(value != null) + this.setHostKeyAlias(value); + + value = config.getValue("UserKnownHostsFile"); + if(value != null) { + KnownHosts kh = new KnownHosts(jsch); + kh.setKnownHosts(value); + this.setHostKeyRepository(kh); + } + + String[] values = config.getValues("IdentityFile"); + if(values != null) { + String[] global = + configRepository.getConfig("").getValues("IdentityFile"); + if(global != null){ + for(int i = 0; i < global.length; i++){ + jsch.addIdentity(global[i]); + } + } + else { + global = new String[0]; + } + if(values.length - global.length > 0){ + IdentityRepository.Wrapper ir = + new IdentityRepository.Wrapper(jsch.getIdentityRepository(), true); + for(int i = 0; i < values.length; i++){ + String ifile = values[i]; + for(int j = 0; j < global.length; j++){ + if(!ifile.equals(global[j])) + continue; + ifile = null; + break; + } + if(ifile == null) + continue; + Identity identity = + IdentityFile.newInstance(ifile, null, jsch); + ir.add(identity); + } + this.setIdentityRepository(ir); + } + } + + value = config.getValue("ServerAliveInterval"); + if(value != null) { + try { + this.setServerAliveInterval(Integer.parseInt(value)); + } + catch(NumberFormatException e){ + } + } + + value = config.getValue("ConnectTimeout"); + if(value != null) { + try { + setTimeout(Integer.parseInt(value)); + } + catch(NumberFormatException e){ + } + } + + value = config.getValue("MaxAuthTries"); + if(value != null) { + setConfig("MaxAuthTries", value); + } + + value = config.getValue("ClearAllForwardings"); + if(value != null) { + setConfig("ClearAllForwardings", value); + } + + } + + private void applyConfigChannel(ChannelSession channel) throws JSchException { + ConfigRepository configRepository = jsch.getConfigRepository(); + if(configRepository == null){ + return; + } + + ConfigRepository.Config config = + configRepository.getConfig(org_host); + + String value = null; + + value = config.getValue("ForwardAgent"); + if(value != null){ + channel.setAgentForwarding(value.equals("yes")); + } + + value = config.getValue("RequestTTY"); + if(value != null){ + channel.setPty(value.equals("yes")); + } + } + + private void requestPortForwarding() throws JSchException { + + if(getConfig("ClearAllForwardings").equals("yes")) + return; + + ConfigRepository configRepository = jsch.getConfigRepository(); + if(configRepository == null){ + return; + } + + ConfigRepository.Config config = + configRepository.getConfig(org_host); + + String[] values = config.getValues("LocalForward"); + if(values != null){ + for(int i = 0; i < values.length; i++) { + setPortForwardingL(values[i]); + } + } + + values = config.getValues("RemoteForward"); + if(values != null){ + for(int i = 0; i < values.length; i++) { + setPortForwardingR(values[i]); + } + } + } + + private void checkConfig(ConfigRepository.Config config, String key){ + String value = config.getValue(key); + if(value != null) + this.setConfig(key, value); + } } diff --git a/src/com/jcraft/jsch/SftpATTRS.java b/src/main/java/com/jcraft/jsch/SftpATTRS.java similarity index 90% rename from src/com/jcraft/jsch/SftpATTRS.java rename to src/main/java/com/jcraft/jsch/SftpATTRS.java index a779e69..96165d5 100644 --- a/src/com/jcraft/jsch/SftpATTRS.java +++ b/src/main/java/com/jcraft/jsch/SftpATTRS.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -108,12 +108,12 @@ public String getPermissionsString() { } public String getAtimeString(){ - SimpleDateFormat locale=new SimpleDateFormat(); - return (locale.format(new Date(atime))); + Date date= new Date(((long)atime)*1000L); + return (date.toString()); } public String getMtimeString(){ - Date date= new Date(((long)mtime)*1000); + Date date= new Date(((long)mtime)*1000L); return (date.toString()); } @@ -123,8 +123,14 @@ public String getMtimeString(){ public static final int SSH_FILEXFER_ATTR_ACMODTIME= 0x00000008; public static final int SSH_FILEXFER_ATTR_EXTENDED= 0x80000000; + static final int S_IFMT=0xf000; + static final int S_IFIFO=0x1000; + static final int S_IFCHR=0x2000; static final int S_IFDIR=0x4000; + static final int S_IFBLK=0x6000; + static final int S_IFREG=0x8000; static final int S_IFLNK=0xa000; + static final int S_IFSOCK=0xc000; int flags=0; long size; @@ -231,14 +237,39 @@ public void setPERMISSIONS(int permissions){ this.permissions=permissions; } + private boolean isType(int mask) { + return (flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 && + (permissions&S_IFMT)==mask; + } + + public boolean isReg(){ + return isType(S_IFREG); + } + public boolean isDir(){ - return ((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 && - ((permissions&S_IFDIR)==S_IFDIR)); + return isType(S_IFDIR); } - public boolean isLink(){ - return ((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 && - ((permissions&S_IFLNK)==S_IFLNK)); + + public boolean isChr(){ + return isType(S_IFCHR); + } + + public boolean isBlk(){ + return isType(S_IFBLK); } + + public boolean isFifo(){ + return isType(S_IFIFO); + } + + public boolean isLink(){ + return isType(S_IFLNK); + } + + public boolean isSock(){ + return isType(S_IFSOCK); + } + public int getFlags() { return flags; } public long getSize() { return size; } public int getUId() { return uid; } diff --git a/src/com/jcraft/jsch/SftpException.java b/src/main/java/com/jcraft/jsch/SftpException.java similarity index 96% rename from src/com/jcraft/jsch/SftpException.java rename to src/main/java/com/jcraft/jsch/SftpException.java index 8df0e5d..6f64475 100644 --- a/src/com/jcraft/jsch/SftpException.java +++ b/src/main/java/com/jcraft/jsch/SftpException.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/SftpProgressMonitor.java b/src/main/java/com/jcraft/jsch/SftpProgressMonitor.java similarity index 93% rename from src/com/jcraft/jsch/SftpProgressMonitor.java rename to src/main/java/com/jcraft/jsch/SftpProgressMonitor.java index c4fa65b..0fd124a 100644 --- a/src/com/jcraft/jsch/SftpProgressMonitor.java +++ b/src/main/java/com/jcraft/jsch/SftpProgressMonitor.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -32,6 +32,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING public interface SftpProgressMonitor{ public static final int PUT=0; public static final int GET=1; + public static final long UNKNOWN_SIZE = -1L; void init(int op, String src, String dest, long max); boolean count(long count); void end(); diff --git a/src/main/java/com/jcraft/jsch/SftpStatVFS.java b/src/main/java/com/jcraft/jsch/SftpStatVFS.java new file mode 100644 index 0000000..04dcd40 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/SftpStatVFS.java @@ -0,0 +1,122 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class SftpStatVFS { + + /* + It seems data is serializsed according to sys/statvfs.h; for example, + http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/statvfs.h.html + */ + + private long bsize; + private long frsize; + private long blocks; + private long bfree; + private long bavail; + private long files; + private long ffree; + private long favail; + private long fsid; + private long flag; + private long namemax; + + int flags=0; + long size; + int uid; + int gid; + int permissions; + int atime; + int mtime; + String[] extended=null; + + private SftpStatVFS(){ + } + + static SftpStatVFS getStatVFS(Buffer buf){ + SftpStatVFS statvfs=new SftpStatVFS(); + + statvfs.bsize = buf.getLong(); + statvfs.frsize = buf.getLong(); + statvfs.blocks = buf.getLong(); + statvfs.bfree = buf.getLong(); + statvfs.bavail = buf.getLong(); + statvfs.files = buf.getLong(); + statvfs.ffree = buf.getLong(); + statvfs.favail = buf.getLong(); + statvfs.fsid = buf.getLong(); + int flag = (int)buf.getLong(); + statvfs.namemax = buf.getLong(); + + statvfs.flag = + (flag & 1/*SSH2_FXE_STATVFS_ST_RDONLY*/) != 0 ? 1/*ST_RDONLY*/ : 0; + statvfs.flag |= + (flag & 2/*SSH2_FXE_STATVFS_ST_NOSUID*/) != 0 ? 2/*ST_NOSUID*/ : 0; + + return statvfs; + } + + public long getBlockSize() { return bsize; } + public long getFragmentSize() { return frsize; } + public long getBlocks() { return blocks; } + public long getFreeBlocks() { return bfree; } + public long getAvailBlocks() { return bavail; } + public long getINodes() { return files; } + public long getFreeINodes() { return ffree; } + public long getAvailINodes() { return favail; } + public long getFileSystemID() { return fsid; } + public long getMountFlag() { return flag; } + public long getMaximumFilenameLength() { return namemax; } + + public long getSize(){ + return getFragmentSize()*getBlocks()/1024; + } + + public long getUsed(){ + return getFragmentSize()*(getBlocks()-getFreeBlocks())/1024; + } + + public long getAvailForNonRoot(){ + return getFragmentSize()*getAvailBlocks()/1024; + } + + public long getAvail(){ + return getFragmentSize()*getFreeBlocks()/1024; + } + + public int getCapacity(){ + return (int)(100*(getBlocks()-getFreeBlocks())/getBlocks()); + } + +// public String toString() { return ""; } +} diff --git a/src/com/jcraft/jsch/SignatureRSA.java b/src/main/java/com/jcraft/jsch/Signature.java similarity index 88% rename from src/com/jcraft/jsch/SignatureRSA.java rename to src/main/java/com/jcraft/jsch/Signature.java index e1e8ed0..711f01d 100644 --- a/src/com/jcraft/jsch/SignatureRSA.java +++ b/src/main/java/com/jcraft/jsch/Signature.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2012-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -29,10 +29,8 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING package com.jcraft.jsch; -public interface SignatureRSA{ +public interface Signature{ void init() throws Exception; - void setPubKey(byte[] e, byte[] n) throws Exception; - void setPrvKey(byte[] d, byte[] n) throws Exception; void update(byte[] H) throws Exception; boolean verify(byte[] sig) throws Exception; byte[] sign() throws Exception; diff --git a/src/com/jcraft/jsch/SignatureDSA.java b/src/main/java/com/jcraft/jsch/SignatureDSA.java similarity index 86% rename from src/com/jcraft/jsch/SignatureDSA.java rename to src/main/java/com/jcraft/jsch/SignatureDSA.java index f9068eb..2cbe0ac 100644 --- a/src/com/jcraft/jsch/SignatureDSA.java +++ b/src/main/java/com/jcraft/jsch/SignatureDSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -29,11 +29,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING package com.jcraft.jsch; -public interface SignatureDSA{ - void init() throws Exception; +public interface SignatureDSA extends Signature { void setPubKey(byte[] y, byte[] p, byte[] q, byte[] g) throws Exception; void setPrvKey(byte[] x, byte[] p, byte[] q, byte[] g) throws Exception; - void update(byte[] H) throws Exception; - boolean verify(byte[] sig) throws Exception; - byte[] sign() throws Exception; } diff --git a/src/main/java/com/jcraft/jsch/SignatureECDSA.java b/src/main/java/com/jcraft/jsch/SignatureECDSA.java new file mode 100644 index 0000000..7e14d5d --- /dev/null +++ b/src/main/java/com/jcraft/jsch/SignatureECDSA.java @@ -0,0 +1,35 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +public interface SignatureECDSA extends Signature { + void setPubKey(byte[] r, byte[] s) throws Exception; + void setPrvKey(byte[] s) throws Exception; +} diff --git a/src/main/java/com/jcraft/jsch/SignatureRSA.java b/src/main/java/com/jcraft/jsch/SignatureRSA.java new file mode 100644 index 0000000..e51d8a6 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/SignatureRSA.java @@ -0,0 +1,35 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch; + +public interface SignatureRSA extends Signature { + void setPubKey(byte[] e, byte[] n) throws Exception; + void setPrvKey(byte[] d, byte[] n) throws Exception; +} diff --git a/src/com/jcraft/jsch/SocketFactory.java b/src/main/java/com/jcraft/jsch/SocketFactory.java similarity index 96% rename from src/com/jcraft/jsch/SocketFactory.java rename to src/main/java/com/jcraft/jsch/SocketFactory.java index 70f922d..d051985 100644 --- a/src/com/jcraft/jsch/SocketFactory.java +++ b/src/main/java/com/jcraft/jsch/SocketFactory.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/UIKeyboardInteractive.java b/src/main/java/com/jcraft/jsch/UIKeyboardInteractive.java similarity index 96% rename from src/com/jcraft/jsch/UIKeyboardInteractive.java rename to src/main/java/com/jcraft/jsch/UIKeyboardInteractive.java index 6ff281d..8ada1a9 100644 --- a/src/com/jcraft/jsch/UIKeyboardInteractive.java +++ b/src/main/java/com/jcraft/jsch/UIKeyboardInteractive.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/UserAuth.java b/src/main/java/com/jcraft/jsch/UserAuth.java similarity index 97% rename from src/com/jcraft/jsch/UserAuth.java rename to src/main/java/com/jcraft/jsch/UserAuth.java index c9a990a..2683631 100644 --- a/src/com/jcraft/jsch/UserAuth.java +++ b/src/main/java/com/jcraft/jsch/UserAuth.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java b/src/main/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java similarity index 99% rename from src/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java rename to src/main/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java index 6b20713..4325955 100644 --- a/src/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java +++ b/src/main/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/UserAuthKeyboardInteractive.java b/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java similarity index 96% rename from src/com/jcraft/jsch/UserAuthKeyboardInteractive.java rename to src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java index 0334fb2..8331b17 100644 --- a/src/com/jcraft/jsch/UserAuthKeyboardInteractive.java +++ b/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -49,6 +49,11 @@ public boolean start(Session session) throws Exception{ _username=Util.str2byte(username); while(true){ + + if(session.auth_failures >= session.max_auth_tries){ + return false; + } + // send // byte SSH_MSG_USERAUTH_REQUEST(50) // string user name (ISO-10646 UTF-8, as defined in [RFC-2279]) @@ -101,6 +106,7 @@ public boolean start(Session session) throws Exception{ //throw new JSchException("USERAUTH KI is not supported"); //cancel=true; // ?? } + session.auth_failures++; break; } if(command==SSH_MSG_USERAUTH_INFO_REQUEST){ @@ -122,7 +128,7 @@ public boolean start(Session session) throws Exception{ if(password!=null && prompt.length==1 && !echo[0] && - prompt[0].toLowerCase().startsWith("password:")){ + prompt[0].toLowerCase().indexOf("password:") >= 0){ response=new byte[1][]; response[0]=password; password=null; diff --git a/src/com/jcraft/jsch/UserAuthNone.java b/src/main/java/com/jcraft/jsch/UserAuthNone.java similarity index 98% rename from src/com/jcraft/jsch/UserAuthNone.java rename to src/main/java/com/jcraft/jsch/UserAuthNone.java index c5cacd5..a2bf63a 100644 --- a/src/com/jcraft/jsch/UserAuthNone.java +++ b/src/main/java/com/jcraft/jsch/UserAuthNone.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/UserAuthPassword.java b/src/main/java/com/jcraft/jsch/UserAuthPassword.java similarity index 96% rename from src/com/jcraft/jsch/UserAuthPassword.java rename to src/main/java/com/jcraft/jsch/UserAuthPassword.java index 41b499a..7bc1a28 100644 --- a/src/com/jcraft/jsch/UserAuthPassword.java +++ b/src/main/java/com/jcraft/jsch/UserAuthPassword.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -44,6 +44,11 @@ public boolean start(Session session) throws Exception{ try{ while(true){ + + if(session.auth_failures >= session.max_auth_tries){ + return false; + } + if(password==null){ if(userinfo==null){ //throw new JSchException("USERAUTH fail"); @@ -157,6 +162,7 @@ public boolean start(Session session) throws Exception{ if(partial_success!=0){ throw new JSchPartialAuthException(Util.byte2str(foo)); } + session.auth_failures++; break; } else{ diff --git a/src/com/jcraft/jsch/UserAuthPublicKey.java b/src/main/java/com/jcraft/jsch/UserAuthPublicKey.java similarity index 88% rename from src/com/jcraft/jsch/UserAuthPublicKey.java rename to src/main/java/com/jcraft/jsch/UserAuthPublicKey.java index b5866ab..40c1fa0 100644 --- a/src/com/jcraft/jsch/UserAuthPublicKey.java +++ b/src/main/java/com/jcraft/jsch/UserAuthPublicKey.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -36,7 +36,7 @@ class UserAuthPublicKey extends UserAuth{ public boolean start(Session session) throws Exception{ super.start(session); - Vector identities=session.jsch.identities; + Vector identities=session.getIdentityRepository().getIdentities(); byte[] passphrase=null; byte[] _username=null; @@ -51,11 +51,14 @@ public boolean start(Session session) throws Exception{ _username=Util.str2byte(username); for(int i=0; i= session.max_auth_tries){ + return false; + } + Identity identity=(Identity)(identities.elementAt(i)); byte[] pubkeyblob=identity.getPublicKeyBlob(); -//System.err.println("UserAuthPublicKey: "+identity+" "+pubkeyblob); - if(pubkeyblob!=null){ // send // byte SSH_MSG_USERAUTH_REQUEST(50) @@ -63,7 +66,8 @@ public boolean start(Session session) throws Exception{ // string service name ("ssh-connection") // string "publickey" // boolen FALSE - // string plaintext password (ISO-10646 UTF-8) + // string public key algorithm name + // string public key blob packet.reset(); buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST); buf.putString(_username); @@ -126,8 +130,13 @@ else if(command==SSH_MSG_USERAUTH_BANNER){ } if(!identity.isEncrypted() || passphrase!=null){ - if(identity.setPassphrase(passphrase)) + if(identity.setPassphrase(passphrase)){ + if(passphrase!=null && + (session.getIdentityRepository() instanceof IdentityRepository.Wrapper)){ + ((IdentityRepository.Wrapper)session.getIdentityRepository()).check(); + } break; + } } Util.bzero(passphrase); passphrase=null; @@ -146,13 +155,15 @@ else if(command==SSH_MSG_USERAUTH_BANNER){ if(pubkeyblob==null) continue; - // send - // byte SSH_MSG_USERAUTH_REQUEST(50) - // string user name - // string service name ("ssh-connection") - // string "publickey" - // boolen TRUE - // string plaintext password (ISO-10646 UTF-8) + // send + // byte SSH_MSG_USERAUTH_REQUEST(50) + // string user name + // string service name ("ssh-connection") + // string "publickey" + // boolen TRUE + // string public key algorithm name + // string public key blob + // string signature packet.reset(); buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST); buf.putString(_username); @@ -209,6 +220,7 @@ else if(command==SSH_MSG_USERAUTH_FAILURE){ if(partial_success!=0){ throw new JSchPartialAuthException(Util.byte2str(foo)); } + session.auth_failures++; break; } //System.err.println("USERAUTH fail ("+command+")"); diff --git a/src/com/jcraft/jsch/UserInfo.java b/src/main/java/com/jcraft/jsch/UserInfo.java similarity index 96% rename from src/com/jcraft/jsch/UserInfo.java rename to src/main/java/com/jcraft/jsch/UserInfo.java index 6939f22..e1b2a32 100644 --- a/src/com/jcraft/jsch/UserInfo.java +++ b/src/main/java/com/jcraft/jsch/UserInfo.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/Util.java b/src/main/java/com/jcraft/jsch/Util.java similarity index 85% rename from src/com/jcraft/jsch/Util.java rename to src/main/java/com/jcraft/jsch/Util.java index 6b8170d..f990b5d 100644 --- a/src/com/jcraft/jsch/Util.java +++ b/src/main/java/com/jcraft/jsch/Util.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -29,6 +29,9 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING package com.jcraft.jsch; import java.net.Socket; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; class Util{ @@ -40,20 +43,25 @@ private static byte val(byte foo){ } return 0; } - static byte[] fromBase64(byte[] buf, int start, int length){ - byte[] foo=new byte[length]; - int j=0; - for (int i=start;i>>4)); - if(buf[i+2]==(byte)'='){ j++; break;} - foo[j+1]=(byte)(((val(buf[i+1])&0x0f)<<4)|((val(buf[i+2])&0x3c)>>>2)); - if(buf[i+3]==(byte)'='){ j+=2; break;} - foo[j+2]=(byte)(((val(buf[i+2])&0x03)<<6)|(val(buf[i+3])&0x3f)); - j+=3; + static byte[] fromBase64(byte[] buf, int start, int length) throws JSchException { + try { + byte[] foo=new byte[length]; + int j=0; + for (int i=start;i>>4)); + if(buf[i+2]==(byte)'='){ j++; break;} + foo[j+1]=(byte)(((val(buf[i+1])&0x0f)<<4)|((val(buf[i+2])&0x3c)>>>2)); + if(buf[i+3]==(byte)'='){ j+=2; break;} + foo[j+2]=(byte)(((val(buf[i+2])&0x03)<<6)|(val(buf[i+3])&0x3f)); + j+=3; + } + byte[] bar=new byte[j]; + System.arraycopy(foo, 0, bar, 0, j); + return bar; + } + catch(ArrayIndexOutOfBoundsException e) { + throw new JSchException("fromBase64: invalid base64 data", e); } - byte[] bar=new byte[j]; - System.arraycopy(foo, 0, bar, 0, j); - return bar; } static byte[] toBase64(byte[] buf, int start, int length){ @@ -383,7 +391,7 @@ public void run(){ } tmp.interrupt(); tmp=null; - throw new JSchException(message); + throw new JSchException(message, ee[0]); } return socket; } @@ -420,6 +428,17 @@ static String byte2str(byte[] str, int s, int l){ return byte2str(str, s, l, "UTF-8"); } + static String toHex(byte[] str){ + StringBuffer sb = new StringBuffer(); + for(int i = 0; ibsize){ - byte[] tmp=new byte[bsize]; + byte[] tmp = new byte[bsize]; System.arraycopy(key, 0, tmp, 0, bsize); - key=tmp; + key = tmp; } - SecretKeySpec skey=new SecretKeySpec(key, "HmacSHA1"); - mac=Mac.getInstance("HmacSHA1"); + SecretKeySpec skey = new SecretKeySpec(key, algorithm); + mac = Mac.getInstance(algorithm); mac.init(skey); } - private final byte[] tmp=new byte[4]; + + private final byte[] tmp = new byte[4]; public void update(int i){ - tmp[0]=(byte)(i>>>24); - tmp[1]=(byte)(i>>>16); - tmp[2]=(byte)(i>>>8); - tmp[3]=(byte)i; + tmp[0] = (byte)(i>>>24); + tmp[1] = (byte)(i>>>16); + tmp[2] = (byte)(i>>>8); + tmp[3] = (byte)i; update(tmp, 0, 4); } @@ -66,6 +72,7 @@ public void doFinal(byte[] buf, int offset){ mac.doFinal(buf, offset); } catch(ShortBufferException e){ + System.err.println(e); } } diff --git a/src/main/java/com/jcraft/jsch/jce/HMACMD5.java b/src/main/java/com/jcraft/jsch/jce/HMACMD5.java new file mode 100644 index 0000000..df1d68a --- /dev/null +++ b/src/main/java/com/jcraft/jsch/jce/HMACMD5.java @@ -0,0 +1,42 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch.jce; + +import com.jcraft.jsch.MAC; +import javax.crypto.*; +import javax.crypto.spec.*; + +public class HMACMD5 extends HMAC { + public HMACMD5(){ + name = "hmac-md5"; + bsize = 16; + algorithm = "HmacMD5"; + } +} diff --git a/src/com/jcraft/jsch/Identity.java b/src/main/java/com/jcraft/jsch/jce/HMACMD596.java similarity index 78% rename from src/com/jcraft/jsch/Identity.java rename to src/main/java/com/jcraft/jsch/jce/HMACMD596.java index 099fabf..b6fc39f 100644 --- a/src/com/jcraft/jsch/Identity.java +++ b/src/main/java/com/jcraft/jsch/jce/HMACMD596.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -27,15 +27,20 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jcraft.jsch; - -public interface Identity{ - public boolean setPassphrase(byte[] passphrase) throws JSchException; - public byte[] getPublicKeyBlob(); - public byte[] getSignature(byte[] data); - public boolean decrypt(); - public String getAlgName(); - public String getName(); - public boolean isEncrypted(); - public void clear(); +package com.jcraft.jsch.jce; + +public class HMACMD596 extends HMACMD5 { + public HMACMD596(){ + name="hmac-md5-96"; + } + + public int getBlockSize(){ + return 12; + }; + + private final byte[] _buf16 = new byte[16]; + public void doFinal(byte[] buf, int offset){ + super.doFinal(_buf16, 0); + System.arraycopy(_buf16, 0, buf, offset, 12); + } } diff --git a/src/main/java/com/jcraft/jsch/jce/HMACSHA1.java b/src/main/java/com/jcraft/jsch/jce/HMACSHA1.java new file mode 100644 index 0000000..eada19e --- /dev/null +++ b/src/main/java/com/jcraft/jsch/jce/HMACSHA1.java @@ -0,0 +1,38 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch.jce; + +public class HMACSHA1 extends HMAC { + public HMACSHA1(){ + name = "hmac-sha1"; + bsize = 20; + algorithm = "HmacSHA1"; + } +} diff --git a/src/main/java/com/jcraft/jsch/jce/HMACSHA196.java b/src/main/java/com/jcraft/jsch/jce/HMACSHA196.java new file mode 100644 index 0000000..ca03c14 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/jce/HMACSHA196.java @@ -0,0 +1,47 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch.jce; + +public class HMACSHA196 extends HMACSHA1 { + + public HMACSHA196(){ + name = "hmac-sha1-96"; + } + + public int getBlockSize(){ + return 12; + }; + + private final byte[] _buf20 = new byte[20]; + public void doFinal(byte[] buf, int offset){ + super.doFinal(_buf20, 0); + System.arraycopy(_buf20, 0, buf, offset, 12); + } +} diff --git a/src/main/java/com/jcraft/jsch/jce/HMACSHA256.java b/src/main/java/com/jcraft/jsch/jce/HMACSHA256.java new file mode 100644 index 0000000..444b6b4 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/jce/HMACSHA256.java @@ -0,0 +1,38 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2012-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch.jce; + +public class HMACSHA256 extends HMAC { + public HMACSHA256(){ + name = "hmac-sha2-256"; + bsize = 32; + algorithm = "HmacSHA256"; + } +} diff --git a/src/main/java/com/jcraft/jsch/jce/HMACSHA512.java b/src/main/java/com/jcraft/jsch/jce/HMACSHA512.java new file mode 100644 index 0000000..3f5aeb6 --- /dev/null +++ b/src/main/java/com/jcraft/jsch/jce/HMACSHA512.java @@ -0,0 +1,38 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2012-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch.jce; + +public class HMACSHA512 extends HMAC { + public HMACSHA512(){ + name = "hmac-sha2-512"; + bsize = 64; + algorithm = "HmacSHA512"; + } +} diff --git a/src/com/jcraft/jsch/jce/KeyPairGenDSA.java b/src/main/java/com/jcraft/jsch/jce/KeyPairGenDSA.java similarity index 97% rename from src/com/jcraft/jsch/jce/KeyPairGenDSA.java rename to src/main/java/com/jcraft/jsch/jce/KeyPairGenDSA.java index 79e11c6..8b8a291 100644 --- a/src/com/jcraft/jsch/jce/KeyPairGenDSA.java +++ b/src/main/java/com/jcraft/jsch/jce/KeyPairGenDSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/main/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java b/src/main/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java new file mode 100644 index 0000000..e68705a --- /dev/null +++ b/src/main/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java @@ -0,0 +1,96 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015-2016 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.jcraft.jsch.jce; + +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.*; +import com.jcraft.jsch.JSchException; + +public class KeyPairGenECDSA implements com.jcraft.jsch.KeyPairGenECDSA { + byte[] d; + byte[] r; + byte[] s; + ECPublicKey pubKey; + ECPrivateKey prvKey; + ECParameterSpec params; + public void init(int key_size) throws Exception { + String name=null; + if(key_size==256) name="secp256r1"; + else if(key_size==384) name="secp384r1"; + else if(key_size==521) name="secp521r1"; + else throw new JSchException("unsupported key size: "+key_size); + + for(int i = 0; i<1000; i++) { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); + ECGenParameterSpec ecsp = new ECGenParameterSpec(name); + kpg.initialize(ecsp); + KeyPair kp = kpg.genKeyPair(); + prvKey = (ECPrivateKey)kp.getPrivate(); + pubKey = (ECPublicKey)kp.getPublic(); + params=pubKey.getParams(); + d=((ECPrivateKey)prvKey).getS().toByteArray(); + ECPoint w = pubKey.getW(); + r = w.getAffineX().toByteArray(); + s = w.getAffineY().toByteArray(); + + if(r.length!=s.length) continue; + if(key_size==256 && r.length==32) break; + if(key_size==384 && r.length==48) break; + if(key_size==521 && r.length==66) break; + } + if(d.length=64) name="secp521r1"; + else if(r.length>=48) name="secp384r1"; + + AlgorithmParameters param = AlgorithmParameters.getInstance("EC"); + param.init(new ECGenParameterSpec(name)); + ECParameterSpec ecparam = + (ECParameterSpec)param.getParameterSpec(ECParameterSpec.class); + ECPoint w = new ECPoint(new BigInteger(1, r), new BigInteger(1, s)); + PublicKey pubKey = + keyFactory.generatePublic(new ECPublicKeySpec(w, ecparam)); + signature.initVerify(pubKey); + } + + public void setPrvKey(byte[] d) throws Exception{ + + // d must be unsigned value. + d=insert0(d); + + String name="secp256r1"; + if(d.length>=64) name="secp521r1"; + else if(d.length>=48) name="secp384r1"; + + AlgorithmParameters param = AlgorithmParameters.getInstance("EC"); + param.init(new ECGenParameterSpec(name)); + ECParameterSpec ecparam = + (ECParameterSpec)param.getParameterSpec(ECParameterSpec.class); + BigInteger _d = new BigInteger(1, d); + PrivateKey prvKey = + keyFactory.generatePrivate(new ECPrivateKeySpec(_d, ecparam)); + signature.initSign(prvKey); + } + public byte[] sign() throws Exception{ + byte[] sig=signature.sign(); + + // It seems that the output from SunEC is in ASN.1, + // so we have to convert it. + if(sig[0]==0x30 && // in ASN.1 + ((sig[1]+2 == sig.length) || + ((sig[1]&0x80)!=0 && (sig[2]&0xff)+3==sig.length))){// 2bytes for len + + int index=3; + if((sig[1]&0x80)!=0 && (sig[2]&0xff)+3==sig.length) + index=4; + + byte[] r = new byte[sig[index]]; + byte[] s = new byte[sig[index+2+sig[index]]]; + System.arraycopy(sig, index+1, r, 0, r.length); + System.arraycopy(sig, index+3+sig[index], s, 0, s.length); + + r = chop0(r); + s = chop0(s); + + Buffer buf = new Buffer(); + buf.putMPInt(r); + buf.putMPInt(s); + + sig=new byte[buf.getLength()]; + buf.setOffSet(0); + buf.getByte(sig); + } + + return sig; + } + public void update(byte[] foo) throws Exception{ + signature.update(foo); + } + public boolean verify(byte[] sig) throws Exception{ + + // It seems that SunEC expects ASN.1 data, + // so we have to convert it. + if(!(sig[0]==0x30 && // not in ASN.1 + ((sig[1]+2 == sig.length) || + ((sig[1]&0x80)!=0 && (sig[2]&0xff)+3==sig.length)))) { + Buffer b = new Buffer(sig); + + b.getString(); // ecdsa-sha2-nistp256 + b.getInt(); + + byte[] r = b.getMPInt(); + byte[] s = b.getMPInt(); + + r=insert0(r); + s=insert0(s); + + byte[] asn1 = null; + if(r.length<64){ + asn1 = new byte[6+r.length+s.length]; + asn1[0] = (byte)0x30; + asn1[1] = (byte)(4+r.length+s.length); + asn1[2] = (byte)0x02; + asn1[3] = (byte)r.length; + System.arraycopy(r, 0, asn1, 4, r.length); + asn1[r.length+4] = (byte)0x02; + asn1[r.length+5] = (byte)s.length; + System.arraycopy(s, 0, asn1, (6+r.length), s.length); + } + else { + asn1 = new byte[6+r.length+s.length+1]; + asn1[0] = (byte)0x30; + asn1[1] = (byte)0x81; + asn1[2] = (byte)(4+r.length+s.length); + asn1[3] = (byte)0x02; + asn1[4] = (byte)r.length; + System.arraycopy(r, 0, asn1, 5, r.length); + asn1[r.length+5] = (byte)0x02; + asn1[r.length+6] = (byte)s.length; + System.arraycopy(s, 0, asn1, (7+r.length), s.length); + } + sig=asn1; + } + + return signature.verify(sig); + } + + private byte[] insert0(byte[] buf){ + if ((buf[0] & 0x80) == 0) return buf; + byte[] tmp = new byte[buf.length+1]; + System.arraycopy(buf, 0, tmp, 1, buf.length); + bzero(buf); + return tmp; + } + private byte[] chop0(byte[] buf){ + if(buf[0]!=0) return buf; + byte[] tmp = new byte[buf.length-1]; + System.arraycopy(buf, 1, tmp, 0, tmp.length); + bzero(buf); + return tmp; + } + + private void bzero(byte[] buf){ + for(int i = 0; ibsize){ byte[] tmp=new byte[bsize]; System.arraycopy(key, 0, tmp, 0, bsize); diff --git a/src/com/jcraft/jsch/jcraft/HMACMD5.java b/src/main/java/com/jcraft/jsch/jcraft/HMACMD5.java similarity index 96% rename from src/com/jcraft/jsch/jcraft/HMACMD5.java rename to src/main/java/com/jcraft/jsch/jcraft/HMACMD5.java index 69bbe63..c4fcb48 100644 --- a/src/com/jcraft/jsch/jcraft/HMACMD5.java +++ b/src/main/java/com/jcraft/jsch/jcraft/HMACMD5.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/jcraft/HMACMD596.java b/src/main/java/com/jcraft/jsch/jcraft/HMACMD596.java similarity index 96% rename from src/com/jcraft/jsch/jcraft/HMACMD596.java rename to src/main/java/com/jcraft/jsch/jcraft/HMACMD596.java index a36ef47..f806962 100644 --- a/src/com/jcraft/jsch/jcraft/HMACMD596.java +++ b/src/main/java/com/jcraft/jsch/jcraft/HMACMD596.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/jcraft/HMACSHA1.java b/src/main/java/com/jcraft/jsch/jcraft/HMACSHA1.java similarity index 96% rename from src/com/jcraft/jsch/jcraft/HMACSHA1.java rename to src/main/java/com/jcraft/jsch/jcraft/HMACSHA1.java index f3ed188..869c13c 100644 --- a/src/com/jcraft/jsch/jcraft/HMACSHA1.java +++ b/src/main/java/com/jcraft/jsch/jcraft/HMACSHA1.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/jcraft/HMACSHA196.java b/src/main/java/com/jcraft/jsch/jcraft/HMACSHA196.java similarity index 96% rename from src/com/jcraft/jsch/jcraft/HMACSHA196.java rename to src/main/java/com/jcraft/jsch/jcraft/HMACSHA196.java index c9d333e..8f8e327 100644 --- a/src/com/jcraft/jsch/jcraft/HMACSHA196.java +++ b/src/main/java/com/jcraft/jsch/jcraft/HMACSHA196.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/com/jcraft/jsch/jgss/GSSContextKrb5.java b/src/main/java/com/jcraft/jsch/jgss/GSSContextKrb5.java similarity index 98% rename from src/com/jcraft/jsch/jgss/GSSContextKrb5.java rename to src/main/java/com/jcraft/jsch/jgss/GSSContextKrb5.java index 7696ba8..cf3ca48 100644 --- a/src/com/jcraft/jsch/jgss/GSSContextKrb5.java +++ b/src/main/java/com/jcraft/jsch/jgss/GSSContextKrb5.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2016 ymnk, JCraft,Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: