From ce48cc8962233d97a39d1f61d661d4e57b7eb1e4 Mon Sep 17 00:00:00 2001 From: "Brian P. Hinz" Date: Sat, 26 Dec 2015 21:48:11 -0500 Subject: [PATCH] Upgrade in-tree jsch and jzlib to latest upstream versions --- java/CMakeLists.txt | 47 +- java/com/jcraft/jsch/Buffer.java | 49 +- java/com/jcraft/jsch/ChangeLog | 629 ++++++++---- java/com/jcraft/jsch/Channel.java | 137 ++- .../jcraft/jsch/ChannelAgentForwarding.java | 5 +- java/com/jcraft/jsch/ChannelDirectTCPIP.java | 21 +- java/com/jcraft/jsch/ChannelExec.java | 2 +- .../jcraft/jsch/ChannelForwardedTCPIP.java | 161 +-- java/com/jcraft/jsch/ChannelSession.java | 19 +- java/com/jcraft/jsch/ChannelSftp.java | 440 +++++++- java/com/jcraft/jsch/ChannelShell.java | 2 +- java/com/jcraft/jsch/ChannelSubsystem.java | 2 +- java/com/jcraft/jsch/ChannelX11.java | 3 +- java/com/jcraft/jsch/Cipher.java | 2 +- java/com/jcraft/jsch/CipherNone.java | 2 +- java/com/jcraft/jsch/Compression.java | 2 +- java/com/jcraft/jsch/ConfigRepository.java | 55 + java/com/jcraft/jsch/DH.java | 6 +- java/com/jcraft/jsch/DHEC256.java | 37 + java/com/jcraft/jsch/DHEC384.java | 37 + java/com/jcraft/jsch/DHEC521.java | 37 + java/com/jcraft/jsch/DHECN.java | 187 ++++ java/com/jcraft/jsch/DHG1.java | 129 +-- java/com/jcraft/jsch/DHG14.java | 110 +- java/com/jcraft/jsch/DHGEX.java | 158 +-- java/com/jcraft/jsch/DHGEX256.java | 36 + java/com/jcraft/jsch/ECDH.java | 37 + .../com/jcraft/jsch/ForwardedTCPIPDaemon.java | 2 +- java/com/jcraft/jsch/GSSContext.java | 2 +- java/com/jcraft/jsch/HASH.java | 2 +- java/com/jcraft/jsch/HostKey.java | 50 +- java/com/jcraft/jsch/HostKeyRepository.java | 52 +- java/com/jcraft/jsch/IO.java | 2 +- java/com/jcraft/jsch/Identity.java | 44 +- java/com/jcraft/jsch/IdentityFile.java | 950 ++---------------- java/com/jcraft/jsch/IdentityRepository.java | 79 +- java/com/jcraft/jsch/JSch.java | 340 ++++++- .../jcraft/jsch/JSchAuthCancelException.java | 2 +- java/com/jcraft/jsch/JSchException.java | 2 +- .../jcraft/jsch/JSchPartialAuthException.java | 2 +- java/com/jcraft/jsch/KeyExchange.java | 199 +++- java/com/jcraft/jsch/KeyPair.java | 660 ++++++++++-- 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 | 173 +++- java/com/jcraft/jsch/LICENSE.txt | 2 +- .../jcraft/jsch/LocalIdentityRepository.java | 66 +- java/com/jcraft/jsch/Logger.java | 2 +- java/com/jcraft/jsch/MAC.java | 2 +- java/com/jcraft/jsch/OpenSSHConfig.java | 264 +++++ java/com/jcraft/jsch/PBKDF.java | 34 + java/com/jcraft/jsch/Packet.java | 2 +- java/com/jcraft/jsch/PortWatcher.java | 22 +- 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/README | 16 +- 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 +- java/com/jcraft/jsch/RequestSubsystem.java | 2 +- java/com/jcraft/jsch/RequestWindowChange.java | 2 +- java/com/jcraft/jsch/RequestX11.java | 2 +- java/com/jcraft/jsch/ServerSocketFactory.java | 2 +- java/com/jcraft/jsch/Session.java | 922 +++++++++++++++-- java/com/jcraft/jsch/SftpATTRS.java | 49 +- java/com/jcraft/jsch/SftpException.java | 2 +- java/com/jcraft/jsch/SftpProgressMonitor.java | 2 +- java/com/jcraft/jsch/SftpStatVFS.java | 122 +++ java/com/jcraft/jsch/Signature.java | 37 + java/com/jcraft/jsch/SignatureDSA.java | 8 +- java/com/jcraft/jsch/SignatureECDSA.java | 35 + java/com/jcraft/jsch/SignatureRSA.java | 8 +- 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 | 4 +- java/com/jcraft/jsch/UserAuthNone.java | 2 +- java/com/jcraft/jsch/UserAuthPassword.java | 2 +- java/com/jcraft/jsch/UserAuthPublicKey.java | 33 +- java/com/jcraft/jsch/UserInfo.java | 2 +- java/com/jcraft/jsch/Util.java | 83 +- 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 +- java/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 + java/com/jcraft/jsch/jce/ECDHN.java | 146 +++ java/com/jcraft/jsch/jce/HMAC.java | 82 ++ java/com/jcraft/jsch/jce/HMACMD5.java | 45 +- java/com/jcraft/jsch/jce/HMACMD596.java | 49 +- java/com/jcraft/jsch/jce/HMACSHA1.java | 49 +- java/com/jcraft/jsch/jce/HMACSHA196.java | 49 +- java/com/jcraft/jsch/jce/HMACSHA256.java | 38 + java/com/jcraft/jsch/jce/HMACSHA512.java | 38 + java/com/jcraft/jsch/jce/KeyPairGenDSA.java | 2 +- java/com/jcraft/jsch/jce/KeyPairGenECDSA.java | 96 ++ java/com/jcraft/jsch/jce/KeyPairGenRSA.java | 2 +- java/com/jcraft/jsch/jce/MD5.java | 2 +- java/com/jcraft/jsch/jce/PBKDF.java | 59 ++ java/com/jcraft/jsch/jce/Random.java | 2 +- java/com/jcraft/jsch/jce/SHA1.java | 2 +- java/com/jcraft/jsch/jce/SHA256.java | 51 + java/com/jcraft/jsch/jce/SHA384.java | 49 + java/com/jcraft/jsch/jce/SHA512.java | 49 + java/com/jcraft/jsch/jce/SignatureDSA.java | 2 +- java/com/jcraft/jsch/jce/SignatureECDSA.java | 186 ++++ java/com/jcraft/jsch/jce/SignatureRSA.java | 2 +- java/com/jcraft/jsch/jce/TripleDESCBC.java | 12 +- java/com/jcraft/jsch/jce/TripleDESCTR.java | 12 +- java/com/jcraft/jsch/jcraft/Compression.java | 3 +- java/com/jcraft/jsch/jcraft/HMAC.java | 3 +- java/com/jcraft/jsch/jcraft/HMACMD5.java | 2 +- java/com/jcraft/jsch/jcraft/HMACMD596.java | 2 +- java/com/jcraft/jsch/jcraft/HMACSHA1.java | 2 +- java/com/jcraft/jsch/jcraft/HMACSHA196.java | 2 +- java/com/jcraft/jsch/jgss/GSSContextKrb5.java | 2 +- java/com/jcraft/jzlib/Deflate.java | 20 +- java/com/jcraft/jzlib/Deflater.java | 171 ++++ .../jcraft/jzlib/DeflaterOutputStream.java | 181 ++++ java/com/jcraft/jzlib/GZIPException.java | 44 + java/com/jcraft/jzlib/GZIPInputStream.java | 145 +++ java/com/jcraft/jzlib/GZIPOutputStream.java | 90 ++ java/com/jcraft/jzlib/Inflate.java | 46 +- java/com/jcraft/jzlib/Inflater.java | 168 ++++ .../com/jcraft/jzlib/InflaterInputStream.java | 247 +++++ java/com/jcraft/jzlib/JZlib.java | 9 + java/com/jcraft/jzlib/Tree.java | 15 +- java/com/jcraft/jzlib/ZInputStream.java | 2 +- java/com/jcraft/jzlib/ZStream.java | 36 +- java/com/jcraft/jzlib/ZStreamException.java | 88 +- 153 files changed, 8073 insertions(+), 2368 deletions(-) create mode 100644 java/com/jcraft/jsch/ConfigRepository.java create mode 100644 java/com/jcraft/jsch/DHEC256.java create mode 100644 java/com/jcraft/jsch/DHEC384.java create mode 100644 java/com/jcraft/jsch/DHEC521.java create mode 100644 java/com/jcraft/jsch/DHECN.java create mode 100644 java/com/jcraft/jsch/DHGEX256.java create mode 100644 java/com/jcraft/jsch/ECDH.java create mode 100644 java/com/jcraft/jsch/KeyPairECDSA.java create mode 100644 java/com/jcraft/jsch/KeyPairGenECDSA.java create mode 100644 java/com/jcraft/jsch/KeyPairPKCS8.java create mode 100644 java/com/jcraft/jsch/OpenSSHConfig.java create mode 100644 java/com/jcraft/jsch/PBKDF.java create mode 100644 java/com/jcraft/jsch/SftpStatVFS.java create mode 100644 java/com/jcraft/jsch/Signature.java create mode 100644 java/com/jcraft/jsch/SignatureECDSA.java create mode 100644 java/com/jcraft/jsch/jce/ECDH256.java create mode 100644 java/com/jcraft/jsch/jce/ECDH384.java create mode 100644 java/com/jcraft/jsch/jce/ECDH521.java create mode 100644 java/com/jcraft/jsch/jce/ECDHN.java create mode 100644 java/com/jcraft/jsch/jce/HMAC.java create mode 100644 java/com/jcraft/jsch/jce/HMACSHA256.java create mode 100644 java/com/jcraft/jsch/jce/HMACSHA512.java create mode 100644 java/com/jcraft/jsch/jce/KeyPairGenECDSA.java create mode 100644 java/com/jcraft/jsch/jce/PBKDF.java create mode 100644 java/com/jcraft/jsch/jce/SHA256.java create mode 100644 java/com/jcraft/jsch/jce/SHA384.java create mode 100644 java/com/jcraft/jsch/jce/SHA512.java create mode 100644 java/com/jcraft/jsch/jce/SignatureECDSA.java create mode 100644 java/com/jcraft/jzlib/Deflater.java create mode 100644 java/com/jcraft/jzlib/DeflaterOutputStream.java create mode 100644 java/com/jcraft/jzlib/GZIPException.java create mode 100644 java/com/jcraft/jzlib/GZIPInputStream.java create mode 100644 java/com/jcraft/jzlib/GZIPOutputStream.java create mode 100644 java/com/jcraft/jzlib/Inflater.java create mode 100644 java/com/jcraft/jzlib/InflaterInputStream.java diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt index 8dd09d1b..a076d958 100644 --- a/java/CMakeLists.txt +++ b/java/CMakeLists.txt @@ -36,9 +36,15 @@ set(JAVA_CLASSES "") set(JSCH_CLASSNAMES DH + DHEC256 + DHEC384 + DHEC521 + DHECN + DHGEX256 DHG1 DHG14 DHGEX + ECDH JSch Session UserAuth @@ -47,28 +53,41 @@ set(JSCH_CLASSNAMES UserAuthPublicKey UserAuthNone jce/AES128CBC - jce/AES192CTR - jce/ARCFOUR128 - jce/BlowfishCBC - jce/HMACMD5 - jce/KeyPairGenDSA - jce/Random - jce/SignatureRSA jce/AES128CTR - jce/AES256CBC - jce/ARCFOUR256 - jce/DH - jce/HMACSHA196 - jce/KeyPairGenRSA - jce/SHA1 - jce/TripleDESCBC jce/AES192CBC + jce/AES192CTR + jce/AES256CBC jce/AES256CTR jce/ARCFOUR + jce/ARCFOUR128 + jce/ARCFOUR256 + jce/BlowfishCBC + jce/DH + jce/ECDH256 + jce/ECDH384 + jce/ECDH521 + jce/ECDHN + jce/HMAC + jce/HMACMD5 jce/HMACMD596 jce/HMACSHA1 + jce/HMACSHA196 + jce/HMACSHA256 + jce/HMACSHA512 + jce/KeyPairGenDSA + jce/KeyPairGenECDSA + jce/KeyPairGenRSA jce/MD5 + jce/PBKDF + jce/Random + jce/SHA1 + jce/SHA256 + jce/SHA384 + jce/SHA512 jce/SignatureDSA + jce/SignatureECDSA + jce/SignatureRSA + jce/TripleDESCBC jce/TripleDESCTR jcraft/Compression jcraft/HMAC diff --git a/java/com/jcraft/jsch/Buffer.java b/java/com/jcraft/jsch/Buffer.java index a3135a15..c54e4292 100644 --- a/java/com/jcraft/jsch/Buffer.java +++ b/java/com/jcraft/jsch/Buffer.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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 @@ public class Buffer{ } void checkFreeSize(int n){ - if(buffer.length 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 @@ -17,34 +249,34 @@ Changes since version 0.1.45: - 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 + volatile. FIXED - bugfix: use local window size offered by the remote in sftp put. - FIXED + 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 + 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 + FIXED - bugfix: Channel X11 had leaked some resources. - FIXED + FIXED - bugfix: packet compression may break sessions - in some case(transferring deflated data). FIXED + in some case(transferring deflated data). FIXED - bugfix: failed to set dev-null for logger - FIXED + 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 + 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 + 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 +- 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 @@ -53,16 +285,16 @@ Changes since version 0.1.44: (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. @@ -71,26 +303,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 @@ -102,19 +334,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. @@ -138,7 +370,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. @@ -151,18 +383,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 @@ -171,20 +403,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 @@ -192,16 +424,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. @@ -213,8 +445,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' @@ -228,15 +460,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". @@ -244,11 +476,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. @@ -264,7 +496,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 @@ -278,7 +511,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 @@ -289,12 +522,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. @@ -307,7 +540,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 @@ -345,48 +578,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. @@ -397,45 +630,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. @@ -449,11 +682,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" @@ -463,37 +696,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. @@ -501,31 +734,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. @@ -534,15 +767,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. @@ -553,36 +786,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. @@ -591,10 +824,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. @@ -604,96 +837,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 @@ -701,8 +934,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. @@ -717,9 +950,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. @@ -730,47 +963,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. @@ -778,17 +1011,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/java/com/jcraft/jsch/Channel.java b/java/com/jcraft/jsch/Channel.java index 73cc4dbf..8c060dd6 100644 --- a/java/com/jcraft/jsch/Channel.java +++ b/java/com/jcraft/jsch/Channel.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,7 +35,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; -@SuppressWarnings({"rawtypes","unchecked"}) + public abstract class Channel implements Runnable{ static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION= 91; @@ -192,29 +192,38 @@ public abstract class Channel implements Runnable{ 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*1024 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(); @@ -384,12 +456,15 @@ public abstract class Channel implements Runnable{ 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); @@ -445,12 +520,15 @@ public abstract class Channel implements Runnable{ 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); } @@ -561,8 +639,25 @@ public abstract class Channel implements Runnable{ } } 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); } } @@ -636,7 +731,7 @@ public abstract class Channel implements Runnable{ Packet packet = genChannelOpenPacket(); _session.write(packet); - int retry=10; + int retry=2000; long start=System.currentTimeMillis(); long timeout=connectTimeout; if(timeout!=0L) retry = 1; @@ -651,7 +746,7 @@ public abstract class Channel implements Runnable{ } } try{ - long t = timeout==0L ? 5000L : timeout; + long t = timeout==0L ? 10L : timeout; this.notifyme=1; wait(t); } diff --git a/java/com/jcraft/jsch/ChannelAgentForwarding.java b/java/com/jcraft/jsch/ChannelAgentForwarding.java index 52e2db19..32db395d 100644 --- a/java/com/jcraft/jsch/ChannelAgentForwarding.java +++ b/java/com/jcraft/jsch/ChannelAgentForwarding.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2015 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,7 +32,6 @@ package com.jcraft.jsch; import java.net.*; import java.util.Vector; -@SuppressWarnings({"rawtypes"}) class ChannelAgentForwarding extends Channel{ static private final int LOCAL_WINDOW_SIZE_MAX=0x20000; @@ -122,7 +121,7 @@ class ChannelAgentForwarding extends Channel{ throw new java.io.IOException(e.toString()); } - IdentityRepository irepo = _session.jsch.getIdentityRepository(); + IdentityRepository irepo = _session.getIdentityRepository(); UserInfo userinfo=_session.getUserInfo(); mbuf.reset(); diff --git a/java/com/jcraft/jsch/ChannelDirectTCPIP.java b/java/com/jcraft/jsch/ChannelDirectTCPIP.java index c8af6a2b..dde42442 100644 --- a/java/com/jcraft/jsch/ChannelDirectTCPIP.java +++ b/java/com/jcraft/jsch/ChannelDirectTCPIP.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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: @@ -54,7 +54,8 @@ public class ChannelDirectTCPIP extends Channel{ io=new IO(); } - public void connect() throws JSchException{ + public void connect(int connectTimeout) throws JSchException{ + this.connectTimeout=connectTimeout; try{ Session _session=getSession(); if(!_session.isConnected()){ @@ -69,6 +70,9 @@ public class ChannelDirectTCPIP extends Channel{ } thread.start(); } + else { + sendChannelOpen(); + } } catch(Exception e){ io.close(); @@ -116,7 +120,16 @@ public class ChannelDirectTCPIP extends Channel{ } } catch(Exception e){ + // Whenever an exception is thrown by sendChannelOpen(), + // 'connected' is false. + if(!connected){ + connected=true; + } + disconnect(); + return; } + + eof(); disconnect(); } @@ -133,7 +146,9 @@ public class ChannelDirectTCPIP extends Channel{ public void setOrgPort(int foo){this.originator_port=foo;} protected Packet genChannelOpenPacket(){ - Buffer buf = new Buffer(150); + 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 // diff --git a/java/com/jcraft/jsch/ChannelExec.java b/java/com/jcraft/jsch/ChannelExec.java index 45322b63..10722c22 100644 --- a/java/com/jcraft/jsch/ChannelExec.java +++ b/java/com/jcraft/jsch/ChannelExec.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/ChannelForwardedTCPIP.java b/java/com/jcraft/jsch/ChannelForwardedTCPIP.java index 39972e19..41f9bebf 100644 --- a/java/com/jcraft/jsch/ChannelForwardedTCPIP.java +++ b/java/com/jcraft/jsch/ChannelForwardedTCPIP.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,11 +31,11 @@ package com.jcraft.jsch; import java.net.*; import java.io.*; +import java.util.Vector; -@SuppressWarnings({"rawtypes","unchecked"}) 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; @@ -43,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(); @@ -61,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(); @@ -71,15 +69,14 @@ public class ChannelForwardedTCPIP extends Channel{ ), 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()); @@ -155,32 +152,29 @@ public class ChannelForwardedTCPIP extends Channel{ // 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)); @@ -100,11 +99,11 @@ class ChannelSession extends Channel{ /** * 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){ @@ -120,9 +119,9 @@ class ChannelSession extends Channel{ /** * 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; @@ -139,12 +138,12 @@ class ChannelSession extends Channel{ /** * 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); diff --git a/java/com/jcraft/jsch/ChannelSftp.java b/java/com/jcraft/jsch/ChannelSftp.java index a278ed61..d2c0913d 100644 --- a/java/com/jcraft/jsch/ChannelSftp.java +++ b/java/com/jcraft/jsch/ChannelSftp.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,7 +33,6 @@ import java.io.*; import java.util.Vector; -@SuppressWarnings({"rawtypes","unchecked"}) public class ChannelSftp extends ChannelSession{ static private final int LOCAL_MAXIMUM_PACKET_SIZE=32*1024; @@ -150,6 +149,11 @@ public class ChannelSftp extends ChannelSession{ 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 @@ -178,7 +182,15 @@ public class ChannelSftp extends ChannelSession{ private String fEncoding=UTF8; private boolean fEncoding_is_utf8=true; - private RequestQueue rq = new RequestQueue(10); + 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); @@ -186,11 +198,18 @@ public class ChannelSftp extends ChannelSession{ 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(); } - ChannelSftp(){ + public ChannelSftp(){ super(); setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX); setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX); @@ -249,8 +268,8 @@ public class ChannelSftp extends ChannelSession{ 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; @@ -265,6 +284,28 @@ public class ChannelSftp extends ChannelSession{ } } + 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){ @@ -330,6 +371,17 @@ public class ChannelSftp extends ChannelSession{ 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{ @@ -446,6 +498,17 @@ public class ChannelSftp extends ChannelSession{ 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{ @@ -468,10 +531,6 @@ public class ChannelSftp extends ChannelSession{ 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, @@ -481,7 +540,13 @@ public class ChannelSftp extends ChannelSession{ _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()); @@ -583,7 +648,6 @@ public class ChannelSftp extends ChannelSession{ if((seq-1)==startid || ((seq-startid)-ackcount)>=bulk_requests){ while(((seq-startid)-ackcount)>=bulk_requests){ - if(this.rwsize>=foo) break; if(checkStatus(ackid, header)){ int _ackid = ackid[0]; if(startid>_ackid || _ackid>seq-1){ @@ -635,6 +699,18 @@ public class ChannelSftp extends ChannelSession{ 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{ try{ ((MyPipedInputStream)io_in).updateReadSide(); @@ -987,7 +1063,16 @@ public class ChannelSftp extends ChannelSession{ length=header.length; type=header.type; - RequestQueue.Request rr = rq.get(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); + continue; + } if(type==SSH_FXP_STATUS){ fill(buf, length); @@ -1079,6 +1164,12 @@ public class ChannelSftp extends ChannelSession{ private class RequestQueue { + class OutOfOrderException extends Exception { + long offset; + OutOfOrderException(long offset){ + this.offset=offset; + } + } class Request { int id; long offset; @@ -1109,15 +1200,27 @@ public class ChannelSftp extends ChannelSession{ count++; } - Request get(int id){ + Request get(int id) throws OutOfOrderException, SftpException { count -= 1; - int i=head; + int i = head; head++; if(head==rrq.length) head=0; - if(rrq[i].id!=id){ - System.err.println("The request is not in order."); + 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{ @@ -1193,6 +1315,8 @@ public class ChannelSftp extends ChannelSession{ final byte[] handle=buf.getString(); // handle + rq.init(); + java.io.InputStream in=new java.io.InputStream(){ long offset=skip; boolean closed=false; @@ -1200,6 +1324,8 @@ public class ChannelSftp extends ChannelSession{ 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; @@ -1248,14 +1374,38 @@ public class ChannelSftp extends ChannelSession{ len=1024; } - try{sendREAD(handle, offset, len);} - catch(Exception e){ throw new IOException("error"); } + if(rq.count()==0) { + 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"); } @@ -1270,6 +1420,7 @@ public class ChannelSftp extends ChannelSession{ //throwStatusError(buf, i); throw new IOException("error"); } + buf.rewind(); fill(buf.buffer, 0, 4); int length_of_data = buf.getInt(); rest_length-=4; @@ -1319,6 +1470,21 @@ public class ChannelSftp extends ChannelSession{ 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(); @@ -1417,9 +1606,11 @@ public class ChannelSftp extends ChannelSession{ throwStatusError(buf, i); } + int cancel = LsEntrySelector.CONTINUE; byte[] handle=buf.getString(); // handle - while(true){ + while(cancel==LsEntrySelector.CONTINUE){ + sendREADDIR(handle); header=header(buf, header); @@ -1461,6 +1652,11 @@ public class ChannelSftp extends ChannelSession{ } SftpATTRS attrs=SftpATTRS.getATTR(buf); + if(cancel==LsEntrySelector.BREAK){ + count--; + continue; + } + boolean find=false; String f=null; if(pattern==null){ @@ -1491,7 +1687,8 @@ public class ChannelSftp extends ChannelSession{ else{ l=Util.byte2str(longname, fEncoding); } - v.addElement(new LsEntry(f, l, attrs)); + + cancel = selector.select(new LsEntry(f, l, attrs)); } count--; @@ -1516,7 +1713,6 @@ public class ChannelSftp extends ChannelSession{ } */ - return v; } catch(Exception e){ if(e instanceof SftpException) throw (SftpException)e; @@ -1525,6 +1721,7 @@ public class ChannelSftp extends ChannelSession{ throw new SftpException(SSH_FX_FAILURE, ""); } } + public String readlink(String path) throws SftpException{ try{ if(server_version<3){ @@ -1574,6 +1771,7 @@ public class ChannelSftp extends ChannelSession{ } return null; } + public void symlink(String oldpath, String newpath) throws SftpException{ if(server_version<3){ throw new SftpException(SSH_FX_OP_UNSUPPORTED, @@ -1583,10 +1781,17 @@ public class ChannelSftp extends ChannelSession{ try{ ((MyPipedInputStream)io_in).updateReadSide(); - oldpath=remoteAbsolutePath(oldpath); + 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); @@ -1619,6 +1824,58 @@ public class ChannelSftp extends ChannelSession{ } } + 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, @@ -1958,6 +2215,66 @@ public class ChannelSftp extends ChannelSession{ return _stat(Util.str2byte(path, fEncoding)); } + 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(); @@ -2161,6 +2478,14 @@ public class ChannelSftp extends ChannelSession{ 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); } @@ -2193,6 +2518,9 @@ public class ChannelSftp extends ChannelSession{ 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); } @@ -2203,7 +2531,8 @@ public class ChannelSftp extends ChannelSession{ 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); @@ -2227,19 +2556,44 @@ public class ChannelSftp extends ChannelSession{ 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, @@ -2649,4 +3003,26 @@ public class ChannelSftp extends ChannelSession{ 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/java/com/jcraft/jsch/ChannelShell.java b/java/com/jcraft/jsch/ChannelShell.java index eeb24a39..25fad048 100644 --- a/java/com/jcraft/jsch/ChannelShell.java +++ b/java/com/jcraft/jsch/ChannelShell.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/ChannelSubsystem.java b/java/com/jcraft/jsch/ChannelSubsystem.java index 3f33bf3e..6df855c7 100644 --- a/java/com/jcraft/jsch/ChannelSubsystem.java +++ b/java/com/jcraft/jsch/ChannelSubsystem.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2005-2015 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/java/com/jcraft/jsch/ChannelX11.java b/java/com/jcraft/jsch/ChannelX11.java index eb66bb66..6a0d248c 100644 --- a/java/com/jcraft/jsch/ChannelX11.java +++ b/java/com/jcraft/jsch/ChannelX11.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,7 +31,6 @@ package com.jcraft.jsch; import java.net.*; -@SuppressWarnings({"rawtypes","unchecked"}) class ChannelX11 extends Channel{ static private final int LOCAL_WINDOW_SIZE_MAX=0x20000; diff --git a/java/com/jcraft/jsch/Cipher.java b/java/com/jcraft/jsch/Cipher.java index cc7084e6..1fe1c540 100644 --- a/java/com/jcraft/jsch/Cipher.java +++ b/java/com/jcraft/jsch/Cipher.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/CipherNone.java b/java/com/jcraft/jsch/CipherNone.java index 61f836ab..542b6bcd 100644 --- a/java/com/jcraft/jsch/CipherNone.java +++ b/java/com/jcraft/jsch/CipherNone.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/Compression.java b/java/com/jcraft/jsch/Compression.java index 7ae79220..ad80abc1 100644 --- a/java/com/jcraft/jsch/Compression.java +++ b/java/com/jcraft/jsch/Compression.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/ConfigRepository.java b/java/com/jcraft/jsch/ConfigRepository.java new file mode 100644 index 00000000..5afa4eaf --- /dev/null +++ b/java/com/jcraft/jsch/ConfigRepository.java @@ -0,0 +1,55 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2013-2015 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 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/java/com/jcraft/jsch/DH.java b/java/com/jcraft/jsch/DH.java index 963f13c2..565d1cfa 100644 --- a/java/com/jcraft/jsch/DH.java +++ b/java/com/jcraft/jsch/DH.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/DHEC256.java b/java/com/jcraft/jsch/DHEC256.java new file mode 100644 index 00000000..13016889 --- /dev/null +++ b/java/com/jcraft/jsch/DHEC256.java @@ -0,0 +1,37 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015 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/java/com/jcraft/jsch/DHEC384.java b/java/com/jcraft/jsch/DHEC384.java new file mode 100644 index 00000000..47cdf5d3 --- /dev/null +++ b/java/com/jcraft/jsch/DHEC384.java @@ -0,0 +1,37 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015 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/java/com/jcraft/jsch/DHEC521.java b/java/com/jcraft/jsch/DHEC521.java new file mode 100644 index 00000000..0bc070a8 --- /dev/null +++ b/java/com/jcraft/jsch/DHEC521.java @@ -0,0 +1,37 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015 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/java/com/jcraft/jsch/DHECN.java b/java/com/jcraft/jsch/DHECN.java new file mode 100644 index 00000000..f4aa123c --- /dev/null +++ b/java/com/jcraft/jsch/DHECN.java @@ -0,0 +1,187 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015 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/java/com/jcraft/jsch/DHG1.java b/java/com/jcraft/jsch/DHG1.java index 655c196c..aa371fed 100644 --- a/java/com/jcraft/jsch/DHG1.java +++ b/java/com/jcraft/jsch/DHG1.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package com.jcraft.jsch; -@SuppressWarnings({"rawtypes"}) public class DHG1 extends KeyExchange{ static final byte[] g={ 2 }; @@ -56,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; @@ -88,8 +77,6 @@ public class DHG1 extends KeyExchange{ 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()); @@ -156,25 +143,15 @@ public class DHG1 extends KeyExchange{ } 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; iihost 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/java/com/jcraft/jsch/IO.java b/java/com/jcraft/jsch/IO.java index 65535ba3..866d4c36 100644 --- a/java/com/jcraft/jsch/IO.java +++ b/java/com/jcraft/jsch/IO.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/Identity.java b/java/com/jcraft/jsch/Identity.java index 2f8cb80e..331ae7e9 100644 --- a/java/com/jcraft/jsch/Identity.java +++ b/java/com/jcraft/jsch/Identity.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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: @@ -30,12 +30,54 @@ 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/java/com/jcraft/jsch/IdentityFile.java b/java/com/jcraft/jsch/IdentityFile.java index cc66dfe2..4ffdaa7a 100644 --- a/java/com/jcraft/jsch/IdentityFile.java +++ b/java/com/jcraft/jsch/IdentityFile.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,926 +31,100 @@ package com.jcraft.jsch; import java.io.*; -@SuppressWarnings({"rawtypes","static"}) 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; + private KeyPair kpair; + private String identity; 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); + 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{ - 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; - - // 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)){ - - Buffer buf=new Buffer(prvkey); - String _type = new String(buf.getString()); // ssh-rsa - - if(_type.equals("ssh-rsa")){ - type=RSA; - n_array=buf.getString(); - e_array=buf.getString(); - d_array=buf.getString(); - buf.getString(); - buf.getString(); - buf.getString(); - this.identity += new String(buf.getString()); - } - else if(_type.equals("ssh-dss")){ - type=DSS; - P_array=buf.getString(); - Q_array=buf.getString(); - G_array=buf.getString(); - pub_array=buf.getString(); - prv_array=buf.getString(); - this.identity += new String(buf.getString()); - } - else{ - throw new JSchException("privatekey: invalid key "+new String(prvkey, 4, 7)); - } - encoded_data=prvkey; - encrypted=false; - keytype=OPENSSH; - return; - } - - /* TODO: IdentityFile should use KeyPair. - * The following logic exists also in KeyPair. It is redundant. - */ - 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()); - } + /** + * 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(){ - 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; + 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){ - 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; + throw new RuntimeException("not implemented"); } - public boolean isEncrypted(){ - return encrypted; + /** + * 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; } - 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()); + /** + * 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(){ - Util.bzero(encoded_data); - Util.bzero(prv_array); - Util.bzero(d_array); - Util.bzero(key); - Util.bzero(iv); + kpair.dispose(); + kpair = null; } - public void finalize (){ - clear(); + /** + * 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/java/com/jcraft/jsch/IdentityRepository.java b/java/com/jcraft/jsch/IdentityRepository.java index c6b60d1c..018f3fa2 100644 --- a/java/com/jcraft/jsch/IdentityRepository.java +++ b/java/com/jcraft/jsch/IdentityRepository.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2012-2015 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,85 @@ package com.jcraft.jsch; import java.util.Vector; -@SuppressWarnings({"rawtypes"}) 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/java/com/jcraft/jsch/JSch.java b/java/com/jcraft/jsch/JSch.java index 47fa29ae..b6bc84b7 100644 --- a/java/com/jcraft/jsch/JSch.java +++ b/java/com/jcraft/jsch/JSch.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,28 +32,25 @@ package com.jcraft.jsch; import java.io.InputStream; import java.util.Vector; -@SuppressWarnings({"rawtypes","unchecked"}) public class JSch{ - public static final String VERSION = "0.1.46"; + /** + * The version number. + */ + public static final String VERSION = "0.1.53"; 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-group14-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("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-cbc,aes256-cbc"); + "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-cbc,aes256-cbc"); + "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-sha1-96,hmac-md5-96"); - config.put("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96"); + 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.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", ""); @@ -65,21 +62,42 @@ public class JSch{ config.put("diffie-hellman-group1-sha1", "com.jcraft.jsch.DHG1"); config.put("diffie-hellman-group14-sha1", - "com.jcraft.jsch.DHG14"); + "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"); @@ -106,30 +124,60 @@ public class JSch{ 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("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"); - config.put("CheckKexes", "diffie-hellman-group14-sha1"); + 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 identityRepository = + 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){ - this.identityRepository = identityRepository; + if(identityRepository == null){ + this.identityRepository = defaultIdentityRepository; + } + else{ + this.identityRepository = identityRepository; + } } - synchronized IdentityRepository getIdentityRepository(){ + 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(){ @@ -139,7 +187,9 @@ public class JSch{ 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")){ @@ -151,21 +201,77 @@ public class JSch{ } 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); } - public Session getSession(String username, String host) throws JSchException { return getSession(username, 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(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); + Session s = new Session(this, username, host, port); return s; } @@ -180,10 +286,30 @@ public class JSch{ 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){ @@ -193,6 +319,17 @@ public class JSch{ } } + /** + * 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){ @@ -202,15 +339,47 @@ public class JSch{ } } + /** + * 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){ @@ -221,20 +390,70 @@ public class JSch{ 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{ @@ -251,13 +470,21 @@ public class JSch{ if(identityRepository instanceof LocalIdentityRepository){ ((LocalIdentityRepository)identityRepository).add(identity); } + else if(identity instanceof IdentityFile && !identity.isEncrypted()) { + identityRepository.add(((IdentityFile)identity).getKeyPair().forSSHAgent()); + } else { - // TODO + synchronized(this){ + if(!(identityRepository instanceof IdentityRepository.Wrapper)){ + setIdentityRepository(new IdentityRepository.Wrapper(identityRepository)); + } + } + ((IdentityRepository.Wrapper)identityRepository).add(identity); } } /** - * @deprecated use JSch#removeIdentity(Identity identity) + * @deprecated use #removeIdentity(Identity identity) */ public void removeIdentity(String name) throws JSchException{ Vector identities = identityRepository.getIdentities(); @@ -265,15 +492,32 @@ public class JSch{ Identity identity=(Identity)(identities.elementAt(i)); if(!identity.getName().equals(name)) continue; - identityRepository.remove(identity.getPublicKeyBlob()); - break; + if(identityRepository instanceof LocalIdentityRepository){ + ((LocalIdentityRepository)identityRepository).remove(identity); + } + else + identityRepository.remove(identity.getPublicKeyBlob()); } } + /** + * Removes the identity from identityRepository. + * + * @param identity the indentity to be removed. + * + * @throws JSchException if identity 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(); @@ -284,16 +528,32 @@ public class JSch{ return foo; } + /** + * Removes all identities from identityRepository. + * + * @throws JSchException if identityReposory has problems. + */ public void removeAllIdentity() throws JSchException{ identityRepository.removeAll(); } + /** + * Returns the config value for the specified key. + * + * @param key key for the configuration. + * @return config value + */ public static String getConfig(String key){ synchronized(config){ return (String)(config.get(key)); } } + /** + * Sets or Overrides the configuration. + * + * @param newconf configurations + */ public static void setConfig(java.util.Hashtable newconf){ synchronized(config){ for(java.util.Enumeration e=newconf.keys() ; e.hasMoreElements() ;) { @@ -303,14 +563,28 @@ public class JSch{ } } + /** + * Sets or Overrides the configuration. + * + * @param key key for the configuration + * @param value value for the configuration + */ public static void setConfig(String key, String value){ config.put(key, value); } + /** + * Sets the logger + * + * @param logger logger + * + * @see com.jcraft.jsch.Logger + */ public static void setLogger(Logger logger){ if(logger==null) logger=DEVNULL; JSch.logger=logger; } + static Logger getLogger(){ return logger; } diff --git a/java/com/jcraft/jsch/JSchAuthCancelException.java b/java/com/jcraft/jsch/JSchAuthCancelException.java index 65e71f19..4e7eb8f4 100644 --- a/java/com/jcraft/jsch/JSchAuthCancelException.java +++ b/java/com/jcraft/jsch/JSchAuthCancelException.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/JSchException.java b/java/com/jcraft/jsch/JSchException.java index 1e9056ce..666d3a41 100644 --- a/java/com/jcraft/jsch/JSchException.java +++ b/java/com/jcraft/jsch/JSchException.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/JSchPartialAuthException.java b/java/com/jcraft/jsch/JSchPartialAuthException.java index aa7ac9e4..93986069 100644 --- a/java/com/jcraft/jsch/JSchPartialAuthException.java +++ b/java/com/jcraft/jsch/JSchPartialAuthException.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/KeyExchange.java b/java/com/jcraft/jsch/KeyExchange.java index 77e7b83b..c74c22f4 100644 --- a/java/com/jcraft/jsch/KeyExchange.java +++ b/java/com/jcraft/jsch/KeyExchange.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package com.jcraft.jsch; -@SuppressWarnings({"rawtypes"}) public abstract class KeyExchange{ static final int PROPOSAL_KEX_ALGS=0; @@ -71,25 +70,43 @@ public abstract class KeyExchange{ public abstract void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception; public abstract boolean next(Buffer buf) throws Exception; - public abstract String getKeyType(); + public abstract int getState(); - /* - void dump(byte[] foo){ - for(int i=0; i 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/java/com/jcraft/jsch/KeyPair.java b/java/com/jcraft/jsch/KeyPair.java index b3f681cb..7c31f15b 100644 --- a/java/com/jcraft/jsch/KeyPair.java +++ b/java/com/jcraft/jsch/KeyPair.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,15 +32,20 @@ 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 UNKNOWN=3; + 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"); @@ -52,6 +57,7 @@ public abstract class KeyPair{ 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); } @@ -64,10 +70,20 @@ public abstract class KeyPair{ 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; } - private String publicKeyComment = ""; + + public void setPublicKeyComment(String publicKeyComment){ + this.publicKeyComment = publicKeyComment; + } + + protected String publicKeyComment = "no comment"; JSch jsch=null; private Cipher cipher; @@ -85,10 +101,27 @@ public abstract class KeyPair{ 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); + byte[] encoded=encrypt(plain, _iv, passphrase); if(encoded!=plain) Util.bzero(plain); byte[] iv=_iv[0]; @@ -130,8 +163,22 @@ public abstract class KeyPair{ abstract byte[] getKeyTypeName(); public abstract int getKeyType(); - public byte[] getPublicKeyBlob(){ return publickeyblob; } + /** + * Returns the blob of the public key. + * @return blob of the public key + */ + public byte[] getPublicKeyBlob() { + // TODO JSchException should be thrown + //if(publickeyblob == null) + // throw new JSchException("public-key blob is not available"); + return publickeyblob; + } + /** + * Writes the public key with the specified comment to the output stream. + * @param out output stream + * @param comment comment + */ public void writePublicKey(java.io.OutputStream out, String comment){ byte[] pubblob=getPublicKeyBlob(); byte[] pub=Util.toBase64(pubblob, 0, pubblob.length); @@ -145,12 +192,24 @@ public abstract class KeyPair{ } } + /** + * Writes the public key with the specified comment to the file. + * @param name file name + * @param comment comment + * @see #writePublicKey(java.io.OutputStream out, String comment) + */ public void writePublicKey(String name, String comment) throws java.io.FileNotFoundException, java.io.IOException{ FileOutputStream fos=new FileOutputStream(name); writePublicKey(fos, comment); fos.close(); } + /** + * Writes the public key with the specified comment to the output stream in + * the format defined in http://www.ietf.org/rfc/rfc4716.txt + * @param out output stream + * @param comment comment + */ public void writeSECSHPublicKey(java.io.OutputStream out, String comment){ byte[] pubblob=getPublicKeyBlob(); byte[] pub=Util.toBase64(pubblob, 0, pubblob.length); @@ -170,27 +229,52 @@ public abstract class KeyPair{ } } + /** + * Writes the public key with the specified comment to the output stream in + * the format defined in http://www.ietf.org/rfc/rfc4716.txt + * @param name file name + * @param comment comment + * @see #writeSECSHPublicKey(java.io.OutputStream out, String comment) + */ public void writeSECSHPublicKey(String name, String comment) throws java.io.FileNotFoundException, java.io.IOException{ FileOutputStream fos=new FileOutputStream(name); writeSECSHPublicKey(fos, comment); fos.close(); } - + /** + * Writes the plain private key to the file. + * @param name file name + * @see #writePrivateKey(String name, byte[] passphrase) + */ public void writePrivateKey(String name) throws java.io.FileNotFoundException, java.io.IOException{ + this.writePrivateKey(name, null); + } + + /** + * Writes the cyphered private key to the file. + * @param name file name + * @param passphrase a passphrase to encrypt the private key + * @see #writePrivateKey(java.io.OutputStream out, byte[] passphrase) + */ + public void writePrivateKey(String name, byte[] passphrase) throws java.io.FileNotFoundException, java.io.IOException{ FileOutputStream fos=new FileOutputStream(name); - writePrivateKey(fos); + writePrivateKey(fos, passphrase); fos.close(); } + /** + * Returns the finger-print of the public key. + * @return finger print + */ public String getFingerPrint(){ if(hash==null) hash=genHash(); byte[] kblob=getPublicKeyBlob(); if(kblob==null) return null; - return getKeySize()+" "+Util.getFingerPrint(hash, kblob); + return Util.getFingerPrint(hash, kblob); } - private byte[] encrypt(byte[] plain, byte[][] _iv){ + private byte[] encrypt(byte[] plain, byte[][] _iv, byte[] passphrase){ if(passphrase==null) return plain; if(cipher==null) cipher=genCipher(); @@ -229,12 +313,7 @@ public abstract class KeyPair{ abstract boolean parse(byte[] data); private byte[] decrypt(byte[] data, byte[] passphrase, byte[] iv){ - /* - if(iv==null){ // FSecure - iv=new byte[8]; - for(int i=0; i11 && + 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{ - 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; + byte[] buf=prvkey; + + if(buf!=null){ + KeyPair ppk = loadPPK(jsch, buf); + if(ppk !=null) + return ppk; } - fis.close(); + 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); } @@ -534,36 +733,60 @@ public abstract class KeyPair{ } if(!inheader){ i++; - encrypted=false; // no passphrase + if(vendor!=VENDOR_PKCS8) + encrypted=false; // no passphrase break; } } i++; } - if(type==ERROR){ - throw new JSchException("invalid privatekey: "+prvkey); - } + if(buf!=null){ - int start=i; - while(i 0) + data=Util.fromBase64(_buf, start, i-start); + + Util.bzero(_buf); } - data=Util.fromBase64(buf, start, i-start); - if(data.length>4 && // FSecure + if(data!=null && + data.length>4 && // FSecure data[0]==(byte)0x3f && data[1]==(byte)0x6f && data[2]==(byte)0xf9 && @@ -598,18 +821,8 @@ public abstract class KeyPair{ 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(); - + buf=pubkey; + len=buf.length; if(buf.length>4 && // FSecure's public key buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){ @@ -634,7 +847,7 @@ public abstract class KeyPair{ } if(buf.length<=i){valid=false;} - start=i; + int start=i; while(valid && i7){ + 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/java/com/jcraft/jsch/KeyPairGenDSA.java b/java/com/jcraft/jsch/KeyPairGenDSA.java index f6507f24..6d7e21c9 100644 --- a/java/com/jcraft/jsch/KeyPairGenDSA.java +++ b/java/com/jcraft/jsch/KeyPairGenDSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/KeyPairGenECDSA.java b/java/com/jcraft/jsch/KeyPairGenECDSA.java new file mode 100644 index 00000000..b0d6bbf4 --- /dev/null +++ b/java/com/jcraft/jsch/KeyPairGenECDSA.java @@ -0,0 +1,37 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015 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/java/com/jcraft/jsch/KeyPairGenRSA.java b/java/com/jcraft/jsch/KeyPairGenRSA.java index 3a849074..ecb97a41 100644 --- a/java/com/jcraft/jsch/KeyPairGenRSA.java +++ b/java/com/jcraft/jsch/KeyPairGenRSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/KeyPairPKCS8.java b/java/com/jcraft/jsch/KeyPairPKCS8.java new file mode 100644 index 00000000..47c2a933 --- /dev/null +++ b/java/com/jcraft/jsch/KeyPairPKCS8.java @@ -0,0 +1,363 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2013-2015 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/java/com/jcraft/jsch/KeyPairRSA.java b/java/com/jcraft/jsch/KeyPairRSA.java index dfc202f9..4221b75e 100644 --- a/java/com/jcraft/jsch/KeyPairRSA.java +++ b/java/com/jcraft/jsch/KeyPairRSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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 @@ public class KeyPairRSA extends KeyPair{ } 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 @@ public class KeyPairRSA extends KeyPair{ 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 @@ public class KeyPairRSA extends KeyPair{ } 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 @@ public class KeyPairRSA extends KeyPair{ 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; } @@ -344,7 +417,7 @@ loop: } 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(); } @@ -358,18 +431,28 @@ loop: for(int i=0; i0){ String data=this.host.substring(HASH_MAGIC.length()); diff --git a/java/com/jcraft/jsch/LICENSE.txt b/java/com/jcraft/jsch/LICENSE.txt index 81c8eacf..303096bf 100644 --- a/java/com/jcraft/jsch/LICENSE.txt +++ b/java/com/jcraft/jsch/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-2012 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/java/com/jcraft/jsch/LocalIdentityRepository.java b/java/com/jcraft/jsch/LocalIdentityRepository.java index 7dde42e7..bc463498 100644 --- a/java/com/jcraft/jsch/LocalIdentityRepository.java +++ b/java/com/jcraft/jsch/LocalIdentityRepository.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2012-2015 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,8 +31,8 @@ package com.jcraft.jsch; import java.util.Vector; -@SuppressWarnings({"rawtypes","unchecked"}) class LocalIdentityRepository implements IdentityRepository { + private static final String name = "Local Identity Repository"; private Vector identities = new Vector(); private JSch jsch; @@ -41,7 +41,16 @@ class LocalIdentityRepository implements IdentityRepository { 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/java/com/jcraft/jsch/PBKDF.java b/java/com/jcraft/jsch/PBKDF.java new file mode 100644 index 00000000..44031fce --- /dev/null +++ b/java/com/jcraft/jsch/PBKDF.java @@ -0,0 +1,34 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2013-2015 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/java/com/jcraft/jsch/Packet.java b/java/com/jcraft/jsch/Packet.java index 9c441577..c163b786 100644 --- a/java/com/jcraft/jsch/Packet.java +++ b/java/com/jcraft/jsch/Packet.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/PortWatcher.java b/java/com/jcraft/jsch/PortWatcher.java index b5fc37bb..2fdcd961 100644 --- a/java/com/jcraft/jsch/PortWatcher.java +++ b/java/com/jcraft/jsch/PortWatcher.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,7 +32,6 @@ package com.jcraft.jsch; import java.net.*; import java.io.*; -@SuppressWarnings({"rawtypes","unchecked"}) class PortWatcher implements Runnable{ private static java.util.Vector pool=new java.util.Vector(); private static InetAddress anyLocalAddress=null; @@ -55,6 +54,7 @@ class PortWatcher implements Runnable{ InetAddress boundaddress; Runnable thread; ServerSocket ss; + int connectTimeout=0; static String[] getPortForwarding(Session session){ java.util.Vector foo=new java.util.Vector(); @@ -93,7 +93,17 @@ class PortWatcher implements Runnable{ return null; } } + private static String normalize(String address){ + if(address!=null){ + if(address.length()==0 || address.equals("*")) + address="0.0.0.0"; + else if(address.equals("localhost")) + address="127.0.0.1"; + } + return address; + } static PortWatcher addPort(Session session, String address, int lport, String host, int rport, ServerSocketFactory ssf) throws JSchException{ + address = normalize(address); if(getPort(session, address, lport)!=null){ throw new JSchException("PortForwardingL: local port "+ address+":"+lport+" is already registered."); } @@ -102,6 +112,7 @@ class PortWatcher implements Runnable{ return pw; } static void delPort(Session session, String address, int lport) throws JSchException{ + address = normalize(address); PortWatcher pw=getPort(session, address, lport); if(pw==null){ throw new JSchException("PortForwardingL: local port "+address+":"+lport+" is not registered."); @@ -171,7 +182,7 @@ class PortWatcher implements Runnable{ ((ChannelDirectTCPIP)channel).setPort(rport); ((ChannelDirectTCPIP)channel).setOrgIPAddress(socket.getInetAddress().getHostAddress()); ((ChannelDirectTCPIP)channel).setOrgPort(socket.getPort()); - channel.connect(); + channel.connect(connectTimeout); if(channel.exitstatus!=-1){ } } @@ -179,7 +190,6 @@ class PortWatcher implements Runnable{ catch(Exception e){ //System.err.println("! "+e); } - delete(); } @@ -192,4 +202,8 @@ class PortWatcher implements Runnable{ catch(Exception e){ } } + + void setConnectTimeout(int connectTimeout){ + this.connectTimeout=connectTimeout; + } } diff --git a/java/com/jcraft/jsch/Proxy.java b/java/com/jcraft/jsch/Proxy.java index 7d05caa8..be196b60 100644 --- a/java/com/jcraft/jsch/Proxy.java +++ b/java/com/jcraft/jsch/Proxy.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/ProxyHTTP.java b/java/com/jcraft/jsch/ProxyHTTP.java index df23114a..09a1623d 100644 --- a/java/com/jcraft/jsch/ProxyHTTP.java +++ b/java/com/jcraft/jsch/ProxyHTTP.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/ProxySOCKS4.java b/java/com/jcraft/jsch/ProxySOCKS4.java index cb506165..5cd97ed5 100644 --- a/java/com/jcraft/jsch/ProxySOCKS4.java +++ b/java/com/jcraft/jsch/ProxySOCKS4.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2015 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/java/com/jcraft/jsch/ProxySOCKS5.java b/java/com/jcraft/jsch/ProxySOCKS5.java index 7960135a..33311bab 100644 --- a/java/com/jcraft/jsch/ProxySOCKS5.java +++ b/java/com/jcraft/jsch/ProxySOCKS5.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/README b/java/com/jcraft/jsch/README index a52886e5..d00a2192 100644 --- a/java/com/jcraft/jsch/README +++ b/java/com/jcraft/jsch/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/java/com/jcraft/jsch/Random.java b/java/com/jcraft/jsch/Random.java index 879b7770..5718ba39 100644 --- a/java/com/jcraft/jsch/Random.java +++ b/java/com/jcraft/jsch/Random.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/Request.java b/java/com/jcraft/jsch/Request.java index 94f9b013..8bedb6ac 100644 --- a/java/com/jcraft/jsch/Request.java +++ b/java/com/jcraft/jsch/Request.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/RequestAgentForwarding.java b/java/com/jcraft/jsch/RequestAgentForwarding.java index 66d328cd..252a0844 100644 --- a/java/com/jcraft/jsch/RequestAgentForwarding.java +++ b/java/com/jcraft/jsch/RequestAgentForwarding.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2015 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/java/com/jcraft/jsch/RequestEnv.java b/java/com/jcraft/jsch/RequestEnv.java index cccda4df..fcbcd3d7 100644 --- a/java/com/jcraft/jsch/RequestEnv.java +++ b/java/com/jcraft/jsch/RequestEnv.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/RequestExec.java b/java/com/jcraft/jsch/RequestExec.java index 318d99ad..badc90f1 100644 --- a/java/com/jcraft/jsch/RequestExec.java +++ b/java/com/jcraft/jsch/RequestExec.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/RequestPtyReq.java b/java/com/jcraft/jsch/RequestPtyReq.java index 86bf4f13..d0dfef16 100644 --- a/java/com/jcraft/jsch/RequestPtyReq.java +++ b/java/com/jcraft/jsch/RequestPtyReq.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/RequestSftp.java b/java/com/jcraft/jsch/RequestSftp.java index 483c296b..b1a1ea51 100644 --- a/java/com/jcraft/jsch/RequestSftp.java +++ b/java/com/jcraft/jsch/RequestSftp.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/RequestShell.java b/java/com/jcraft/jsch/RequestShell.java index e037ba9e..1266ad7d 100644 --- a/java/com/jcraft/jsch/RequestShell.java +++ b/java/com/jcraft/jsch/RequestShell.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/RequestSignal.java b/java/com/jcraft/jsch/RequestSignal.java index a6926177..3a88d068 100644 --- a/java/com/jcraft/jsch/RequestSignal.java +++ b/java/com/jcraft/jsch/RequestSignal.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/RequestSubsystem.java b/java/com/jcraft/jsch/RequestSubsystem.java index b6fee4f4..4de2b1c4 100644 --- a/java/com/jcraft/jsch/RequestSubsystem.java +++ b/java/com/jcraft/jsch/RequestSubsystem.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2005-2015 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/java/com/jcraft/jsch/RequestWindowChange.java b/java/com/jcraft/jsch/RequestWindowChange.java index 43600ac4..53a31e63 100644 --- a/java/com/jcraft/jsch/RequestWindowChange.java +++ b/java/com/jcraft/jsch/RequestWindowChange.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/RequestX11.java b/java/com/jcraft/jsch/RequestX11.java index 3bdaca9f..870a352d 100644 --- a/java/com/jcraft/jsch/RequestX11.java +++ b/java/com/jcraft/jsch/RequestX11.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/ServerSocketFactory.java b/java/com/jcraft/jsch/ServerSocketFactory.java index 682b4c4f..c405577c 100644 --- a/java/com/jcraft/jsch/ServerSocketFactory.java +++ b/java/com/jcraft/jsch/ServerSocketFactory.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/Session.java b/java/com/jcraft/jsch/Session.java index 900d96d6..39e9029a 100644 --- a/java/com/jcraft/jsch/Session.java +++ b/java/com/jcraft/jsch/Session.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,8 +31,8 @@ package com.jcraft.jsch; import java.io.*; import java.net.*; +import java.util.Vector; -@SuppressWarnings({"rawtypes","static","unchecked"}) public class Session implements Runnable{ // http://ietf.org/internet-drafts/draft-ietf-secsh-assignednumbers-01.txt @@ -135,6 +135,9 @@ public class Session implements Runnable{ private int serverAliveInterval=0; private int serverAliveCountMax=1; + private IdentityRepository identityRepository = null; + private HostKeyRepository hostkeyRepository = null; + protected boolean daemon_thread=false; private long kex_start_time=0L; @@ -143,6 +146,7 @@ public class Session implements Runnable{ int auth_failures = 0; String host="127.0.0.1"; + String org_host="127.0.0.1"; int port=22; String username=null; @@ -150,11 +154,29 @@ public class Session implements Runnable{ JSch jsch; - Session(JSch jsch) throws JSchException{ + Session(JSch jsch, String username, String host, int port) throws JSchException{ super(); this.jsch=jsch; buf=new Buffer(); packet=new Packet(buf); + this.username = username; + this.org_host = this.host = host; + this.port = port; + + applyConfig(); + + if(this.username==null) { + try { + this.username=(String)(System.getProperties().get("user.name")); + } + catch(SecurityException e){ + // ignore e + } + } + + if(this.username==null) { + throw new JSchException("username is not given."); + } } public void connect() throws JSchException{ @@ -462,8 +484,15 @@ public class Session implements Runnable{ catch(RuntimeException ee){ throw ee; } + catch(JSchException ee){ + throw ee; + } catch(Exception ee){ //System.err.println("ee: "+ee); // SSH_MSG_DISCONNECT: 2 Too many authentication failures + if(JSch.getLogger().isEnabled(Logger.WARN)){ + JSch.getLogger().log(Logger.WARN, + "an exception during authentication\n"+ee.toString()); + } break loop; } } @@ -483,7 +512,7 @@ public class Session implements Runnable{ throw new JSchException("Auth fail"); } - if(connectTimeout>0 || timeout>0){ + if(socket!=null && (connectTimeout>0 || timeout>0)){ socket.setSoTimeout(timeout); } @@ -497,6 +526,8 @@ public class Session implements Runnable{ connectThread.setDaemon(daemon_thread); } connectThread.start(); + + requestPortForwarding(); } else{ // The session has been already down and @@ -506,19 +537,20 @@ public class Session implements Runnable{ } 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; @@ -570,7 +602,7 @@ public class Session implements Runnable{ return kex; } - private boolean in_kex=false; + private volatile boolean in_kex=false; public void rekey() throws Exception { send_kexinit(); } @@ -599,6 +631,16 @@ public class Session implements Runnable{ } } + 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(); @@ -622,7 +664,7 @@ public class Session implements Runnable{ random.fill(buf.buffer, buf.index, 16); buf.skip(16); } buf.putString(Util.str2byte(kex)); - buf.putString(Util.str2byte(getConfig("server_host_key"))); + buf.putString(Util.str2byte(server_host_key)); buf.putString(Util.str2byte(cipherc2s)); buf.putString(Util.str2byte(ciphers2c)); buf.putString(Util.str2byte(getConfig("mac.c2s"))); @@ -675,16 +717,22 @@ public class Session implements Runnable{ 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; @@ -701,7 +749,7 @@ public class Session implements Runnable{ "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."; @@ -721,7 +769,7 @@ key_fprint+".\n"+ synchronized(hkr){ hkr.remove(chost, - (key_type.equals("DSA") ? "ssh-dss" : "ssh-rsa"), + kex.getKeyAlgorithName(), null); insert=true; } @@ -757,10 +805,32 @@ key_type+" key fingerprint is "+key_fprint+".\n"+ 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 && @@ -769,21 +839,11 @@ key_type+" key fingerprint is "+key_fprint+".\n"+ "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(); } @@ -796,6 +856,9 @@ key_type+" key fingerprint is "+key_fprint+".\n"+ Channel channel=Channel.getChannel(type); addChannel(channel); channel.init(); + if(channel instanceof ChannelSession){ + applyConfigChannel((ChannelSession)channel); + } return channel; } catch(Exception e){ @@ -966,7 +1029,7 @@ key_type+" key fingerprint is "+key_fprint+".\n"+ if(c==null){ } else{ - c.addRemoteWindowSize(buf.getInt()); + c.addRemoteWindowSize(buf.getUInt()); } } else if(type==UserAuth.SSH_MSG_USERAUTH_SUCCESS){ @@ -1032,8 +1095,6 @@ key_type+" key fingerprint is "+key_fprint+".\n"+ 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); @@ -1103,6 +1164,7 @@ key_type+" key fingerprint is "+key_fprint+".\n"+ 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()]; @@ -1129,6 +1191,7 @@ key_type+" key fingerprint is "+key_fprint+".\n"+ 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]; @@ -1145,6 +1208,40 @@ key_type+" key fingerprint is "+key_fprint+".\n"+ } } + + /* + * 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){ @@ -1170,6 +1267,10 @@ key_type+" key fingerprint is "+key_fprint+".\n"+ } } + if(in_kex){ + continue; + } + if(c.rwsize>=length){ c.rwsize-=length; break; @@ -1407,7 +1508,7 @@ break; if(channel==null){ break; } - channel.addRemoteWindowSize(buf.getInt()); + channel.addRemoteWindowSize(buf.getUInt()); break; case SSH_MSG_CHANNEL_EOF: @@ -1447,33 +1548,30 @@ break; buf.getShort(); i=buf.getInt(); channel=Channel.getChannel(i, this); - if(channel==null){ - //break; - } int r=buf.getInt(); long rws=buf.getUInt(); int rps=buf.getInt(); - - channel.setRemoteWindowSize(rws); - channel.setRemotePacketSize(rps); - channel.open_confirmation=true; - channel.setRecipient(r); + if(channel!=null){ + channel.setRemoteWindowSize(rws); + channel.setRemotePacketSize(rps); + channel.open_confirmation=true; + channel.setRecipient(r); + } break; case SSH_MSG_CHANNEL_OPEN_FAILURE: buf.getInt(); buf.getShort(); i=buf.getInt(); channel=Channel.getChannel(i, this); - if(channel==null){ - //break; - } - int reason_code=buf.getInt(); - //foo=buf.getString(); // additional textual information - //foo=buf.getString(); // language tag - channel.setExitStatus(reason_code); - channel.close=true; - channel.eof_remote=true; - channel.setRecipient(0); + if(channel!=null){ + int reason_code=buf.getInt(); + //foo=buf.getString(); // additional textual information + //foo=buf.getString(); // language tag + channel.setExitStatus(reason_code); + channel.close=true; + channel.eof_remote=true; + channel.setRecipient(0); + } break; case SSH_MSG_CHANNEL_REQUEST: buf.getInt(); @@ -1529,8 +1627,8 @@ break; tmp.setDaemon(daemon_thread); } tmp.start(); - break; } + break; case SSH_MSG_CHANNEL_SUCCESS: buf.getInt(); buf.getShort(); @@ -1567,6 +1665,11 @@ break; Thread t=grr.getThread(); if(t!=null){ grr.setReply(msgType==SSH_MSG_REQUEST_SUCCESS? 1 : 0); + if(msgType==SSH_MSG_REQUEST_SUCCESS && grr.getPort()==0){ + buf.getInt(); + buf.getShort(); + grr.setPort(buf.getInt()); + } t.interrupt(); } break; @@ -1665,14 +1768,73 @@ break; //System.gc(); } + /** + * Registers the local port forwarding for loop-back interface. + * If lport 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){ @@ -1681,44 +1843,291 @@ break; 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; @@ -1726,9 +2135,11 @@ break; 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); @@ -1736,6 +2147,7 @@ break; String address_to_bind=ChannelForwardedTCPIP.normalize(bind_address); grr.setThread(Thread.currentThread()); + grr.setPort(rport); try{ // byte SSH_MSG_GLOBAL_REQUEST 80 @@ -1771,10 +2183,30 @@ break; 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{ @@ -1794,6 +2226,9 @@ break; 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."); @@ -1935,6 +2370,17 @@ break; 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; } @@ -1948,17 +2394,46 @@ break; 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; } @@ -1976,11 +2451,17 @@ break; "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) @@ -2052,4 +2533,295 @@ break; } catch(Exception e){ return false; } } + + private String[] checkSignatures(String sigs){ + if(sigs==null || sigs.length()==0) + return null; + + if(JSch.getLogger().isEnabled(Logger.INFO)){ + JSch.getLogger().log(Logger.INFO, + "CheckSignatures: "+sigs); + } + + java.util.Vector result=new java.util.Vector(); + String[] _sigs=Util.split(sigs, ","); + for(int i=0; i<_sigs.length; i++){ + try{ + Class c=Class.forName((String)jsch.getConfig(_sigs[i])); + final Signature sig=(Signature)(c.newInstance()); + sig.init(); + } + catch(Exception e){ + result.addElement(_sigs[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/java/com/jcraft/jsch/SftpATTRS.java b/java/com/jcraft/jsch/SftpATTRS.java index e89b2435..3195def9 100644 --- a/java/com/jcraft/jsch/SftpATTRS.java +++ b/java/com/jcraft/jsch/SftpATTRS.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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 class SftpATTRS { } 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 class SftpATTRS { 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 class SftpATTRS { 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/java/com/jcraft/jsch/SftpException.java b/java/com/jcraft/jsch/SftpException.java index 6a6c1ff8..7fb630e4 100644 --- a/java/com/jcraft/jsch/SftpException.java +++ b/java/com/jcraft/jsch/SftpException.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/SftpProgressMonitor.java b/java/com/jcraft/jsch/SftpProgressMonitor.java index bd91688d..cfc69e6b 100644 --- a/java/com/jcraft/jsch/SftpProgressMonitor.java +++ b/java/com/jcraft/jsch/SftpProgressMonitor.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/SftpStatVFS.java b/java/com/jcraft/jsch/SftpStatVFS.java new file mode 100644 index 00000000..872eddb9 --- /dev/null +++ b/java/com/jcraft/jsch/SftpStatVFS.java @@ -0,0 +1,122 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/Signature.java b/java/com/jcraft/jsch/Signature.java new file mode 100644 index 00000000..a517cfd3 --- /dev/null +++ b/java/com/jcraft/jsch/Signature.java @@ -0,0 +1,37 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2012-2015 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 Signature{ + void init() throws Exception; + void update(byte[] H) throws Exception; + boolean verify(byte[] sig) throws Exception; + byte[] sign() throws Exception; +} diff --git a/java/com/jcraft/jsch/SignatureDSA.java b/java/com/jcraft/jsch/SignatureDSA.java index 6f44b7ff..9cc0651e 100644 --- a/java/com/jcraft/jsch/SignatureDSA.java +++ b/java/com/jcraft/jsch/SignatureDSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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/java/com/jcraft/jsch/SignatureECDSA.java b/java/com/jcraft/jsch/SignatureECDSA.java new file mode 100644 index 00000000..516a4906 --- /dev/null +++ b/java/com/jcraft/jsch/SignatureECDSA.java @@ -0,0 +1,35 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015 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/java/com/jcraft/jsch/SignatureRSA.java b/java/com/jcraft/jsch/SignatureRSA.java index e8e61059..b31a8dcf 100644 --- a/java/com/jcraft/jsch/SignatureRSA.java +++ b/java/com/jcraft/jsch/SignatureRSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package com.jcraft.jsch; -public interface SignatureRSA{ - void init() throws Exception; +public interface SignatureRSA extends Signature { 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/java/com/jcraft/jsch/SocketFactory.java b/java/com/jcraft/jsch/SocketFactory.java index aaac0dce..532b7d4d 100644 --- a/java/com/jcraft/jsch/SocketFactory.java +++ b/java/com/jcraft/jsch/SocketFactory.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/UIKeyboardInteractive.java b/java/com/jcraft/jsch/UIKeyboardInteractive.java index 23af9c31..afc5217e 100644 --- a/java/com/jcraft/jsch/UIKeyboardInteractive.java +++ b/java/com/jcraft/jsch/UIKeyboardInteractive.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/UserAuth.java b/java/com/jcraft/jsch/UserAuth.java index 085a9508..8a74dc62 100644 --- a/java/com/jcraft/jsch/UserAuth.java +++ b/java/com/jcraft/jsch/UserAuth.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java b/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java index 15856cbc..2b0bdc7d 100644 --- a/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java +++ b/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2015 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/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java b/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java index 29947965..389733e6 100644 --- a/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java +++ b/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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: @@ -128,7 +128,7 @@ class UserAuthKeyboardInteractive extends UserAuth{ 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/java/com/jcraft/jsch/UserAuthNone.java b/java/com/jcraft/jsch/UserAuthNone.java index b3b0b077..4b04a1fa 100644 --- a/java/com/jcraft/jsch/UserAuthNone.java +++ b/java/com/jcraft/jsch/UserAuthNone.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/UserAuthPassword.java b/java/com/jcraft/jsch/UserAuthPassword.java index 9b5837f5..b10f4622 100644 --- a/java/com/jcraft/jsch/UserAuthPassword.java +++ b/java/com/jcraft/jsch/UserAuthPassword.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/UserAuthPublicKey.java b/java/com/jcraft/jsch/UserAuthPublicKey.java index 234ad0ac..129c124d 100644 --- a/java/com/jcraft/jsch/UserAuthPublicKey.java +++ b/java/com/jcraft/jsch/UserAuthPublicKey.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,13 +31,12 @@ package com.jcraft.jsch; import java.util.Vector; -@SuppressWarnings({"rawtypes"}) class UserAuthPublicKey extends UserAuth{ public boolean start(Session session) throws Exception{ super.start(session); - Vector identities=session.jsch.getIdentityRepository().getIdentities(); + Vector identities=session.getIdentityRepository().getIdentities(); byte[] passphrase=null; byte[] _username=null; @@ -60,8 +59,6 @@ class UserAuthPublicKey extends UserAuth{ 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) @@ -69,7 +66,8 @@ class UserAuthPublicKey extends UserAuth{ // 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); @@ -132,8 +130,13 @@ class UserAuthPublicKey extends UserAuth{ } 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; @@ -152,13 +155,15 @@ class UserAuthPublicKey extends UserAuth{ 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); diff --git a/java/com/jcraft/jsch/UserInfo.java b/java/com/jcraft/jsch/UserInfo.java index 22552ede..c7f9f478 100644 --- a/java/com/jcraft/jsch/UserInfo.java +++ b/java/com/jcraft/jsch/UserInfo.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/Util.java b/java/com/jcraft/jsch/Util.java index 8d51fc61..5974b0cb 100644 --- a/java/com/jcraft/jsch/Util.java +++ b/java/com/jcraft/jsch/Util.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,8 +29,10 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package com.jcraft.jsch; import java.net.Socket; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; -@SuppressWarnings({"rawtypes","unchecked"}) class Util{ private static final byte[] b64 =Util.str2byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); @@ -41,20 +43,25 @@ class Util{ } 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){ @@ -384,7 +391,7 @@ class Util{ } tmp.interrupt(); tmp=null; - throw new JSchException(message); + throw new JSchException(message, ee[0]); } return socket; } @@ -421,6 +428,17 @@ class Util{ 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]; + System.arraycopy(key, 0, tmp, 0, bsize); + key = tmp; + } + SecretKeySpec skey = new SecretKeySpec(key, algorithm); + mac = Mac.getInstance(algorithm); + 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){ + System.err.println(e); + } + } + + public String getName(){ + return name; + } +} diff --git a/java/com/jcraft/jsch/jce/HMACMD5.java b/java/com/jcraft/jsch/jce/HMACMD5.java index def3747b..6249c0b6 100644 --- a/java/com/jcraft/jsch/jce/HMACMD5.java +++ b/java/com/jcraft/jsch/jce/HMACMD5.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,43 +33,10 @@ import com.jcraft.jsch.MAC; import javax.crypto.*; import javax.crypto.spec.*; -public class HMACMD5 implements MAC{ - private static final String name="hmac-md5"; - private static final int BSIZE=16; - private Mac mac; - public int getBlockSize(){return BSIZE;}; - public void init(byte[] key) throws Exception{ - if(key.length>BSIZE){ - 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; +public class HMACMD5 extends HMAC { + public HMACMD5(){ + name = "hmac-md5"; + bsize = 16; + algorithm = "HmacMD5"; } } diff --git a/java/com/jcraft/jsch/jce/HMACMD596.java b/java/com/jcraft/jsch/jce/HMACMD596.java index a296a5df..b9809316 100644 --- a/java/com/jcraft/jsch/jce/HMACMD596.java +++ b/java/com/jcraft/jsch/jce/HMACMD596.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,49 +29,18 @@ 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 class HMACMD596 extends HMACMD5 { + public HMACMD596(){ + name="hmac-md5-96"; } - public void update(byte foo[], int s, int l){ - mac.update(foo, s, l); - } + public int getBlockSize(){ + return 12; + }; - private final byte[] _buf16=new byte[16]; + private final byte[] _buf16 = new byte[16]; public void doFinal(byte[] buf, int offset){ - try{ - mac.doFinal(_buf16, 0); - } - catch(ShortBufferException e){ - } + super.doFinal(_buf16, 0); System.arraycopy(_buf16, 0, buf, offset, 12); } - - public String getName(){ - return name; - } } diff --git a/java/com/jcraft/jsch/jce/HMACSHA1.java b/java/com/jcraft/jsch/jce/HMACSHA1.java index 13feaabf..12f3de5f 100644 --- a/java/com/jcraft/jsch/jce/HMACSHA1.java +++ b/java/com/jcraft/jsch/jce/HMACSHA1.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,47 +29,10 @@ 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 HMACSHA1 implements MAC{ - private static final String name="hmac-sha1"; - private static final int bsize=20; - private Mac mac; - public int getBlockSize(){return bsize;}; - public void init(byte[] key) throws Exception{ - if(key.length>bsize){ - byte[] tmp=new byte[bsize]; - System.arraycopy(key, 0, tmp, 0, bsize); - 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); - } - - public void doFinal(byte[] buf, int offset){ - try{ - mac.doFinal(buf, offset); - } - catch(ShortBufferException e){ - } - } - - public String getName(){ - return name; +public class HMACSHA1 extends HMAC { + public HMACSHA1(){ + name = "hmac-sha1"; + bsize = 20; + algorithm = "HmacSHA1"; } } diff --git a/java/com/jcraft/jsch/jce/HMACSHA196.java b/java/com/jcraft/jsch/jce/HMACSHA196.java index e8791762..ab3b07b9 100644 --- a/java/com/jcraft/jsch/jce/HMACSHA196.java +++ b/java/com/jcraft/jsch/jce/HMACSHA196.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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,48 +29,19 @@ 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 extends HMACSHA1 { -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); + public HMACSHA196(){ + name = "hmac-sha1-96"; } - private final byte[] _buf20=new byte[20]; + public int getBlockSize(){ + return 12; + }; + + private final byte[] _buf20 = new byte[20]; public void doFinal(byte[] buf, int offset){ - try{ - mac.doFinal(_buf20, 0); - } - catch(ShortBufferException e){ - } + super.doFinal(_buf20, 0); System.arraycopy(_buf20, 0, buf, offset, 12); } - - public String getName(){ - return name; - } } diff --git a/java/com/jcraft/jsch/jce/HMACSHA256.java b/java/com/jcraft/jsch/jce/HMACSHA256.java new file mode 100644 index 00000000..d3cebf49 --- /dev/null +++ b/java/com/jcraft/jsch/jce/HMACSHA256.java @@ -0,0 +1,38 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2012-2015 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/java/com/jcraft/jsch/jce/HMACSHA512.java b/java/com/jcraft/jsch/jce/HMACSHA512.java new file mode 100644 index 00000000..41433435 --- /dev/null +++ b/java/com/jcraft/jsch/jce/HMACSHA512.java @@ -0,0 +1,38 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2012-2015 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/java/com/jcraft/jsch/jce/KeyPairGenDSA.java b/java/com/jcraft/jsch/jce/KeyPairGenDSA.java index 67ad54eb..722e7043 100644 --- a/java/com/jcraft/jsch/jce/KeyPairGenDSA.java +++ b/java/com/jcraft/jsch/jce/KeyPairGenDSA.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2002-2015 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/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java b/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java new file mode 100644 index 00000000..54b1e8e9 --- /dev/null +++ b/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java @@ -0,0 +1,96 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2015 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/java/com/jcraft/jsch/jcraft/HMACMD5.java b/java/com/jcraft/jsch/jcraft/HMACMD5.java index 90960113..850e81db 100644 --- a/java/com/jcraft/jsch/jcraft/HMACMD5.java +++ b/java/com/jcraft/jsch/jcraft/HMACMD5.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2015 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/java/com/jcraft/jsch/jcraft/HMACMD596.java b/java/com/jcraft/jsch/jcraft/HMACMD596.java index 95c6f60d..56593939 100644 --- a/java/com/jcraft/jsch/jcraft/HMACMD596.java +++ b/java/com/jcraft/jsch/jcraft/HMACMD596.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2015 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/java/com/jcraft/jsch/jcraft/HMACSHA1.java b/java/com/jcraft/jsch/jcraft/HMACSHA1.java index ea9eccf1..6dbb9de0 100644 --- a/java/com/jcraft/jsch/jcraft/HMACSHA1.java +++ b/java/com/jcraft/jsch/jcraft/HMACSHA1.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2015 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/java/com/jcraft/jsch/jcraft/HMACSHA196.java b/java/com/jcraft/jsch/jcraft/HMACSHA196.java index 86a81b5b..0a49f548 100644 --- a/java/com/jcraft/jsch/jcraft/HMACSHA196.java +++ b/java/com/jcraft/jsch/jcraft/HMACSHA196.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2015 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/java/com/jcraft/jsch/jgss/GSSContextKrb5.java b/java/com/jcraft/jsch/jgss/GSSContextKrb5.java index 9ee1560e..8f72f35d 100644 --- a/java/com/jcraft/jsch/jgss/GSSContextKrb5.java +++ b/java/com/jcraft/jsch/jgss/GSSContextKrb5.java @@ -1,6 +1,6 @@ /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* -Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved. +Copyright (c) 2006-2015 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/java/com/jcraft/jzlib/Deflate.java b/java/com/jcraft/jzlib/Deflate.java index baaac9be..cfda0f0b 100644 --- a/java/com/jcraft/jzlib/Deflate.java +++ b/java/com/jcraft/jzlib/Deflate.java @@ -263,6 +263,8 @@ final class Deflate implements Cloneable { // number of codes at each bit length for an optimal tree short[] bl_count=new short[MAX_BITS+1]; + // working area to be used in Tree#gen_codes() + short[] next_code=new short[MAX_BITS+1]; // heap used to build the Huffman trees int[] heap=new int[2*L_CODES+1]; @@ -275,7 +277,7 @@ final class Deflate implements Cloneable { // Depth of each subtree used as tie breaker for trees of equal frequency byte[] depth=new byte[2*L_CODES+1]; - int l_buf; // index for literals or lengths */ + byte[] l_buf; // index for literals or lengths */ // Size of match buffer for literals/lengths. There are 4 reasons for // limiting lit_bufsize to 64K: @@ -630,7 +632,7 @@ final class Deflate implements Cloneable { pending_buf[d_buf+last_lit*2] = (byte)(dist>>>8); pending_buf[d_buf+last_lit*2+1] = (byte)dist; - pending_buf[l_buf+last_lit] = (byte)lc; last_lit++; + l_buf[last_lit] = (byte)lc; last_lit++; if (dist == 0) { // lc is the unmatched char @@ -675,7 +677,7 @@ final class Deflate implements Cloneable { do{ dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)| (pending_buf[d_buf+lx*2+1]&0xff); - lc=(pending_buf[l_buf+lx])&0xff; lx++; + lc=(l_buf[lx])&0xff; lx++; if(dist == 0){ send_code(lc, ltree); // send a literal byte @@ -1379,11 +1381,11 @@ final class Deflate implements Cloneable { // We overlay pending_buf and d_buf+l_buf. This works since the average // output size for (length,distance) codes is <= 24 bits. - pending_buf = new byte[lit_bufsize*4]; - pending_buf_size = lit_bufsize*4; + pending_buf = new byte[lit_bufsize*3]; + pending_buf_size = lit_bufsize*3; - d_buf = lit_bufsize/2; - l_buf = (1+2)*lit_bufsize; + d_buf = lit_bufsize; + l_buf = new byte[lit_bufsize]; this.level = level; @@ -1420,6 +1422,7 @@ final class Deflate implements Cloneable { } // Deallocate in reverse order of allocations: pending_buf=null; + l_buf=null; head=null; prev=null; window=null; @@ -1697,6 +1700,8 @@ final class Deflate implements Cloneable { Deflate dest = (Deflate)super.clone(); dest.pending_buf = dup(dest.pending_buf); + dest.d_buf = dest.d_buf; + dest.l_buf = dup(dest.l_buf); dest.window = dup(dest.window); dest.prev = dup(dest.prev); @@ -1706,6 +1711,7 @@ final class Deflate implements Cloneable { dest.bl_tree = dup(dest.bl_tree); dest.bl_count = dup(dest.bl_count); + dest.next_code = dup(dest.next_code); dest.heap = dup(dest.heap); dest.depth = dup(dest.depth); diff --git a/java/com/jcraft/jzlib/Deflater.java b/java/com/jcraft/jzlib/Deflater.java new file mode 100644 index 00000000..ce0580dd --- /dev/null +++ b/java/com/jcraft/jzlib/Deflater.java @@ -0,0 +1,171 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 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. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final public class Deflater extends ZStream{ + + static final private int MAX_WBITS=15; // 32K LZ77 window + static final private int DEF_WBITS=MAX_WBITS; + + static final private int Z_NO_FLUSH=0; + static final private int Z_PARTIAL_FLUSH=1; + static final private int Z_SYNC_FLUSH=2; + static final private int Z_FULL_FLUSH=3; + static final private int Z_FINISH=4; + + static final private int MAX_MEM_LEVEL=9; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + private boolean finished = false; + + public Deflater(){ + super(); + } + + public Deflater(int level) throws GZIPException { + this(level, MAX_WBITS); + } + + public Deflater(int level, boolean nowrap) throws GZIPException { + this(level, MAX_WBITS, nowrap); + } + + public Deflater(int level, int bits) throws GZIPException { + this(level, bits, false); + } + + public Deflater(int level, int bits, boolean nowrap) throws GZIPException { + super(); + int ret = init(level, bits, nowrap); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + public Deflater(int level, int bits, int memlevel, JZlib.WrapperType wrapperType) throws GZIPException { + super(); + int ret = init(level, bits, memlevel, wrapperType); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + public Deflater(int level, int bits, int memlevel) throws GZIPException { + super(); + int ret = init(level, bits, memlevel); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + public int init(int level){ + return init(level, MAX_WBITS); + } + public int init(int level, boolean nowrap){ + return init(level, MAX_WBITS, nowrap); + } + public int init(int level, int bits){ + return init(level, bits, false); + } + public int init(int level, int bits, int memlevel, JZlib.WrapperType wrapperType){ + if(bits < 9 || bits > 15){ + return Z_STREAM_ERROR; + } + if(wrapperType == JZlib.W_NONE) { + bits *= -1; + } + else if(wrapperType == JZlib.W_GZIP) { + bits += 16; + } + else if(wrapperType == JZlib.W_ANY) { + return Z_STREAM_ERROR; + } + else if(wrapperType == JZlib.W_ZLIB) { + } + return init(level, bits, memlevel); + } + public int init(int level, int bits, int memlevel){ + finished = false; + dstate=new Deflate(this); + return dstate.deflateInit(level, bits, memlevel); + } + public int init(int level, int bits, boolean nowrap){ + finished = false; + dstate=new Deflate(this); + return dstate.deflateInit(level, nowrap?-bits:bits); + } + + public int deflate(int flush){ + if(dstate==null){ + return Z_STREAM_ERROR; + } + int ret = dstate.deflate(flush); + if(ret == Z_STREAM_END) + finished = true; + return ret; + } + public int end(){ + finished = true; + if(dstate==null) return Z_STREAM_ERROR; + int ret=dstate.deflateEnd(); + dstate=null; + free(); + return ret; + } + public int params(int level, int strategy){ + if(dstate==null) return Z_STREAM_ERROR; + return dstate.deflateParams(level, strategy); + } + public int setDictionary (byte[] dictionary, int dictLength){ + if(dstate == null) + return Z_STREAM_ERROR; + return dstate.deflateSetDictionary(dictionary, dictLength); + } + + public boolean finished(){ + return finished; + } + + public int copy(Deflater src){ + this.finished = src.finished; + return Deflate.deflateCopy(this, src); + } +} diff --git a/java/com/jcraft/jzlib/DeflaterOutputStream.java b/java/com/jcraft/jzlib/DeflaterOutputStream.java new file mode 100644 index 00000000..4c9f0d25 --- /dev/null +++ b/java/com/jcraft/jzlib/DeflaterOutputStream.java @@ -0,0 +1,181 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 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.jzlib; +import java.io.*; + +public class DeflaterOutputStream extends FilterOutputStream { + + protected final Deflater deflater; + + protected byte[] buffer; + + private boolean closed = false; + + private boolean syncFlush = false; + + private final byte[] buf1 = new byte[1]; + + protected boolean mydeflater = false; + + private boolean close_out = true; + + protected static final int DEFAULT_BUFSIZE = 512; + + public DeflaterOutputStream(OutputStream out) throws IOException { + this(out, + new Deflater(JZlib.Z_DEFAULT_COMPRESSION), + DEFAULT_BUFSIZE, true); + mydeflater = true; + } + + public DeflaterOutputStream(OutputStream out, Deflater def) throws IOException { + this(out, def, DEFAULT_BUFSIZE, true); + } + + public DeflaterOutputStream(OutputStream out, + Deflater deflater, + int size) throws IOException { + this(out, deflater, size, true); + } + public DeflaterOutputStream(OutputStream out, + Deflater deflater, + int size, + boolean close_out) throws IOException { + super(out); + if (out == null || deflater == null) { + throw new NullPointerException(); + } + else if (size <= 0) { + throw new IllegalArgumentException("buffer size must be greater than 0"); + } + this.deflater = deflater; + buffer = new byte[size]; + this.close_out = close_out; + } + + public void write(int b) throws IOException { + buf1[0] = (byte)(b & 0xff); + write(buf1, 0, 1); + } + + public void write(byte[] b, int off, int len) throws IOException { + if (deflater.finished()) { + throw new IOException("finished"); + } + else if (off<0 | len<0 | off+len>b.length) { + throw new IndexOutOfBoundsException(); + } + else if (len == 0) { + return; + } + else { + int flush = syncFlush ? JZlib.Z_SYNC_FLUSH : JZlib.Z_NO_FLUSH; + deflater.setInput(b, off, len, true); + while (deflater.avail_in>0) { + int err = deflate(flush); + if (err == JZlib.Z_STREAM_END) + break; + } + } + } + + public void finish() throws IOException { + while (!deflater.finished()) { + deflate(JZlib.Z_FINISH); + } + } + + public void close() throws IOException { + if (!closed) { + finish(); + if (mydeflater){ + deflater.end(); + } + if(close_out) + out.close(); + closed = true; + } + } + + protected int deflate(int flush) throws IOException { + deflater.setOutput(buffer, 0, buffer.length); + int err = deflater.deflate(flush); + switch(err) { + case JZlib.Z_OK: + case JZlib.Z_STREAM_END: + break; + case JZlib.Z_BUF_ERROR: + if(deflater.avail_in<=0 && flush!=JZlib.Z_FINISH){ + // flush() without any data + break; + } + default: + throw new IOException("failed to deflate"); + } + int len = deflater.next_out_index; + if (len > 0) { + out.write(buffer, 0, len); + } + return err; + } + + public void flush() throws IOException { + if (syncFlush && !deflater.finished()) { + while (true) { + int err = deflate(JZlib.Z_SYNC_FLUSH); + if (deflater.next_out_index < buffer.length) + break; + if (err == JZlib.Z_STREAM_END) + break; + } + } + out.flush(); + } + + public long getTotalIn() { + return deflater.getTotalIn(); + } + + public long getTotalOut() { + return deflater.getTotalOut(); + } + + public void setSyncFlush(boolean syncFlush){ + this.syncFlush = syncFlush; + } + + public boolean getSyncFlush(){ + return this.syncFlush; + } + + public Deflater getDeflater(){ + return deflater; + } +} diff --git a/java/com/jcraft/jzlib/GZIPException.java b/java/com/jcraft/jzlib/GZIPException.java new file mode 100644 index 00000000..0beef40d --- /dev/null +++ b/java/com/jcraft/jzlib/GZIPException.java @@ -0,0 +1,44 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 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. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +public class GZIPException extends java.io.IOException { + public GZIPException() { + super(); + } + public GZIPException(String s) { + super(s); + } +} diff --git a/java/com/jcraft/jzlib/GZIPInputStream.java b/java/com/jcraft/jzlib/GZIPInputStream.java new file mode 100644 index 00000000..5d29dca7 --- /dev/null +++ b/java/com/jcraft/jzlib/GZIPInputStream.java @@ -0,0 +1,145 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 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.jzlib; +import java.io.*; + +public class GZIPInputStream extends InflaterInputStream { + + public GZIPInputStream(InputStream in) throws IOException { + this(in, DEFAULT_BUFSIZE, true); + } + + public GZIPInputStream(InputStream in, + int size, + boolean close_in) throws IOException { + this(in, new Inflater(15+16), size, close_in); + myinflater = true; + } + + public GZIPInputStream(InputStream in, + Inflater inflater, + int size, + boolean close_in) throws IOException { + super(in, inflater, size, close_in); + } + + public long getModifiedtime() { + return inflater.istate.getGZIPHeader().getModifiedTime(); + } + + public int getOS() { + return inflater.istate.getGZIPHeader().getOS(); + } + + public String getName() { + return inflater.istate.getGZIPHeader().getName(); + } + + public String getComment() { + return inflater.istate.getGZIPHeader().getComment(); + } + + public long getCRC() throws GZIPException { + if(inflater.istate.mode != 12 /*DONE*/) + throw new GZIPException("checksum is not calculated yet."); + return inflater.istate.getGZIPHeader().getCRC(); + } + + public void readHeader() throws IOException { + + byte[] empty = "".getBytes(); + inflater.setOutput(empty, 0, 0); + inflater.setInput(empty, 0, 0, false); + + byte[] b = new byte[10]; + + int n = fill(b); + if(n!=10){ + if(n>0){ + inflater.setInput(b, 0, n, false); + //inflater.next_in_index = n; + inflater.next_in_index = 0; + inflater.avail_in = n; + } + throw new IOException("no input"); + } + + inflater.setInput(b, 0, n, false); + + byte[] b1 = new byte[1]; + do{ + if(inflater.avail_in<=0){ + int i = in.read(b1); + if(i<=0) + throw new IOException("no input"); + inflater.setInput(b1, 0, 1, true); + } + + int err = inflater.inflate(JZlib.Z_NO_FLUSH); + + if(err!=0/*Z_OK*/){ + int len = 2048-inflater.next_in.length; + if(len>0){ + byte[] tmp = new byte[len]; + n = fill(tmp); + if(n>0){ + inflater.avail_in += inflater.next_in_index; + inflater.next_in_index = 0; + inflater.setInput(tmp, 0, n, true); + } + } + //inflater.next_in_index = inflater.next_in.length; + inflater.avail_in += inflater.next_in_index; + inflater.next_in_index = 0; + throw new IOException(inflater.msg); + } + } + while(inflater.istate.inParsingHeader()); + } + + private int fill(byte[] buf) { + int len = buf.length; + int n = 0; + do{ + int i = -1; + try { + i = in.read(buf, n, buf.length - n); + } + catch(IOException e){ + } + if(i == -1){ + break; + } + n+=i; + } + while(n> 4) + 1; if(w < 48) @@ -195,7 +212,11 @@ final class Inflate{ try { r=readBytes(2, r, f); } catch(Return e){ return e.r; } - if((wrap&2)!=0 && this.need == 0x8b1fL) { // gzip header + if((wrap == 4 || (wrap&2)!=0) && + this.need == 0x8b1fL) { // gzip header + if(wrap == 4){ + wrap = 2; + } z.adler=new CRC32(); checksum(2, this.need); @@ -206,13 +227,28 @@ final class Inflate{ break; } + if((wrap&2) != 0){ + this.mode = BAD; + z.msg = "incorrect header check"; + break; + } + flags = 0; this.method = ((int)this.need)&0xff; b=((int)(this.need>>8))&0xff; - if((wrap&1)==0 || // check if zlib header allowed - (((this.method << 8)+b) % 31)!=0){ + if(((wrap&1)==0 || // check if zlib header allowed + (((this.method << 8)+b) % 31)!=0) && + (this.method&0xf)!=Z_DEFLATED){ + if(wrap == 4){ + z.next_in_index -= 2; + z.avail_in += 2; + z.total_in -= 2; + wrap = 0; + this.mode = BLOCKS; + break; + } this.mode = BAD; z.msg = "incorrect header check"; // since zlib 1.2, it is allowted to inflateSync for this case. @@ -231,6 +267,10 @@ final class Inflate{ */ break; } + + if(wrap == 4){ + wrap = 1; + } if((this.method>>4)+8>this.wbits){ this.mode = BAD; diff --git a/java/com/jcraft/jzlib/Inflater.java b/java/com/jcraft/jzlib/Inflater.java new file mode 100644 index 00000000..0fb0b098 --- /dev/null +++ b/java/com/jcraft/jzlib/Inflater.java @@ -0,0 +1,168 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 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. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +final public class Inflater extends ZStream{ + + static final private int MAX_WBITS=15; // 32K LZ77 window + static final private int DEF_WBITS=MAX_WBITS; + + static final private int Z_NO_FLUSH=0; + static final private int Z_PARTIAL_FLUSH=1; + static final private int Z_SYNC_FLUSH=2; + static final private int Z_FULL_FLUSH=3; + static final private int Z_FINISH=4; + + static final private int MAX_MEM_LEVEL=9; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + public Inflater() { + super(); + init(); + } + + public Inflater(JZlib.WrapperType wrapperType) throws GZIPException { + this(DEF_WBITS, wrapperType); + } + + public Inflater(int w, JZlib.WrapperType wrapperType) throws GZIPException { + super(); + int ret = init(w, wrapperType); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + public Inflater(int w) throws GZIPException { + this(w, false); + } + + public Inflater(boolean nowrap) throws GZIPException { + this(DEF_WBITS, nowrap); + } + + public Inflater(int w, boolean nowrap) throws GZIPException { + super(); + int ret = init(w, nowrap); + if(ret!=Z_OK) + throw new GZIPException(ret+": "+msg); + } + + private boolean finished = false; + + public int init(){ + return init(DEF_WBITS); + } + + public int init(JZlib.WrapperType wrapperType){ + return init(DEF_WBITS, wrapperType); + } + + public int init(int w, JZlib.WrapperType wrapperType) { + boolean nowrap = false; + if(wrapperType == JZlib.W_NONE){ + nowrap = true; + } + else if(wrapperType == JZlib.W_GZIP) { + w += 16; + } + else if(wrapperType == JZlib.W_ANY) { + w |= Inflate.INFLATE_ANY; + } + else if(wrapperType == JZlib.W_ZLIB) { + } + return init(w, nowrap); + } + + public int init(boolean nowrap){ + return init(DEF_WBITS, nowrap); + } + + public int init(int w){ + return init(w, false); + } + + public int init(int w, boolean nowrap){ + finished = false; + istate=new Inflate(this); + return istate.inflateInit(nowrap?-w:w); + } + + public int inflate(int f){ + if(istate==null) return Z_STREAM_ERROR; + int ret = istate.inflate(f); + if(ret == Z_STREAM_END) + finished = true; + return ret; + } + + public int end(){ + finished = true; + if(istate==null) return Z_STREAM_ERROR; + int ret=istate.inflateEnd(); +// istate = null; + return ret; + } + + public int sync(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSync(); + } + + public int syncPoint(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSyncPoint(); + } + + public int setDictionary(byte[] dictionary, int dictLength){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSetDictionary(dictionary, dictLength); + } + + public boolean finished(){ + return istate.mode==12 /*DONE*/; + } +} diff --git a/java/com/jcraft/jzlib/InflaterInputStream.java b/java/com/jcraft/jzlib/InflaterInputStream.java new file mode 100644 index 00000000..0420582a --- /dev/null +++ b/java/com/jcraft/jzlib/InflaterInputStream.java @@ -0,0 +1,247 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 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.jzlib; +import java.io.*; + +public class InflaterInputStream extends FilterInputStream { + protected final Inflater inflater; + protected byte[] buf; + + private boolean closed = false; + + private boolean eof = false; + + private boolean close_in = true; + + protected static final int DEFAULT_BUFSIZE = 512; + + public InflaterInputStream(InputStream in) throws IOException { + this(in, false); + } + + public InflaterInputStream(InputStream in, boolean nowrap) throws IOException { + this(in, new Inflater(nowrap)); + myinflater = true; + } + + public InflaterInputStream(InputStream in, Inflater inflater) throws IOException { + this(in, inflater, DEFAULT_BUFSIZE); + } + + public InflaterInputStream(InputStream in, + Inflater inflater, int size) throws IOException { + this(in, inflater, size, true); + } + + public InflaterInputStream(InputStream in, + Inflater inflater, + int size, boolean close_in) throws IOException { + super(in); + if (in == null || inflater == null) { + throw new NullPointerException(); + } + else if (size <= 0) { + throw new IllegalArgumentException("buffer size must be greater than 0"); + } + this.inflater = inflater; + buf = new byte[size]; + this.close_in = close_in; + } + + protected boolean myinflater = false; + + private byte[] byte1 = new byte[1]; + + public int read() throws IOException { + if (closed) { throw new IOException("Stream closed"); } + return read(byte1, 0, 1) == -1 ? -1 : byte1[0] & 0xff; + } + + public int read(byte[] b, int off, int len) throws IOException { + if (closed) { throw new IOException("Stream closed"); } + if (b == null) { + throw new NullPointerException(); + } + else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + else if (len == 0) { + return 0; + } + else if (eof) { + return -1; + } + + int n = 0; + inflater.setOutput(b, off, len); + while(!eof) { + if(inflater.avail_in==0) + fill(); + int err = inflater.inflate(JZlib.Z_NO_FLUSH); + n += inflater.next_out_index - off; + off = inflater.next_out_index; + switch(err) { + case JZlib.Z_DATA_ERROR: + throw new IOException(inflater.msg); + case JZlib.Z_STREAM_END: + case JZlib.Z_NEED_DICT: + eof = true; + if(err == JZlib.Z_NEED_DICT) + return -1; + break; + default: + } + if(inflater.avail_out==0) + break; + } + return n; + } + + public int available() throws IOException { + if (closed) { throw new IOException("Stream closed"); } + if (eof) { + return 0; + } + else { + return 1; + } + } + + private byte[] b = new byte[512]; + + public long skip(long n) throws IOException { + if (n < 0) { + throw new IllegalArgumentException("negative skip length"); + } + + if (closed) { throw new IOException("Stream closed"); } + + int max = (int)Math.min(n, Integer.MAX_VALUE); + int total = 0; + while (total < max) { + int len = max - total; + if (len > b.length) { + len = b.length; + } + len = read(b, 0, len); + if (len == -1) { + eof = true; + break; + } + total += len; + } + return total; + } + + public void close() throws IOException { + if (!closed) { + if (myinflater) + inflater.end(); + if(close_in) + in.close(); + closed = true; + } + } + + protected void fill() throws IOException { + if (closed) { throw new IOException("Stream closed"); } + int len = in.read(buf, 0, buf.length); + if (len == -1) { + if(inflater.istate.wrap == 0 && + !inflater.finished()){ + buf[0]=0; + len=1; + } + else if(inflater.istate.was != -1){ // in reading trailer + throw new IOException("footer is not found"); + } + else{ + throw new EOFException("Unexpected end of ZLIB input stream"); + } + } + inflater.setInput(buf, 0, len, true); + } + + public boolean markSupported() { + return false; + } + + public synchronized void mark(int readlimit) { + } + + public synchronized void reset() throws IOException { + throw new IOException("mark/reset not supported"); + } + + public long getTotalIn() { + return inflater.getTotalIn(); + } + + public long getTotalOut() { + return inflater.getTotalOut(); + } + + public byte[] getAvailIn() { + if(inflater.avail_in<=0) + return null; + byte[] tmp = new byte[inflater.avail_in]; + System.arraycopy(inflater.next_in, inflater.next_in_index, + tmp, 0, inflater.avail_in); + return tmp; + } + + public void readHeader() throws IOException { + + byte[] empty = "".getBytes(); + inflater.setInput(empty, 0, 0, false); + inflater.setOutput(empty, 0, 0); + + int err = inflater.inflate(JZlib.Z_NO_FLUSH); + if(!inflater.istate.inParsingHeader()){ + return; + } + + byte[] b1 = new byte[1]; + do{ + int i = in.read(b1); + if(i<=0) + throw new IOException("no input"); + inflater.setInput(b1); + err = inflater.inflate(JZlib.Z_NO_FLUSH); + if(err!=0/*Z_OK*/) + throw new IOException(inflater.msg); + } + while(inflater.istate.inParsingHeader()); + } + + public Inflater getInflater(){ + return inflater; + } +} \ No newline at end of file diff --git a/java/com/jcraft/jzlib/JZlib.java b/java/com/jcraft/jzlib/JZlib.java index 8fd98ea7..a4bb3410 100644 --- a/java/com/jcraft/jzlib/JZlib.java +++ b/java/com/jcraft/jzlib/JZlib.java @@ -41,6 +41,15 @@ final public class JZlib{ static final public int MAX_WBITS=15; // 32K LZ77 window static final public int DEF_WBITS=MAX_WBITS; + public enum WrapperType { + NONE, ZLIB, GZIP, ANY + } + + public static final WrapperType W_NONE = WrapperType.NONE; + public static final WrapperType W_ZLIB = WrapperType.ZLIB; + public static final WrapperType W_GZIP = WrapperType.GZIP; + public static final WrapperType W_ANY = WrapperType.ANY; + // compression levels static final public int Z_NO_COMPRESSION=0; static final public int Z_BEST_SPEED=1; diff --git a/java/com/jcraft/jzlib/Tree.java b/java/com/jcraft/jzlib/Tree.java index 40b6ba87..38cb40f2 100644 --- a/java/com/jcraft/jzlib/Tree.java +++ b/java/com/jcraft/jzlib/Tree.java @@ -308,7 +308,7 @@ final class Tree{ gen_bitlen(s); // The field len is now set, we can generate the bit codes - gen_codes(tree, max_code, s.bl_count); + gen_codes(tree, max_code, s.bl_count, s.next_code); } // Generate the codes for a given tree and bit counts (which need not be @@ -317,11 +317,11 @@ final class Tree{ // the given tree and the field len is set for all tree elements. // OUT assertion: the field code is set for all tree elements of non // zero code length. - static short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length - synchronized static void gen_codes(short[] tree, // the tree to decorate - int max_code, // largest code with non zero frequency - short[] bl_count // number of codes at each bit length - ){ + private final static void gen_codes( + short[] tree, // the tree to decorate + int max_code, // largest code with non zero frequency + short[] bl_count, // number of codes at each bit length + short[] next_code){ short code = 0; // running code value int bits; // bit index int n; // code index @@ -350,7 +350,8 @@ final class Tree{ // Reverse the first len bits of a code, using straightforward code (a faster // method would use a table) // IN assertion: 1 <= len <= 15 - static int bi_reverse(int code, // the value to invert + private final static int bi_reverse( + int code, // the value to invert int len // its bit length ){ int res = 0; diff --git a/java/com/jcraft/jzlib/ZInputStream.java b/java/com/jcraft/jzlib/ZInputStream.java index 0054645e..cbd38e15 100644 --- a/java/com/jcraft/jzlib/ZInputStream.java +++ b/java/com/jcraft/jzlib/ZInputStream.java @@ -50,7 +50,7 @@ public class ZInputStream extends FilterInputStream { } public ZInputStream(InputStream in, boolean nowrap) throws IOException { super(in); - iis = new InflaterInputStream(in); + iis = new InflaterInputStream(in, nowrap); compress=false; } diff --git a/java/com/jcraft/jzlib/ZStream.java b/java/com/jcraft/jzlib/ZStream.java index dd0a5256..0afa4fd0 100644 --- a/java/com/jcraft/jzlib/ZStream.java +++ b/java/com/jcraft/jzlib/ZStream.java @@ -99,7 +99,24 @@ public class ZStream{ public int inflateInit(int w){ return inflateInit(w, false); } - + public int inflateInit(JZlib.WrapperType wrapperType) { + return inflateInit(DEF_WBITS, wrapperType); + } + public int inflateInit(int w, JZlib.WrapperType wrapperType) { + boolean nowrap = false; + if(wrapperType == JZlib.W_NONE){ + nowrap = true; + } + else if(wrapperType == JZlib.W_GZIP) { + w += 16; + } + else if(wrapperType == JZlib.W_ANY) { + w |= Inflate.INFLATE_ANY; + } + else if(wrapperType == JZlib.W_ZLIB) { + } + return inflateInit(w, nowrap); + } public int inflateInit(int w, boolean nowrap){ istate=new Inflate(this); return istate.inflateInit(nowrap?-w:w); @@ -143,6 +160,23 @@ public class ZStream{ public int deflateInit(int level, int bits){ return deflateInit(level, bits, false); } + public int deflateInit(int level, int bits, int memlevel, JZlib.WrapperType wrapperType){ + if(bits < 9 || bits > 15){ + return Z_STREAM_ERROR; + } + if(wrapperType == JZlib.W_NONE) { + bits *= -1; + } + else if(wrapperType == JZlib.W_GZIP) { + bits += 16; + } + else if(wrapperType == JZlib.W_ANY) { + return Z_STREAM_ERROR; + } + else if(wrapperType == JZlib.W_ZLIB) { + } + return this.deflateInit(level, bits, memlevel); + } public int deflateInit(int level, int bits, int memlevel){ dstate=new Deflate(this); return dstate.deflateInit(level, bits, memlevel); diff --git a/java/com/jcraft/jzlib/ZStreamException.java b/java/com/jcraft/jzlib/ZStreamException.java index 308bb8a1..424b74b7 100644 --- a/java/com/jcraft/jzlib/ZStreamException.java +++ b/java/com/jcraft/jzlib/ZStreamException.java @@ -1,44 +1,44 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 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. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -public class ZStreamException extends java.io.IOException { - public ZStreamException() { - super(); - } - public ZStreamException(String s) { - super(s); - } -} +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2000,2001,2002,2003 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. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package com.jcraft.jzlib; + +public class ZStreamException extends java.io.IOException { + public ZStreamException() { + super(); + } + public ZStreamException(String s) { + super(s); + } +} -- 2.39.5