]> source.dussan.org Git - tigervnc.git/commitdiff
Upgrade in-tree jsch and jzlib to latest upstream versions
authorBrian P. Hinz <bphinz@users.sf.net>
Sun, 27 Dec 2015 02:48:11 +0000 (21:48 -0500)
committerBrian P. Hinz <bphinz@users.sf.net>
Sun, 27 Dec 2015 02:48:11 +0000 (21:48 -0500)
153 files changed:
java/CMakeLists.txt
java/com/jcraft/jsch/Buffer.java
java/com/jcraft/jsch/ChangeLog
java/com/jcraft/jsch/Channel.java
java/com/jcraft/jsch/ChannelAgentForwarding.java
java/com/jcraft/jsch/ChannelDirectTCPIP.java
java/com/jcraft/jsch/ChannelExec.java
java/com/jcraft/jsch/ChannelForwardedTCPIP.java
java/com/jcraft/jsch/ChannelSession.java
java/com/jcraft/jsch/ChannelSftp.java
java/com/jcraft/jsch/ChannelShell.java
java/com/jcraft/jsch/ChannelSubsystem.java
java/com/jcraft/jsch/ChannelX11.java
java/com/jcraft/jsch/Cipher.java
java/com/jcraft/jsch/CipherNone.java
java/com/jcraft/jsch/Compression.java
java/com/jcraft/jsch/ConfigRepository.java [new file with mode: 0644]
java/com/jcraft/jsch/DH.java
java/com/jcraft/jsch/DHEC256.java [new file with mode: 0644]
java/com/jcraft/jsch/DHEC384.java [new file with mode: 0644]
java/com/jcraft/jsch/DHEC521.java [new file with mode: 0644]
java/com/jcraft/jsch/DHECN.java [new file with mode: 0644]
java/com/jcraft/jsch/DHG1.java
java/com/jcraft/jsch/DHG14.java
java/com/jcraft/jsch/DHGEX.java
java/com/jcraft/jsch/DHGEX256.java [new file with mode: 0644]
java/com/jcraft/jsch/ECDH.java [new file with mode: 0644]
java/com/jcraft/jsch/ForwardedTCPIPDaemon.java
java/com/jcraft/jsch/GSSContext.java
java/com/jcraft/jsch/HASH.java
java/com/jcraft/jsch/HostKey.java
java/com/jcraft/jsch/HostKeyRepository.java
java/com/jcraft/jsch/IO.java
java/com/jcraft/jsch/Identity.java
java/com/jcraft/jsch/IdentityFile.java
java/com/jcraft/jsch/IdentityRepository.java
java/com/jcraft/jsch/JSch.java
java/com/jcraft/jsch/JSchAuthCancelException.java
java/com/jcraft/jsch/JSchException.java
java/com/jcraft/jsch/JSchPartialAuthException.java
java/com/jcraft/jsch/KeyExchange.java
java/com/jcraft/jsch/KeyPair.java
java/com/jcraft/jsch/KeyPairDSA.java
java/com/jcraft/jsch/KeyPairECDSA.java [new file with mode: 0644]
java/com/jcraft/jsch/KeyPairGenDSA.java
java/com/jcraft/jsch/KeyPairGenECDSA.java [new file with mode: 0644]
java/com/jcraft/jsch/KeyPairGenRSA.java
java/com/jcraft/jsch/KeyPairPKCS8.java [new file with mode: 0644]
java/com/jcraft/jsch/KeyPairRSA.java
java/com/jcraft/jsch/KnownHosts.java
java/com/jcraft/jsch/LICENSE.txt
java/com/jcraft/jsch/LocalIdentityRepository.java
java/com/jcraft/jsch/Logger.java
java/com/jcraft/jsch/MAC.java
java/com/jcraft/jsch/OpenSSHConfig.java [new file with mode: 0644]
java/com/jcraft/jsch/PBKDF.java [new file with mode: 0644]
java/com/jcraft/jsch/Packet.java
java/com/jcraft/jsch/PortWatcher.java
java/com/jcraft/jsch/Proxy.java
java/com/jcraft/jsch/ProxyHTTP.java
java/com/jcraft/jsch/ProxySOCKS4.java
java/com/jcraft/jsch/ProxySOCKS5.java
java/com/jcraft/jsch/README
java/com/jcraft/jsch/Random.java
java/com/jcraft/jsch/Request.java
java/com/jcraft/jsch/RequestAgentForwarding.java
java/com/jcraft/jsch/RequestEnv.java
java/com/jcraft/jsch/RequestExec.java
java/com/jcraft/jsch/RequestPtyReq.java
java/com/jcraft/jsch/RequestSftp.java
java/com/jcraft/jsch/RequestShell.java
java/com/jcraft/jsch/RequestSignal.java
java/com/jcraft/jsch/RequestSubsystem.java
java/com/jcraft/jsch/RequestWindowChange.java
java/com/jcraft/jsch/RequestX11.java
java/com/jcraft/jsch/ServerSocketFactory.java
java/com/jcraft/jsch/Session.java
java/com/jcraft/jsch/SftpATTRS.java
java/com/jcraft/jsch/SftpException.java
java/com/jcraft/jsch/SftpProgressMonitor.java
java/com/jcraft/jsch/SftpStatVFS.java [new file with mode: 0644]
java/com/jcraft/jsch/Signature.java [new file with mode: 0644]
java/com/jcraft/jsch/SignatureDSA.java
java/com/jcraft/jsch/SignatureECDSA.java [new file with mode: 0644]
java/com/jcraft/jsch/SignatureRSA.java
java/com/jcraft/jsch/SocketFactory.java
java/com/jcraft/jsch/UIKeyboardInteractive.java
java/com/jcraft/jsch/UserAuth.java
java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java
java/com/jcraft/jsch/UserAuthKeyboardInteractive.java
java/com/jcraft/jsch/UserAuthNone.java
java/com/jcraft/jsch/UserAuthPassword.java
java/com/jcraft/jsch/UserAuthPublicKey.java
java/com/jcraft/jsch/UserInfo.java
java/com/jcraft/jsch/Util.java
java/com/jcraft/jsch/jce/AES128CBC.java
java/com/jcraft/jsch/jce/AES128CTR.java
java/com/jcraft/jsch/jce/AES192CBC.java
java/com/jcraft/jsch/jce/AES192CTR.java
java/com/jcraft/jsch/jce/AES256CBC.java
java/com/jcraft/jsch/jce/AES256CTR.java
java/com/jcraft/jsch/jce/ARCFOUR.java
java/com/jcraft/jsch/jce/ARCFOUR128.java
java/com/jcraft/jsch/jce/ARCFOUR256.java
java/com/jcraft/jsch/jce/BlowfishCBC.java
java/com/jcraft/jsch/jce/DH.java
java/com/jcraft/jsch/jce/ECDH256.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/ECDH384.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/ECDH521.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/ECDHN.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/HMAC.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/HMACMD5.java
java/com/jcraft/jsch/jce/HMACMD596.java
java/com/jcraft/jsch/jce/HMACSHA1.java
java/com/jcraft/jsch/jce/HMACSHA196.java
java/com/jcraft/jsch/jce/HMACSHA256.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/HMACSHA512.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/KeyPairGenDSA.java
java/com/jcraft/jsch/jce/KeyPairGenECDSA.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/KeyPairGenRSA.java
java/com/jcraft/jsch/jce/MD5.java
java/com/jcraft/jsch/jce/PBKDF.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/Random.java
java/com/jcraft/jsch/jce/SHA1.java
java/com/jcraft/jsch/jce/SHA256.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/SHA384.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/SHA512.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/SignatureDSA.java
java/com/jcraft/jsch/jce/SignatureECDSA.java [new file with mode: 0644]
java/com/jcraft/jsch/jce/SignatureRSA.java
java/com/jcraft/jsch/jce/TripleDESCBC.java
java/com/jcraft/jsch/jce/TripleDESCTR.java
java/com/jcraft/jsch/jcraft/Compression.java
java/com/jcraft/jsch/jcraft/HMAC.java
java/com/jcraft/jsch/jcraft/HMACMD5.java
java/com/jcraft/jsch/jcraft/HMACMD596.java
java/com/jcraft/jsch/jcraft/HMACSHA1.java
java/com/jcraft/jsch/jcraft/HMACSHA196.java
java/com/jcraft/jsch/jgss/GSSContextKrb5.java
java/com/jcraft/jzlib/Deflate.java
java/com/jcraft/jzlib/Deflater.java [new file with mode: 0644]
java/com/jcraft/jzlib/DeflaterOutputStream.java [new file with mode: 0644]
java/com/jcraft/jzlib/GZIPException.java [new file with mode: 0644]
java/com/jcraft/jzlib/GZIPInputStream.java [new file with mode: 0644]
java/com/jcraft/jzlib/GZIPOutputStream.java [new file with mode: 0644]
java/com/jcraft/jzlib/Inflate.java
java/com/jcraft/jzlib/Inflater.java [new file with mode: 0644]
java/com/jcraft/jzlib/InflaterInputStream.java [new file with mode: 0644]
java/com/jcraft/jzlib/JZlib.java
java/com/jcraft/jzlib/Tree.java
java/com/jcraft/jzlib/ZInputStream.java
java/com/jcraft/jzlib/ZStream.java
java/com/jcraft/jzlib/ZStreamException.java

index 8dd09d1ba0f925352c85c289306d09fec0409a52..a076d958a6a1315c808704463e8c58423dbb9893 100644 (file)
@@ -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
index a3135a1550ca486837663c8c741d674630139447..c54e4292ed60414f3332411f4da3e642423f1ea5 100644 (file)
@@ -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<index+n){
-      byte[] tmp = new byte[buffer.length*2];
+    int size = index+n+Session.buffer_margin;
+    if(buffer.length<size){
+      int i = buffer.length*2;
+      if(i<size) i = size;
+      byte[] tmp = new byte[i];
       System.arraycopy(buffer, 0, tmp, 0, index);
       buffer = tmp;
     }
   }
 
+  byte[][] getBytes(int n, String msg) throws JSchException {
+    byte[][] tmp = new byte[n][];
+    for(int i = 0; i < n; i++){
+      int j = getInt();
+      if(getLength() < j){
+        throw new JSchException(msg);
+      }
+      tmp[i] = new byte[j];
+      getByte(tmp[i]);
+    }
+    return tmp;
+  }
+
+  /*
+  static Buffer fromBytes(byte[]... args){
+    int length = args.length*4;
+    for(int i = 0; i < args.length; i++){
+      length += args[i].length;
+    }
+    Buffer buf = new Buffer(length);
+    for(int i = 0; i < args.length; i++){
+      buf.putString(args[i]);
+    }
+    return buf;
+  }
+  */
+
+  static Buffer fromBytes(byte[][] args){
+    int length = args.length*4;
+    for(int i = 0; i < args.length; i++){
+      length += args[i].length;
+    }
+    Buffer buf = new Buffer(length);
+    for(int i = 0; i < args.length; i++){
+      buf.putString(args[i]);
+    }
+    return buf;
+  }
+
+
 /*
   static String[] chars={
     "0","1","2","3","4","5","6","7","8","9", "a","b","c","d","e","f"
index 7642c28a34c393112197211b6ae682d4597b3ae9..a88f83320bdff6c56c13cf503ed51c8839f97b97 100644 (file)
@@ -1,8 +1,240 @@
 ChangeLog of JSch
 ====================================================================
-Last modified: Thu Feb  2 09:04:04 UTC 2012
+Last modified: Fri Jun  5 03:22:57 UTC 2015
+
+
+Changes since version 0.1.52:
+- bugfix: the rekey initiated by the remote may crash the session.
+- change: Logjam: use ecdh-sha2-nistp* if available,
+          ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
+          diffie-hellman-group14-sha1,
+          diffie-hellman-group-exchange-sha256,
+          diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1
+- change: Logjam: diffie-hellman-group-exchange-sha256 and
+          diffie-hellman-group-exchange-sha1 will use 2048-bit key on
+          Java8's SunJCE, thanks to JDK-6521495 and JDK-7044060.
+- change: key words for OpenSSH's config file should be case-insensitive.
+- change: there should be the host name in "WARNING: REMOTE HOST
+          IDENTIFICATION HAS CHANGED" message.
+
+
+Changes since version 0.1.51:
+- bugfix: resource leak: duplicate keys in LocalIdentityRepository.
+- feature: added the support for SSH ECC defined in RFC5656,
+           ecdsa-sha2-nistp256,
+           ecdsa-sha2-nistp384,
+           ecdsa-sha2-nistp521,
+           ecdh-sha2-nistp256,
+           ecdh-sha2-nistp384,
+           ecdh-sha2-nistp521
+           This functionality requires Java7 or later.
+- feature: added the support for server host keys in
+           ecdsa-sha2-nistp256,
+           ecdsa-sha2-nistp384,
+           ecdsa-sha2-nistp521
+- feature: generating key-pairs in
+           ecdh-sha2-nistp256,
+           ecdh-sha2-nistp384,
+           ecdh-sha2-nistp521
+- change: aes192-ctr, aes256-ctr and
+          diffie-hellman-group-exchange-sha256 have been enabled
+          by the default.
+- change: key exchange methods, ecdh-sha2-nistp256,
+          ecdh-sha2-nistp384 and ecdh-sha2-nistp521 have been enabled
+          by the default.
+- change: the support for host keys in ecdsa-sha2-nistp256,
+          ecdsa-sha2-nistp384 and ecdsa-sha2-nistp521 have been enabled
+          by the default.
+- change: 'examples/KeyGen.java' demonstrates how to generate
+          ecdsa-sha2-* key-pairs.
+- change: updating copyright messages; 2014 -> 2015
+- TODO: The ECC support is not functional on Java6 with BouncyCastle.
+
+
+Changes since version 0.1.50:
+- bugfix: reproducibility of "verify: false".   FIXED.
+          Hundreds of thousands of connections had caused that exception.
+- bugfix: resource leaks at the failure of making local port forwarding. FIXED.
+- bugfix: NPE in connecting to the non-standard TCP port.  FIXED.
+          This problem had appeared if a host-key does not exist in
+         "known_host" file.
+- bugfix: TCP connection may not be dropped if error messages from
+         the remote are too long.                          FIXED.
+- bugfix: SftpATTRS#getAtimeString() returns the wrong string. FIXED.
+- bugfix: bytes to be added by SSH_MSG_CHANNEL_WINDOW_ADJUST must be in
+         unsigned integer. FIXED.
+- bugfix: Util#checkTilde() should not convert a tilde in
+          "C:\PROGRA~1\". FIXED.
+- bugfix: A long long command for ChannelExec will cause
+          an ArrayIndexOutOfBoundsException. FIXED.
+- bugfix: ChannelSftp should not send bulk request greedily even if the remote
+          window has the enough space.  FIXED.
+- bugfix: Util.createSocket() should throw an exception with 'cause'. FIXED.
+- bugfix: failed to parse .ssh/config in the EBCDIC environment. FIXED.
+- bugfix: com.jcraft.jsch.jcraft.HMACSHA1(used only for MacOSX) is not
+          reusable.  FIXED.
+- bugfix: NPE caused by the delayed response for channel opening
+          requests. FIXED.
+- bugfix: hung-up in uploading huge data to ProFTPd without the config
+          'SFTPClientMatch "JSCH.*" channelWindowSize 1GB'  FIXED.
+- bugfix: Cipher#init() may cause an infinite loop with 100% cpu use due to
+          https://bugs.openjdk.java.net/browse/JDK-8028627  FIXED.
+- bugfix: in some case, JSche#setKnowHosts(InputStream stream) may fail
+          to close the given stream.  FIXED
+- change: com.jcraft.jsch.jcraft.HMAC* will not be used.
+          It seems Java6 on Mac OS X has fixed some memory leak bug in JCE,
+         so there is no reason to use c.j.j.j.HMAC* introduced at 0.1.30.
+- change: updating copyright messages; 2013 -> 2014
+- change: allowed to create the symbolic/hard link to the relative path by
+          ChannelSftp#symlink(String oldpath, String newpath)
+          ChannelSftp#hardlink(String oldpath, String newpath)
+- change: the availability of ciphers listed in "CheckCiphers" config will
+          not be checked if they are not used.
+- change: Util#fromBase64() will throw JSchException in stead of
+          RuntimeException, if the given string is not in base64 format.
+- feature: added the support for private keys in PKCS#8 format.
+- feature: introduced the interface com.jcraft.jsch.PBKDF to abstract
+           the implementation of Password-Based Key Derivation Function,
+           and added its implementation com.jcraft.jsch.jce.PBKDF by using JCE.
+
+
+Changes since version 0.1.49:
+- bugfix: "verify: false" error on Java7u6(and later).  FIXED.
+          http://stackoverflow.com/questions/12279836/ssh-using-jschexception-verify-false-sometimes-fails
+          https://issues.apache.org/jira/browse/IVY-1374
+- bugfix: Session#setPortForwardingL(String bind_address,
+                                    int lport, String host, int rport)
+         will not work for the long host name.         FIXED.
+- change: changed JSch#getIdentityRepository() to be public.
+- feature: added the following method to choose a canceled remote
+          port-forwarding with the specified bind address,
+             Session#delPortForwardingR(String bind_address, int rport)
+- feature: added support for following OpenSSH's sftp extensions,
+             posix-rename@openssh.com,
+             statvfs@openssh.com,
+             hardlink@openssh.com,
+          and some methods and a class to use those functionalities,
+             ChannelSftp#hardlink(String oldpath, String newpath),
+            ChannelSftp#statVFS(String path)
+             SftpStatVFS
+- feature: added support for OpenSSH's configuration file,
+            JSch#setConfigRepository(ConfigRepository configRepository)
+            JSch#getConfigRepository()
+             OpenSSHConfig class
+             Session#getSession(String host)
+          and added an example to demonstrate how to use it,
+            examples/OpenSSHConfig.java
+          OpenSSHConfig class will recognize the following keywords,
+             Host
+             User
+             Hostname
+             Port
+             PreferredAuthentications
+             IdentityFile
+             NumberOfPasswordPrompts
+             ConnectTimeout
+             HostKeyAlias
+             UserKnownHostsFile
+             KexAlgorithms
+             HostKeyAlgorithms
+             Ciphers
+             Macs
+             Compression
+             CompressionLevel
+             ForwardAgent
+             RequestTTY
+             ServerAliveInterval
+             LocalForward
+             RemoteForward
+             ClearAllForwardings
+- feature: added support for "diffie-hellman-group-exchange-sha256"
+- feature: allowed to use tilde(~) in the file name,
+             JSch#setIdentity(String prvkey, String pubkey)
+             JSch#setKnownHosts(String prvkey, String pubkey)
+- feature: added support for known_hosts file, which may include
+          markers(@revoke) and comments.
+             HostKey(String host, int type, byte[] key, String comment)
+             HostKey(String marker, String host, int type,
+                     byte[] key, String comment)
+             HostKey#getComment()
+             HostKey#getMarker()
+- feature: added following methods to KeyPar class,
+             writePrivateKey(java.io.OutputStream out, byte[] passphrase)
+             writePrivateKey(String name, byte[] passphrase)
+- feature: allowed to set the connection timeout for the local port-forwarding,
+          and added following methods,
+             Session#setPortForwardingL(String bind_address,
+                                        int lport, String host, int rport,
+                                        ServerSocketFactory ssf,
+                                        int connectTimeout)
+             ChannelDirectTCPIP#connect(int connectTimeout)
+- feature: added the following method to Session class
+            getStreamForwarder(String host, int port)
+           and updated example/StreamForwarding.java to use that method.
+- feature: added following methods to Session class,
+             setPortForwardingL(String conf)
+             setPortForwardingR(String conf)
+- feature: allowed to have the session local HostkeyRepository,
+             Session#setHostKeyRepository(HostKeyRepository hostkeyRepository)
+             Session#getHostKeyRepository()
+- feature: added support for OpenSSH's local extension,
+          "no-more-sessions@openssh.com" and the method,
+             Session#noMoreSessionChannels()
+
+
+Changes since version 0.1.48:
+- bugfix: Some sftp servers will sometimes fail to handle bulk requests,
+         and whenever detecting such failures, we should re-send
+          requests again and again.                                    FIXED
+- bugfix: KeyPair#getFingerPrint() should return a fingerprint instead
+         of keysize + " " + fingerprint.                              FIXED
+- bugfix: KeyPair#getKeySize() should return its key size.             FIXED
+- bugfix: SftpATTRS#isDir() should return false for unix domain
+         socket files.                                                FIXED
+- change: improved the heuristics for the password prompt in
+         the keyboard-interactive authentication.  It may not be
+         started with "password:".
+- change: ChannelSftp#put(InputStream src, String dst) will not check
+         if dst is directory or not, and if an exception is thrown,
+         the check will be done.
+- change: if the compression is enabled without jzlib.jar,
+         an exception will be thrown.
+- feature: JSch#addIdentity() and KeyPair#load() methods will accept
+          Putty's private key files.
+          Note that Putty encrypts its private key with "aes256-cbc".
+          So, to handle such key files, "Java Cryptography
+          Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
+          must be installed.
+- feature: hmac-sha2-256 defined in RFC6668 is supported.
+- feature: added following methods to KeyPair class,
+          byte[] getSignature(byte[] data)
+          Signature getVerifier()
+          byte[] forSSHAgent()
+          void setPublicKeyComment(String comment)
+- feature: added following methods to SftpATTR class,
+           boolean isChr()
+           boolean isBlk()
+           boolean isFifo()
+           boolean isSock()
+
+
+Changes since version 0.1.47:
+- change: the file transfer speed with ChannelSftp#get(String src) has been
+          improved; sending multiple requests at any one time.
+- change: by the default, at most, 16 requests will be sent at any one time
+          in ChannelSftp.
+- feature: added Session#{setIdentityRepository(),getIdentityRepository()}
+
+
+Changes since version 0.1.46:
+- bugfix: failed to initialize channels for the stream forwarding.     FIXED
+- change: Session#getHostKey() will return the given hostkey
+         even if session is not established.
+- change: Logger will record additional messages about algorithm negotiations.
+- feature: added ChannelSftp#ls(String path, LsEntrySelector selector) method.
+- feature: added IdentityRepository#{getName(),getStatus()} methods.
+
 
-       
 Changes since version 0.1.45:
 - bugfix: in the agent forwarding mode, "ssh-add -l" on the remote
           will freeze.                                                 FIXED
@@ -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.
index 73cc4dbf8da887e83541703b3ac05b1ddf6833b4..8c060dd6930cf57b11e27beac7e5d543d49f73c3 100644 (file)
@@ -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_input_buffer_size;
+    io.setOutputStream(new PassiveOutputStream(in, resizable), false);
     return in;
   }
   public InputStream getExtInputStream() 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.setExtOutputStream(new PassiveOutputStream(in), false);
+    boolean resizable = 32*1024<max_input_buffer_size;
+    io.setExtOutputStream(new PassiveOutputStream(in, resizable), false);
     return in;
   }
   public OutputStream getOutputStream() throws IOException {
-    /*
-    PipedOutputStream out=new PipedOutputStream();
-    io.setInputStream(new PassiveInputStream(out
-                                             , 32*1024
-                                             ), false);
-    return out;
-    */
 
     final Channel channel=this;
     OutputStream out=new OutputStream(){
@@ -317,15 +326,24 @@ public abstract class Channel implements Runnable{
   }
 
   class MyPipedInputStream extends PipedInputStream{
+    private int BUFFER_SIZE = 1024;
+    private int max_buffer_size = BUFFER_SIZE;
     MyPipedInputStream() throws IOException{ super(); }
     MyPipedInputStream(int size) throws IOException{
       super();
       buffer=new byte[size];
+      BUFFER_SIZE = size;
+      max_buffer_size = size;
+    }
+    MyPipedInputStream(int size, int max_buffer_size) throws IOException{
+      this(size);
+      this.max_buffer_size = max_buffer_size;
     }
     MyPipedInputStream(PipedOutputStream out) throws IOException{ super(out); }
     MyPipedInputStream(PipedOutputStream out, int size) throws IOException{
       super(out);
       buffer=new byte[size];
+      BUFFER_SIZE=size;
     }
 
     /*
@@ -343,12 +361,66 @@ public abstract class Channel implements Runnable{
       buffer[in++] = 0;
       read();
     }
+
+    private int freeSpace(){
+      int size = 0;
+      if(out < in) {
+        size = buffer.length-in;
+      }
+      else if(in < out){
+        if(in == -1) size = buffer.length;
+        else size = out - in;
+      }
+      return size;
+    } 
+    synchronized void checkSpace(int len) throws IOException {
+      int size = freeSpace();
+      if(size<len){
+        int datasize=buffer.length-size;
+        int foo = buffer.length;
+        while((foo - datasize) < len){
+          foo*=2;
+        }
+
+        if(foo > 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(i<BUFFER_SIZE) i = BUFFER_SIZE;
+        byte[] tmp = new byte[i];
+        buffer=tmp;
+      }
+    }
   }
   void setLocalWindowSizeMax(int foo){ this.lwsize_max=foo; }
   void setLocalWindowSize(int foo){ this.lwsize=foo; }
   void setLocalPacketSize(int foo){ this.lmpsize=foo; }
   synchronized void setRemoteWindowSize(long foo){ this.rwsize=foo; }
-  synchronized void addRemoteWindowSize(int foo){ 
+  synchronized void addRemoteWindowSize(long foo){ 
     this.rwsize+=foo; 
     if(notifyme>0)
       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);
         }
index 52e2db19781eb86d17fbcc560ca0d94bdded0731..32db395dba3e7435dc0afcf2271d5d2ff499ae53 100644 (file)
@@ -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();
index c8af6a2be7b36219f0afdb10997aa75c855f7940..dde42442c0d8f01b38bad6cf367882d8229aeaa7 100644 (file)
@@ -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         //
index 45322b63b2c4e32215d1798192041711a46f2519..10722c22cd38927f3a6652917e30cab109e48411 100644 (file)
@@ -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:
index 39972e1988204a7ba32b19b38f97814c9e120da6..41f9bebf3f16bf468ee5dbf9ac362cd158cbd34c 100644 (file)
@@ -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<pool.size(); i++){
-        Object[] foo=(Object[])(pool.elementAt(i));
-        if(foo[0]!=_session) continue;
-        if(((Integer)foo[1]).intValue()!=port) continue;
-        this.rport=port;
-        this.target=(String)foo[2];
-        if(foo[3]==null || (foo[3] instanceof Object[])){ this.lport=-1; }
-        else{ this.lport=((Integer)foo[3]).intValue(); }
-        if(foo.length>=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; i<pool.size(); i++){
-        Object[] bar=(Object[])(pool.elementAt(i));
-        if(bar[0]!=session) continue;
-        if(((Integer)bar[1]).intValue()!=rport) continue;
+        Config bar = (Config)(pool.elementAt(i));
+        if(bar.session != session) continue;
+        if(bar.rport != rport) {
+          if(bar.rport != 0 || bar.allocated_rport != rport)
+            continue;
+        }
+        if(address_to_bind != null &&
+           !bar.address_to_bind.equals(address_to_bind)) continue;
         return bar;
       }
       return null;
@@ -188,13 +182,14 @@ public class ChannelForwardedTCPIP extends Channel{
   }
 
   static String[] getPortForwarding(Session session){
-    java.util.Vector foo=new java.util.Vector();
+    Vector foo = new Vector();
     synchronized(pool){
       for(int i=0; i<pool.size(); i++){
-        Object[] bar=(Object[])(pool.elementAt(i));
-        if(bar[0]!=session) continue;
-        if(bar[3]==null){ foo.addElement(bar[1]+":"+bar[2]+":"); }
-        else{ foo.addElement(bar[1]+":"+bar[2]+":"+bar[3]); }
+        Config config = (Config)(pool.elementAt(i));
+        if(config instanceof ConfigDaemon)
+          foo.addElement(config.allocated_rport+":"+config.target+":");
+        else
+          foo.addElement(config.allocated_rport+":"+config.target+":"+((ConfigLHost)config).lport);
       }
     }
     String[] bar=new String[foo.size()];
@@ -210,31 +205,39 @@ public class ChannelForwardedTCPIP extends Channel{
     else{ return address; }
   }
 
-  static void addPort(Session session, String _address_to_bind, int port, String target, int lport, SocketFactory factory) throws JSchException{
+  static void addPort(Session session, String _address_to_bind,
+                      int port, int allocated_port, String target, int lport, SocketFactory factory) throws JSchException{
     String address_to_bind=normalize(_address_to_bind);
     synchronized(pool){
-      if(getPort(session, port)!=null){
+      if(getPort(session, address_to_bind, port)!=null){
         throw new JSchException("PortForwardingR: remote port "+port+" is already registered.");
       }
-      Object[] foo=new Object[6];
-      foo[0]=session; foo[1]=new Integer(port);
-      foo[2]=target; foo[3]=new Integer(lport);
-      foo[4]=address_to_bind;
-      foo[5]=factory;
-      pool.addElement(foo);
+      ConfigLHost config = new ConfigLHost();
+      config.session = session;
+      config.rport = port;
+      config.allocated_rport = allocated_port;
+      config.target = target;
+      config.lport =lport;
+      config.address_to_bind = address_to_bind;
+      config.factory = factory;
+      pool.addElement(config);
     }
   }
-  static void addPort(Session session, String _address_to_bind, int port, String daemon, Object[] arg) throws JSchException{
+  static void addPort(Session session, String _address_to_bind,
+                      int port, int allocated_port, String daemon, Object[] arg) throws JSchException{
     String address_to_bind=normalize(_address_to_bind);
     synchronized(pool){
-      if(getPort(session, port)!=null){
+      if(getPort(session, address_to_bind, port)!=null){
         throw new JSchException("PortForwardingR: remote port "+port+" is already registered.");
       }
-      Object[] foo=new Object[5];
-      foo[0]=session; foo[1]=new Integer(port);
-      foo[2]=daemon; foo[3]=arg;
-      foo[4]=address_to_bind; 
-      pool.addElement(foo);
+      ConfigDaemon config = new ConfigDaemon();
+      config.session = session;
+      config.rport = port;
+      config.allocated_rport = port;
+      config.target = daemon;
+      config.arg = arg;
+      config.address_to_bind = address_to_bind;
+      pool.addElement(config);
     }
   }
   static void delPort(ChannelForwardedTCPIP c){
@@ -245,26 +248,21 @@ public class ChannelForwardedTCPIP extends Channel{
     catch(JSchException e){
       // session has been already down.
     }
-    if(_session!=null)
-      delPort(_session, c.rport);
+    if(_session!=null && c.config!=null)
+      delPort(_session, c.config.rport);
   }
   static void delPort(Session session, int rport){
     delPort(session, null, rport);
   }
   static void delPort(Session session, String address_to_bind, int rport){
     synchronized(pool){
-      Object[] foo=null;
-      for(int i=0; i<pool.size(); i++){
-        Object[] bar=(Object[])(pool.elementAt(i));
-        if(bar[0]!=session) continue;
-        if(((Integer)bar[1]).intValue()!=rport) continue;
-        foo=bar;
-        break;
-      }
-      if(foo==null)return;
+      Config foo = getPort(session, normalize(address_to_bind), rport);
+      if(foo == null)
+        foo = getPort(session, null, rport);
+      if(foo==null) return;
       pool.removeElement(foo);
       if(address_to_bind==null){
-        address_to_bind=(String)foo[4];
+        address_to_bind=foo.address_to_bind;
       }        
       if(address_to_bind==null){
         address_to_bind="0.0.0.0";
@@ -298,9 +296,9 @@ public class ChannelForwardedTCPIP extends Channel{
     synchronized(pool){
       rport=new int[pool.size()];
       for(int i=0; i<pool.size(); i++){
-        Object[] bar=(Object[])(pool.elementAt(i));
-        if(bar[0]==session) {
-          rport[count++]=((Integer)bar[1]).intValue();
+        Config config = (Config)(pool.elementAt(i));
+        if(config.session == session) {
+          rport[count++]=config.rport; // ((Integer)bar[1]).intValue();
         }
       }
     }
@@ -309,8 +307,25 @@ public class ChannelForwardedTCPIP extends Channel{
     }
   }
 
-  public int getRemotePort(){return rport;}
-  void setSocketFactory(SocketFactory factory){
-    this.factory=factory;
+  public int getRemotePort(){return (config!=null ? config.rport: 0);}
+  private void setSocketFactory(SocketFactory factory){
+    if(config!=null && (config instanceof ConfigLHost) )
+      ((ConfigLHost)config).factory = factory;
+  }
+  static abstract class Config {
+    Session session;
+    int rport;
+    int allocated_rport;
+    String address_to_bind;
+    String target;
+  }
+
+  static class ConfigDaemon extends Config {
+    Object[] arg;
+  }
+
+  static class ConfigLHost extends Config {
+    int lport;
+    SocketFactory factory;
   }
 }
index 70dea2d2ff8bd485ca7fbfca77acdd795d2713c0..8d12869e844bd8ed11a538faec467a724eaf2592 100644 (file)
@@ -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.util.*;
 
-@SuppressWarnings({"rawtypes","unchecked"})
 class ChannelSession extends Channel{
   private static byte[] _session=Util.str2byte("session");
 
@@ -65,9 +64,9 @@ class ChannelSession extends Channel{
 
   /**
    * Enable the X11 forwarding.
+   * Refer to RFC4254 6.3.1. Requesting X11 Forwarding.
    *
    * @param enable
-   * @see RFC4254 6.3.1. Requesting X11 Forwarding
    */
   public void setXForwarding(boolean enable){
     xforwading=enable; 
@@ -87,12 +86,12 @@ class ChannelSession extends Channel{
   /**
    * Set the environment variable. 
    * If <code>name</code> and <code>value</code> 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);
index a278ed61bd977fd5c91fac462403476d58c2d074..d2c0913db01fd9168cc8ef35a9094b036e1aefee 100644 (file)
@@ -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 <code>src</code> file to <code>dst</code> file.
+   * The <code>mode</code> should be <code>OVERWRITE</code>,
+   * <code>RESUME</code> or <code>APPEND</code>.
+   *
+   * @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 <code>src</code> to <code>dst</code> file.
+   * The <code>mode</code> should be <code>OVERWRITE</code>,
+   * <code>RESUME</code> or <code>APPEND</code>.
+   *
+   * @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 <code>dst</code> file.
+   * The <code>mode</code> should be <code>OVERWRITE</code>,
+   * <code>RESUME</code> or <code>APPEND</code>.
+   *
+   * @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; j<rrq.length; j++){
+          if(rrq[j].id == id){
+            find = true;
+            rrq[j].id = 0;
+            break;
+          }
+        }
+        if(find)
+          throw new OutOfOrderException(offset);
+        throw new SftpException(SSH_FX_FAILURE, 
+                                "RequestQueue: unknown request id "+id);
       }
-      rrq[i].id=0;
+      rrq[i].id = 0;
       return rrq[i];
     }
 
@@ -1134,10 +1237,29 @@ public class ChannelSftp extends ChannelSession{
       for(int i=0; i<_count; i++){
         header=header(buf, header);
         int length=header.length;
-        get(header.rid);
+        for(int j=0; j<rrq.length; j++){
+          if(rrq[j].id == header.rid){
+            rrq[j].id=0;
+            break;
+          }
+        }
         skip(length); 
       }
+      init();
     }
+
+    long getOffset(){
+      long result = Long.MAX_VALUE;
+
+      for(int i=0; i<rrq.length; i++){
+        if(rrq[i].id == 0)
+          continue;
+        if(result>rrq[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_data<rr.length){  //
+                 rq.cancel(header, buf);
+                 try {
+                   sendREAD(handle,
+                            rr.offset+length_of_data,
+                            (int)(rr.length-length_of_data), rq);
+                 }
+                 catch(Exception e){ throw new IOException("error"); }
+                 request_offset=rr.offset+rr.length;
+               }
+
+               if(request_max < rq.size()){
+                 request_max++;
+               }
+
                if(monitor!=null){
                  if(!monitor.count(i)){
                    close();
@@ -1334,6 +1500,7 @@ public class ChannelSftp extends ChannelSession{
              if(closed)return;
              closed=true;
              if(monitor!=null)monitor.end();
+             rq.cancel(header, buf);
              try{_sendCLOSE(handle, header);}
              catch(Exception e){throw new IOException("error");}
            }
@@ -1349,6 +1516,28 @@ public class ChannelSftp extends ChannelSession{
    }
 
    public java.util.Vector ls(String path) throws SftpException{
+     final java.util.Vector v = new Vector();
+     LsEntrySelector selector = new LsEntrySelector(){
+       public int select(LsEntry entry){
+         v.addElement(entry);
+         return CONTINUE;
+       }
+     };
+     ls(path, selector);
+     return v;
+   }
+
+  /**
+   * List files specified by the remote <code>path</code>.
+   * Each files and directories will be passed to
+   * <code>LsEntrySelector#select(LsEntry)</code> method, and if that method
+   * returns <code>LsEntrySelector#BREAK</code>, 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 <code>ls</code> 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;
+
+    /**
+     * <p> The <code>select</code> method will be invoked in <code>ls</code>
+     * method for each file entry. If this method returns BREAK,
+     * <code>ls</code> 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);
+  }
 }
index eeb24a39e68d43dedfd98787f7ee69eeab6ba5cb..25fad0481f05afd15c1ebb8a27a84dc31cbb5019 100644 (file)
@@ -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:
index 3f33bf3ee3b5dcac8a47d7339ceab82f26fd8d43..6df855c7022bd7d509ec575c0df2f3d289720043 100644 (file)
@@ -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:
index eb66bb66ae164607b839f2e2a292be8da0f7e454..6a0d248c49eddb9aea5ee9757dc64355be69b074 100644 (file)
@@ -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;
index cc7084e67162e0e7e1b004db8a749cd94ca09e16..1fe1c5404457529fc73cf91a79845c5220b0970c 100644 (file)
@@ -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:
index 61f836ab1e3260f58197fe89196be0887682d2b3..542b6bcd5335c4eeafa73f79a10135ef40e8ebc1 100644 (file)
@@ -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:
index 7ae792206f382fb0c377f34bd8eecacaeb1a31d8..ad80abc1e675d141b731e415ce4bd8cd3fe35837 100644 (file)
@@ -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 (file)
index 0000000..5afa4ea
--- /dev/null
@@ -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; }
+  };
+}
index 963f13c2eab4da707208c4429f2afa0fa27878a5..565d1cfa77b4d7fc04958e731676a5af0a78965d 100644 (file)
@@ -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 (file)
index 0000000..1301688
--- /dev/null
@@ -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 (file)
index 0000000..47cdf5d
--- /dev/null
@@ -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 (file)
index 0000000..0bc070a
--- /dev/null
@@ -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 (file)
index 0000000..f4aa123
--- /dev/null
@@ -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; }
+}
index 655c196c61716dada02f8a0a7a754f0496deb7d4..aa371fedb31dc86bab5eec9ce85064df21e281c9 100644 (file)
@@ -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; ii<sig_of_H.length;ii++){
-  System.err.print(Integer.toHexString(sig_of_H[ii]&0xff));
-  System.err.print(": ");
-}
-System.err.println("");
-      */
 
       dh.setF(f);
-      K=dh.getK();
+
+      dh.checkRange();
+
+      K=normalize(dh.getK());
 
       //The hash H is computed as the HASH hash of the concatenation of the
       //following:
@@ -207,105 +184,13 @@ System.err.println("");
       String alg=Util.byte2str(K_S, i, j);
       i+=j;
 
-      boolean result=false;
-
-      if(alg.equals("ssh-rsa")){
-       byte[] tmp;
-       byte[] ee;
-       byte[] n;
-
-       type=RSA;
-
-       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=new SignatureRSA();
-//     sig.init();
-
-       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;
-      
-       type=DSS;
-
-       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=new SignatureDSA();
-//     sig.init();
-       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);
-        }
+      boolean result = verify(alg, K_S, i, sig_of_H);
 
-      }
-      else{
-       System.err.println("unknown alg");
-      }            
       state=STATE_END;
       return result;
     }
     return false;
   }
 
-  public String getKeyType(){
-    if(type==DSS) return "DSA";
-    return "RSA";
-  }
-
   public int getState(){return state; }
 }
index e46fb6fddee9ca77c00006cbaf13a77f256d8425..4ea2aea4ea0401ff10d38b5014268ac0dfb07fb7 100644 (file)
@@ -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 DHG14 extends KeyExchange{
 
   static final byte[] g={ 2 };
@@ -72,10 +71,6 @@ public class DHG14 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;
@@ -167,18 +162,15 @@ public class DHG14 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();
 
       dh.setF(f);
-      K=dh.getK();
+
+      dh.checkRange();
+
+      K=normalize(dh.getK());
 
       //The hash H is computed as the HASH hash of the concatenation of the
       //following:
@@ -211,101 +203,13 @@ public class DHG14 extends KeyExchange{
       String alg=Util.byte2str(K_S, i, j);
       i+=j;
 
-      boolean result=false;
-
-      if(alg.equals("ssh-rsa")){
-       byte[] tmp;
-       byte[] ee;
-       byte[] n;
-
-       type=RSA;
-
-       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);
-        }
+      boolean result = verify(alg, K_S, i, sig_of_H);
 
-      }
-      else if(alg.equals("ssh-dss")){
-       byte[] q=null;
-       byte[] tmp;
-       byte[] p;
-       byte[] g;
-      
-       type=DSS;
-
-       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{
-       System.err.println("unknown alg");
-      }            
       state=STATE_END;
       return result;
     }
     return false;
   }
 
-  public String getKeyType(){
-    if(type==DSS) return "DSA";
-    return "RSA";
-  }
-
   public int getState(){return state; }
 }
index 0f0da10424fafa85ceaafcae85c71997c13643d9..8a9a17c8ac9514b0d83456cc257fbd1c326c0a69 100644 (file)
@@ -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 DHGEX extends KeyExchange{
 
   private static final int SSH_MSG_KEX_DH_GEX_GROUP=               31;
@@ -38,21 +37,11 @@ public class DHGEX extends KeyExchange{
   private static final int SSH_MSG_KEX_DH_GEX_REQUEST=             34;
 
   static int min=1024;
-
-//  static int min=512;
   static int preferred=1024;
-  static int max=1024;
-
-//  static int preferred=1024;
-//  static int max=2000;
-
-  static final int RSA=0;
-  static final int DSS=1;
-  private int type=0;
+  int max=1024;
 
   private int state;
 
-//  com.jcraft.jsch.DH dh;
   DH dh;
 
   byte[] V_S;
@@ -66,7 +55,8 @@ public class DHGEX extends KeyExchange{
   private byte[] p;
   private byte[] g;
   private byte[] e;
-  //private byte[] f;
+
+  protected String hash="sha-1";
 
   public void init(Session session,
                   byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{
@@ -77,7 +67,7 @@ public class DHGEX extends KeyExchange{
     this.I_C=I_C;      
 
     try{
-      Class c=Class.forName(session.getConfig("sha-1"));
+      Class c=Class.forName(session.getConfig(hash));
       sha=(HASH)(c.newInstance());
       sha.init();
     }
@@ -90,11 +80,13 @@ public class DHGEX extends KeyExchange{
 
     try{
       Class c=Class.forName(session.getConfig("dh"));
+      // Since JDK8, SunJCE has lifted the keysize restrictions
+      // from 1024 to 2048 for DH.
+      preferred = max = check2048(c, max); 
       dh=(com.jcraft.jsch.DH)(c.newInstance());
       dh.init();
     }
     catch(Exception e){
-//      System.err.println(e);
       throw e;
     }
 
@@ -132,18 +124,9 @@ public class DHGEX extends KeyExchange{
 
       p=_buf.getMPInt();
       g=_buf.getMPInt();
-      /*
-for(int iii=0; iii<p.length; iii++){
-System.err.println("0x"+Integer.toHexString(p[iii]&0xff)+",");
-}
-System.err.println("");
-for(int iii=0; iii<g.length; iii++){
-System.err.println("0x"+Integer.toHexString(g[iii]&0xff)+",");
-}
-      */
+
       dh.setP(p);
       dh.setG(g);
-
       // The client responds with:
       // byte  SSH_MSG_KEX_DH_GEX_INIT(32)
       // mpint e <- g^x mod p
@@ -182,19 +165,15 @@ System.err.println("0x"+Integer.toHexString(g[iii]&0xff)+",");
       }
 
       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();
 
       dh.setF(f);
-      K=dh.getK();
+
+      dh.checkRange();
+
+      K=normalize(dh.getK());
 
       //The hash H is computed as the HASH hash of the concatenation of the
       //following:
@@ -237,105 +216,30 @@ System.err.println("0x"+Integer.toHexString(g[iii]&0xff)+",");
       String alg=Util.byte2str(K_S, i, j);
       i+=j;
 
-      boolean result=false;
-      if(alg.equals("ssh-rsa")){
-       byte[] tmp;
-       byte[] ee;
-       byte[] n;
-       
-       type=RSA;
-
-       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=new SignatureRSA();
-//     sig.init();
-
-       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;
-
-       type=DSS;
-
-       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=new SignatureDSA();
-//     sig.init();
-
-       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);
-        }
+      boolean result = verify(alg, K_S, i, sig_of_H);
 
-      }
-      else{
-       System.err.println("unknown alg");
-      }            
       state=STATE_END;
       return result;
     }
     return false;
   }
 
-  public String getKeyType(){
-    if(type==DSS) return "DSA";
-    return "RSA";
-  }
-
   public int getState(){return state; }
+
+  protected int check2048(Class c, int _max) throws Exception {
+    DH dh=(com.jcraft.jsch.DH)(c.newInstance());
+    dh.init();
+    byte[] foo = new byte[257];
+    foo[1]=(byte)0xdd;
+    foo[256]=0x73;
+    dh.setP(foo);
+    byte[] bar = {(byte)0x02};
+    dh.setG(bar);
+    try {
+      dh.getE();
+      _max=2048;
+    }
+    catch(Exception e){ }
+    return _max;
+  }
 }
diff --git a/java/com/jcraft/jsch/DHGEX256.java b/java/com/jcraft/jsch/DHGEX256.java
new file mode 100644 (file)
index 0000000..ecd4176
--- /dev/null
@@ -0,0 +1,36 @@
+/* -*-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;
+
+public class DHGEX256 extends DHGEX {
+  DHGEX256(){
+    hash="sha-256";
+  }
+}
diff --git a/java/com/jcraft/jsch/ECDH.java b/java/com/jcraft/jsch/ECDH.java
new file mode 100644 (file)
index 0000000..d7085db
--- /dev/null
@@ -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 ECDH {
+  void init(int size) throws Exception;
+  byte[] getSecret(byte[] r, byte[] s) throws Exception;
+  byte[] getQ() throws Exception;
+  boolean validate(byte[] r, byte[] s) throws Exception;
+}
index 4176aef4f77d2aec5d83417c9083ff6c3b53fdab..1fc829f7a525f01b8d236dc564b6b7a1f53b5b55 100644 (file)
@@ -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:
index 23c58ee3e22030024e3e517cb5981189a0672bb8..cacb9a985e9f787ad2c19e8b1c7213cdc9bb2bdb 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2004-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2004-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:
index 6bfff8868162229fb3b50ac73f780a9fcf51ffbd..250b6816c88630337cb506c34ba54cf9e2a4af32 100644 (file)
@@ -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:
index 6ed420ad1f09d9f577f0992215d52d3c8cb8a4e4..6269469a3b9a4ae4bbac81573780b1cc3140747d 100644 (file)
@@ -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,43 +29,77 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 package com.jcraft.jsch;
 
-@SuppressWarnings({"rawtypes","static"})
 public class HostKey{
-  private static final byte[] sshdss=Util.str2byte("ssh-dss");
-  private static final byte[] sshrsa=Util.str2byte("ssh-rsa");
+
+  private static final byte[][] names = {
+    Util.str2byte("ssh-dss"),
+    Util.str2byte("ssh-rsa"),
+    Util.str2byte("ecdsa-sha2-nistp256"),
+    Util.str2byte("ecdsa-sha2-nistp384"),
+    Util.str2byte("ecdsa-sha2-nistp521")
+  };
 
   protected static final int GUESS=0;
   public static final int SSHDSS=1;
   public static final int SSHRSA=2;
-  static final int UNKNOWN=3;
+  public static final int ECDSA256=3;
+  public static final int ECDSA384=4;
+  public static final int ECDSA521=5;
+  static final int UNKNOWN=6;
 
+  protected String marker;
   protected String host;
   protected int type;
   protected byte[] key;
+  protected String comment;
 
   public HostKey(String host, byte[] key) throws JSchException {
     this(host, GUESS, key);
   }
 
   public HostKey(String host, int type, byte[] key) throws JSchException {
+    this(host, type, key, null);
+  }
+  public HostKey(String host, int type, byte[] key, String comment) throws JSchException {
+    this("", host, type, key, comment);
+  }
+  public HostKey(String marker, String host, int type, byte[] key, String comment) throws JSchException {
+    this.marker=marker;
     this.host=host; 
     if(type==GUESS){
       if(key[8]=='d'){ this.type=SSHDSS; }
       else if(key[8]=='r'){ this.type=SSHRSA; }
+      else if(key[8]=='a' && key[20]=='2'){ this.type=ECDSA256; }
+      else if(key[8]=='a' && key[20]=='3'){ this.type=ECDSA384; }
+      else if(key[8]=='a' && key[20]=='5'){ this.type=ECDSA521; }
       else { throw new JSchException("invalid key type");}
     }
     else{
       this.type=type; 
     }
     this.key=key;
+    this.comment=comment;
   }
 
   public String getHost(){ return host; }
   public String getType(){
-    if(type==SSHDSS){ return Util.byte2str(sshdss); }
-    if(type==SSHRSA){ return Util.byte2str(sshrsa);}
+    if(type==SSHDSS ||
+       type==SSHRSA ||
+       type==ECDSA256 ||
+       type==ECDSA384 ||
+       type==ECDSA521){
+      return Util.byte2str(names[type-1]);
+    }
     return "UNKNOWN";
   }
+  protected static int name2type(String name){
+    for(int i = 0; i < names.length; i++){
+      if(Util.byte2str(names[i]).equals(name)){
+        return i + 1;
+      }
+    }
+    return UNKNOWN;
+  }
   public String getKey(){
     return Util.byte2str(Util.toBase64(key, 0, key.length));
   }
@@ -78,6 +112,8 @@ public class HostKey{
     catch(Exception e){ System.err.println("getFingerPrint: "+e); }
     return Util.getFingerPrint(hash, key);
   }
+  public String getComment(){ return comment; }
+  public String getMarker(){ return marker; }
 
   boolean isMatched(String _host){
     return isIncluded(_host);
index adfe633c9fa34e8110b8922bd1b7b248a731107d..c3cea124ec2c383d13f84cdb1ef978616a0f9b7b 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2004-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2004-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:
@@ -34,11 +34,61 @@ public interface HostKeyRepository{
   final int NOT_INCLUDED=1;
   final int CHANGED=2;
 
+  /**
+   * Checks if <code>host</code> is included with the <code>key</code>. 
+   * 
+   * @return #NOT_INCLUDED, #OK or #CHANGED
+   * @see #NOT_INCLUDED
+   * @see #OK
+   * @see #CHANGED
+   */
   int check(String host, byte[] key);
+
+  /**
+   * Adds a host key <code>hostkey</code>
+   *
+   * @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
+   * <code>host</code>, <code>type</code>.
+   *
+   * @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
+   * <code>host</code>, <code>type</code> and <code>key</code>.
+   */
   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 <code>null</code> 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 <code>null</code> is given, a key type type will not be ignored.
+   */
   HostKey[] getHostKey(String host, String type);
 }
index 65535ba32bd60cbf572bdcd2ddcf35b285061873..866d4c36838f913dd9a822328237f7e64eb48fcf 100644 (file)
@@ -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:
index 2f8cb80e08247fd929d073e60747668091560eb7..331ae7e9b8701b327a95a70a00799fdb9a5e71c8 100644 (file)
@@ -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 <tt>true</tt> 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 <tt>true</tt> if this identity is cyphered.
+   * @return <tt>true</tt> if this identity is cyphered.
+   */
   public boolean isEncrypted();
+
+  /**
+   * Disposes internally allocated data, like byte array for the private key.
+   */
   public void clear();
 }
index cc66dfe2b97b3876b85cd4b608e3a03083673f3e..4ffdaa7a1a4f44dfdf98717203ba48be17f45f43 100644 (file)
@@ -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(i<len){
-        if(buf[i] == '-' && i+4<len && 
-           buf[i+1] == '-' && buf[i+2] == '-' && 
-           buf[i+3] == '-' && buf[i+4] == '-'){
-          break;
-        }
-        i++;
-      }
-
-      while(i<len){
-        if(buf[i]=='B'&& i+3<len && buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I'){
-          i+=6;            
-          if(buf[i]=='D'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=DSS; }
-         else if(buf[i]=='R'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=RSA; }
-         else if(buf[i]=='S'&& buf[i+1]=='S'&& buf[i+2]=='H'){ // FSecure
-           type=UNKNOWN;
-           keytype=FSECURE;
-         }
-         else{
-            //System.err.println("invalid format: "+identity);
-           throw new JSchException("invalid privatekey: "+identity);
-         }
-          i+=3;
-         continue;
-       }
-        if(buf[i]=='A'&& i+7<len && buf[i+1]=='E'&& buf[i+2]=='S'&& buf[i+3]=='-' && 
-           buf[i+4]=='2'&& buf[i+5]=='5'&& buf[i+6]=='6'&& buf[i+7]=='-'){
-          i+=8;
-          if(Session.checkCipher((String)jsch.getConfig("aes256-cbc"))){
-            c=Class.forName((String)jsch.getConfig("aes256-cbc"));
-            cipher=(Cipher)(c.newInstance());
-            key=new byte[cipher.getBlockSize()];
-            iv=new byte[cipher.getIVSize()];
-          }
-          else{
-            throw new JSchException("privatekey: aes256-cbc is not available "+identity);
-          }
-          continue;
-        }
-        if(buf[i]=='A'&& i+7<len && buf[i+1]=='E'&& buf[i+2]=='S'&& buf[i+3]=='-' && 
-           buf[i+4]=='1'&& buf[i+5]=='9'&& buf[i+6]=='2'&& buf[i+7]=='-'){
-          i+=8;
-          if(Session.checkCipher((String)jsch.getConfig("aes192-cbc"))){
-            c=Class.forName((String)jsch.getConfig("aes192-cbc"));
-            cipher=(Cipher)(c.newInstance());
-            key=new byte[cipher.getBlockSize()];
-            iv=new byte[cipher.getIVSize()];
-          }
-          else{
-            throw new JSchException("privatekey: aes192-cbc is not available "+identity);
-          }
-          continue;
-        }
-        if(buf[i]=='A'&& i+7<len && buf[i+1]=='E'&& buf[i+2]=='S'&& buf[i+3]=='-' && 
-           buf[i+4]=='1'&& buf[i+5]=='2'&& buf[i+6]=='8'&& buf[i+7]=='-'){
-          i+=8;
-          if(Session.checkCipher((String)jsch.getConfig("aes128-cbc"))){
-            c=Class.forName((String)jsch.getConfig("aes128-cbc"));
-            cipher=(Cipher)(c.newInstance());
-            key=new byte[cipher.getBlockSize()];
-            iv=new byte[cipher.getIVSize()];
-          }
-          else{
-            throw new JSchException("privatekey: aes128-cbc is not available "+identity);
-          }
-          continue;
-        }
-        if(buf[i]=='C'&& i+3<len && buf[i+1]=='B'&& buf[i+2]=='C'&& buf[i+3]==','){
-          i+=4;
-         for(int ii=0; ii<iv.length; ii++){
-            iv[ii]=(byte)(((a2b(buf[i++])<<4)&0xf0)+
-                         (a2b(buf[i++])&0xf));
-         }
-         continue;
-       }
-       if(buf[i]==0x0d && i+1<len && buf[i+1]==0x0a){
-         i++;
-         continue;
-       }
-       if(buf[i]==0x0a && i+1<len){
-         if(buf[i+1]==0x0a){ i+=2; break; }
-         if(buf[i+1]==0x0d &&
-            i+2<len && buf[i+2]==0x0a){
-            i+=3; break;
-         }
-         boolean inheader=false;
-         for(int j=i+1; j<len; j++){
-           if(buf[j]==0x0a) break;
-           //if(buf[j]==0x0d) break;
-           if(buf[j]==':'){inheader=true; break;}
-         }
-         if(!inheader){
-           i++; 
-           encrypted=false;    // no passphrase
-           break;
-         }
-       }
-       i++;
-      }
-
-      if(type==ERROR){
-       throw new JSchException("invalid privatekey: "+identity);
-      }
-
-      int start=i;
-      while(i<len){
-        if(buf[i]==0x0a){
-         boolean xd=(buf[i-1]==0x0d);
-          System.arraycopy(buf, i+1, 
-                          buf, 
-                          i-(xd ? 1 : 0), 
-                          len-i-1-(xd ? 1 : 0)
-                          );
-         if(xd)len--;
-          len--;
-          continue;
-        }
-        if(buf[i]=='-'){  break; }
-        i++;
-      }
-      encoded_data=Util.fromBase64(buf, start, i-start);
-
-      if(encoded_data.length>4 &&            // 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(i<len){
-         if(buf[i]==0x0a){
-           boolean inheader=false;
-           for(int j=i+1; j<len; j++){
-             if(buf[j]==0x0a) break;
-             if(buf[j]==':'){inheader=true; break;}
-           }
-           if(!inheader){
-             i++; 
-             break;
-           }
-         }
-         i++;
-       }
-       if(len<=i) return;
-
-       start=i;
-       while(i<len){
-         if(buf[i]==0x0a){
-           System.arraycopy(buf, i+1, buf, i, len-i-1);
-           len--;
-           continue;
-         }
-         if(buf[i]=='-'){  break; }
-         i++;
-       }
-       publickeyblob=Util.fromBase64(buf, start, i-start);
-
-       if(type==UNKNOWN && publickeyblob.length>8){
-         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){ if(buf[i]==' ')break; i++;} i++;
-       if(i>=len) return;
-       start=i;
-       while(i<len){ if(buf[i]==' ' || buf[i]=='\n')break; i++;}
-       publickeyblob=Util.fromBase64(buf, start, i-start);
-        if(publickeyblob.length<4+7){  // It must start with "ssh-XXX".
-          if(JSch.getLogger().isEnabled(Logger.WARN)){
-            JSch.getLogger().log(Logger.WARN, 
-                                 "failed to parse the public key");
-          }
-          publickeyblob=null;
-        }
-      }
-    }
-    catch(Exception e){
-      //System.err.println("IdentityFile: "+e);
-      if(e instanceof JSchException) throw (JSchException)e;
-      if(e instanceof Throwable)
-        throw new JSchException(e.toString(), (Throwable)e);
-      throw new JSchException(e.toString());
-    }
+    KeyPair kpair = KeyPair.load(jsch, prvkey, pubkey);
+    return new IdentityFile(jsch, name, kpair);
   }
 
-  public String getAlgName(){
-    if(type==RSA) return "ssh-rsa";
-    return "ssh-dss"; 
+  private IdentityFile(JSch jsch, String name, KeyPair kpair) throws JSchException{
+    this.jsch = jsch;
+    this.identity = name;
+    this.kpair = kpair;
   }
 
-  public boolean setPassphrase(byte[] _passphrase) throws JSchException{
-    /*
-      hash is MD5
-      h(0) <- hash(passphrase, iv);
-      h(n) <- hash(h(n-1), passphrase, iv);
-      key <- (h(0),...,h(n))[0,..,key.length];
-    */
-    try{
-      if(encrypted){
-       if(_passphrase==null) return false;
-       byte[] passphrase=_passphrase;
-       int hsize=hash.getBlockSize();
-       byte[] hn=new byte[key.length/hsize*hsize+
-                          (key.length%hsize==0?0:hsize)];
-       byte[] tmp=null;
-       if(keytype==OPENSSH){
-         for(int index=0; index+hsize<=hn.length;){
-           if(tmp!=null){ hash.update(tmp, 0, tmp.length); }
-           hash.update(passphrase, 0, passphrase.length);
-           hash.update(iv, 0, iv.length > 8 ? 8: iv.length);
-           tmp=hash.digest();
-           System.arraycopy(tmp, 0, hn, index, tmp.length);
-           index+=tmp.length;
-         }
-         System.arraycopy(hn, 0, key, 0, key.length); 
-       }
-       else if(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 <tt>true</tt> 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;  i<foo.length; i++){
-      System.err.print(Integer.toHexString(foo[i]&0xff)+":");
-    }
-    System.err.println("");
-    System.err.print("Q ");
-    foo=Q_array;
-    for(i=0;  i<foo.length; i++){
-      System.err.print(Integer.toHexString(foo[i]&0xff)+":");
-    }
-    System.err.println("");
-    System.err.print("G ");
-    foo=G_array;
-    for(i=0;  i<foo.length; i++){
-      System.err.print(Integer.toHexString(foo[i]&0xff)+":");
-    }
-    System.err.println("");
-*/
-
-    try{      
-      Class c=Class.forName((String)jsch.getConfig("signature.dss"));
-      SignatureDSA dsa=(SignatureDSA)(c.newInstance());
-      dsa.init();
-      dsa.setPrvKey(prv_array, P_array, Q_array, G_array);
-
-      dsa.update(data);
-      byte[] sig = dsa.sign();
-      Buffer buf=new Buffer("ssh-dss".length()+4+
-                           sig.length+4);
-      buf.putString(Util.str2byte("ssh-dss"));
-      buf.putString(sig);
-      return buf.buffer;
-    }
-    catch(Exception e){
-      //System.err.println("e "+e);
-    }
-    return null;
+    return kpair.getSignature(data);
   }
 
+  /**
+   * @deprecated This method should not be invoked.
+   * @see #setPassphrase(byte[] passphrase)
+   */
   public boolean decrypt(){
-    if(type==RSA) return decrypt_rsa();
-    return decrypt_dss();
-  }
-
-  boolean decrypt_rsa(){
-    byte[] p_array;
-    byte[] q_array;
-    byte[] dmp1_array;
-    byte[] dmq1_array;
-    byte[] iqmp_array;
-
-    try{
-      byte[] plain;
-      if(encrypted){
-       if(keytype==OPENSSH){
-         cipher.init(Cipher.DECRYPT_MODE, key, iv);
-         plain=new byte[encoded_data.length];
-         cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
-       }
-       else if(keytype==FSECURE){
-         for(int i=0; i<iv.length; i++)iv[i]=0;
-         cipher.init(Cipher.DECRYPT_MODE, key, iv);
-         plain=new byte[encoded_data.length];
-         cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
-       }
-       else{
-         return false;
-       }
-      }
-      else{
-       if(n_array!=null) return true;
-       plain=encoded_data;
-      }
-
-      if(keytype==FSECURE){              // FSecure   
-       Buffer buf=new Buffer(plain);
-        int foo=buf.getInt();
-        if(plain.length!=foo+4){
-          return false;
-        }
-       e_array=buf.getMPIntBits();
-        d_array=buf.getMPIntBits();
-       n_array=buf.getMPIntBits();
-       byte[] u_array=buf.getMPIntBits();
-       p_array=buf.getMPIntBits();
-       q_array=buf.getMPIntBits();
-        return true;
-      }
-
-      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;
-
-//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; i<n_array.length; i++){
-System.err.print(Integer.toHexString(n_array[i]&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); }
-      }
-      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; i<e_array.length; i++){
-System.err.print(Integer.toHexString(e_array[i]&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); }
-      }
-      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; i<d_array.length; i++){
-System.err.print(Integer.toHexString(d_array[i]&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); }
-      }
-      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; i<p_array.length; i++){
-System.err.print(Integer.toHexString(p_array[i]&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); }
-      }
-      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; i<q_array.length; i++){
-System.err.print(Integer.toHexString(q_array[i]&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); }
-      }
-      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; i<dmp1_array.length; i++){
-System.err.print(Integer.toHexString(dmp1_array[i]&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); }
-      }
-      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; i<dmq1_array.length; i++){
-System.err.print(Integer.toHexString(dmq1_array[i]&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); }
-      }
-      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; i<iqmp_array.length; i++){
-System.err.print(Integer.toHexString(iqmp_array[i]&0xff)+":");
-}
-System.err.println("");
-*/
-    }
-    catch(Exception e){
-      //System.err.println(e);
-      return false;
-    }
-    return true;
-  }
-
-  boolean decrypt_dss(){
-    try{
-      byte[] plain;
-      if(encrypted){
-       if(keytype==OPENSSH){
-         cipher.init(Cipher.DECRYPT_MODE, key, iv);
-         plain=new byte[encoded_data.length];
-         cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
-/*
-for(int i=0; i<plain.length; i++){
-System.err.print(Integer.toHexString(plain[i]&0xff)+":");
-}
-System.err.println("");
-*/
-       }
-       else if(keytype==FSECURE){
-         for(int i=0; i<iv.length; i++)iv[i]=0;
-         cipher.init(Cipher.DECRYPT_MODE, key, iv);
-         plain=new byte[encoded_data.length];
-         cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
-       }
-       else{
-         return false;
-       }
-      }
-      else{
-       if(P_array!=null) return true;
-       plain=encoded_data;
-      }
-
-      if(keytype==FSECURE){              // FSecure   
-       Buffer buf=new Buffer(plain);
-        int foo=buf.getInt();
-        if(plain.length!=foo+4){
-          return false;
-        }
-       P_array=buf.getMPIntBits();
-        G_array=buf.getMPIntBits();
-       Q_array=buf.getMPIntBits();
-       pub_array=buf.getMPIntBits();
-       prv_array=buf.getMPIntBits();
-        return true;
-      }
-
-      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++;
-      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 <tt>true</tt> if this identity is cyphered.
+   * @return <tt>true</tt> 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;
   }
 }
index c6b60d1cf1d86315e557c480704de0bcf5942b22..018f3fa2b549badc61ae1b686ef159b0514afb0a 100644 (file)
@@ -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);
+        }
+      }
+    }
+  }
 }
index 47fa29ae703eee348e37e85e41216bafbfe0332b..b6bc84b7323041fbbcde7d2259668992776e7eea 100644 (file)
@@ -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 <code>identityRepository</code>, which will be referred
+   * in the public key authentication.
+   *
+   * @param identityRepository if <code>null</code> 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 <code>Session</code> object with
+   * <code>host</code>.  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 <code>username</code> or <code>host</code> are invalid.
+   *
+   * @return the instance of <code>Session</code> 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 <code>Session</code> object with
+   * <code>username</code> and <code>host</code>.
+   * 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 <code>username</code> or <code>host</code> are invalid.
+   *
+   * @return the instance of <code>Session</code> 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 <code>Session</code> object with given
+   * <code>username</code>, <code>host</code> and <code>port</code>.
+   * 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 <code>username</code> or <code>host</code> are invalid.
+   *
+   * @return the instance of <code>Session</code> 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 <code>KnownHosts</code>, which refers
+   * to <code>filename</code>.
+   *
+   * @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 <code>KnownHosts</code> generated with
+   * <code>stream</code>.
+   *
+   * @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 <code>KnownHosts</code>.
+   *
+   * @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 <code>prvkey</code> 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 <code>passphrase</code>.
+   *
+   * @param prvkey filename of the private key.
+   * @param passphrase passphrase for <code>prvkey</code>.
+   *
+   * @throws JSchException if <code>passphrase</code> 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 <code>passphrase</code>.
+   *
+   * @param prvkey filename of the private key.
+   * @param passphrase passphrase for <code>prvkey</code>.
+   *
+   * @throws JSchException if <code>passphrase</code> 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 <code>passphrase</code>.
+   *
+   * @param prvkey filename of the private key.
+   * @param pubkey filename of the public key.
+   * @param passphrase passphrase for <code>prvkey</code>.
+   *
+   * @throws JSchException if <code>passphrase</code> 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 <code>passphrase</code>.
+   *
+   * @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 <code>prvkey</code>.
+   *
+   */
   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 <code>passphrase</code>.
+   *
+   * @param identity private key.
+   * @param passphrase passphrase for <code>identity</code>.
+   *
+   * @throws JSchException if <code>passphrase</code> 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 <code>identity</code> 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;
   }
index 65e71f19ffc867199a111672c3f61c5b1cb9680f..4e7eb8f4127a9249670a62e56deb643f52d4569f 100644 (file)
@@ -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:
index 1e9056ce0c38e156532b23b9a3abb9d151605d42..666d3a41efd13c6a3f051f029358588150b7fc83 100644 (file)
@@ -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:
index aa7ac9e4243ba691bbf589e52d9c81a5303acbc3..9398606971614702679ba3e981e84495f5044669 100644 (file)
@@ -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:
index 77e7b83ba95c5867e6e8f52f5d135dff5402dd99..c74c22f4751e1d0cec1fdd652bf9b40456ff219f 100644 (file)
@@ -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<foo.length; i++){
-      if((foo[i]&0xf0)==0)System.err.print("0");
-      System.err.print(Integer.toHexString(foo[i]&0xff));
-      if(i%16==15){System.err.println(""); continue;}
-      if(i%2==1)System.err.print(" ");
-    }
-  } 
-  */
+  protected final int RSA=0;
+  protected final int DSS=1;
+  protected final int ECDSA=2;
+  private int type=0;
+  private String key_alg_name = "";
+
+  public String getKeyType() {
+    if(type==DSS) return "DSA";
+    if(type==RSA) return "RSA";
+    return "ECDSA";
+  }
+
+  public String getKeyAlgorithName() {
+    return key_alg_name;
+  }
 
   protected static String[] guess(byte[]I_S, byte[]I_C){
     String[] guess=new String[PROPOSAL_MAX];
     Buffer sb=new Buffer(I_S); sb.setOffSet(17);
     Buffer cb=new Buffer(I_C); cb.setOffSet(17);
 
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      for(int i=0; i<PROPOSAL_MAX; i++){
+        JSch.getLogger().log(Logger.INFO,
+                             "kex: server: "+Util.byte2str(sb.getString()));
+      }
+      for(int i=0; i<PROPOSAL_MAX; i++){
+        JSch.getLogger().log(Logger.INFO,
+                             "kex: client: "+Util.byte2str(cb.getString()));
+      }
+      sb.setOffSet(17);
+      cb.setOffSet(17);
+    }
+
     for(int i=0; i<PROPOSAL_MAX; i++){
       byte[] sp=sb.getString();  // server proposal
       byte[] cp=cb.getString();  // client proposal
@@ -137,10 +154,6 @@ public abstract class KeyExchange{
                            " "+guess[PROPOSAL_COMP_ALGS_CTOS]);
     }
 
-//    for(int i=0; i<PROPOSAL_MAX; i++){
-//      System.err.println("guess: ["+guess[i]+"]");
-//    }
-
     return guess;
   }
 
@@ -157,4 +170,156 @@ public abstract class KeyExchange{
   byte[] getH(){ return H; }
   HASH getHash(){ return sha; }
   byte[] getHostKey(){ return K_S; }
+
+  /*
+   * It seems JCE included in Oracle's Java7u6(and later) has suddenly changed
+   * its behavior.  The secrete generated by KeyAgreement#generateSecret()
+   * may start with 0, even if it is a positive value.
+   */
+  protected byte[] normalize(byte[] secret) {
+    if(secret.length > 1 &&
+       secret[0] == 0 && (secret[1]&0x80) == 0) {
+      byte[] tmp=new byte[secret.length-1];
+      System.arraycopy(secret, 1, tmp, 0, tmp.length);
+      return normalize(tmp);
+    }
+    else {
+      return secret;
+    }
+  }
+
+  protected boolean verify(String alg, byte[] K_S, int index,
+                           byte[] sig_of_H) throws Exception {
+    int i,j;
+
+    i=index;
+    boolean result=false;
+
+    if(alg.equals("ssh-rsa")){
+      byte[] tmp;
+      byte[] ee;
+      byte[] n;
+
+      type=RSA;
+      key_alg_name=alg;
+      
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+        ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+      ee=tmp;
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+        ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+      n=tmp;
+       
+      SignatureRSA sig=null;
+      try{
+        Class c=Class.forName(session.getConfig("signature.rsa"));
+        sig=(SignatureRSA)(c.newInstance());
+        sig.init();
+      }
+      catch(Exception e){
+        System.err.println(e);
+      }
+      sig.setPubKey(ee, n);   
+      sig.update(H);
+      result=sig.verify(sig_of_H);
+
+      if(JSch.getLogger().isEnabled(Logger.INFO)){
+        JSch.getLogger().log(Logger.INFO, 
+                             "ssh_rsa_verify: signature "+result);
+      }
+    }
+    else if(alg.equals("ssh-dss")){
+      byte[] q=null;
+      byte[] tmp;
+      byte[] p;
+      byte[] g;
+      byte[] f;
+      
+      type=DSS;
+      key_alg_name=alg;
+
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+      p=tmp;
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+        ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+      q=tmp;
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+      g=tmp;
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+        ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+      f=tmp;
+
+      SignatureDSA sig=null;
+      try{
+        Class c=Class.forName(session.getConfig("signature.dss"));
+        sig=(SignatureDSA)(c.newInstance());
+        sig.init();
+      }
+      catch(Exception e){
+        System.err.println(e);
+      }
+      sig.setPubKey(f, p, q, g);   
+      sig.update(H);
+      result=sig.verify(sig_of_H);
+
+      if(JSch.getLogger().isEnabled(Logger.INFO)){
+        JSch.getLogger().log(Logger.INFO, 
+                             "ssh_dss_verify: signature "+result);
+      }
+    }
+    else if(alg.equals("ecdsa-sha2-nistp256") ||
+            alg.equals("ecdsa-sha2-nistp384") ||
+            alg.equals("ecdsa-sha2-nistp521")) {
+      byte[] tmp;
+      byte[] r;
+      byte[] s;
+
+      // RFC 5656, 
+      type=ECDSA;
+      key_alg_name=alg;
+
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+        ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+        ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      i++;
+      tmp=new byte[(j-1)/2];
+      System.arraycopy(K_S, i, tmp, 0, tmp.length); i+=(j-1)/2;
+      r=tmp;
+      tmp=new byte[(j-1)/2];
+      System.arraycopy(K_S, i, tmp, 0, tmp.length); i+=(j-1)/2;
+      s=tmp;
+
+      SignatureECDSA sig=null;
+      try{
+        Class c=Class.forName(session.getConfig("signature.ecdsa"));
+        sig=(SignatureECDSA)(c.newInstance());
+        sig.init();
+      }
+      catch(Exception e){
+        System.err.println(e);
+      }
+
+      sig.setPubKey(r, s);
+
+      sig.update(H);
+
+      result=sig.verify(sig_of_H);
+    }
+    else{
+      System.err.println("unknown alg");
+    }      
+
+    return result;
+  }
+
 }
index b3f681cbc309e43e38ca6484c9e289c890c59df4..7c31f15bddaef5445e4151338470b78db5f187df 100644 (file)
@@ -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; i<iv.length; i++)iv[i]=0;
-    }
-    */
+
     try{
       byte[] key=genKey(passphrase, iv);
       cipher.init(Cipher.DECRYPT_MODE, key, iv);
@@ -262,6 +341,22 @@ public abstract class KeyPair{
     return index;
   }
 
+  int writeOCTETSTRING(byte[] buf, int index, byte[] data){
+    buf[index++]=0x04;
+    index=writeLength(buf, index, data.length);
+    System.arraycopy(data, 0, buf, index, data.length);
+    index+=data.length;
+    return index;
+  }
+
+ int writeDATA(byte[] buf, byte n, int index, byte[] data){
+    buf[index++]=n;
+    index=writeLength(buf, index, data.length);
+    System.arraycopy(data, 0, buf, index, data.length);
+    index+=data.length;
+    return index;
+  }
+
   int countLength(int len){
     int i=1;
     if(len<=0x7f) return i;
@@ -357,6 +452,19 @@ public abstract class KeyPair{
        }
        System.arraycopy(hn, 0, key, 0, key.length); 
       }
+      else if(vendor==VENDOR_PUTTY){
+        Class c=Class.forName((String)jsch.getConfig("sha-1"));
+        HASH sha1=(HASH)(c.newInstance());
+        tmp = new byte[4];
+        key = new byte[20*2];
+        for(int i = 0; i < 2; i++){
+          sha1.init();
+          tmp[3]=(byte)i;
+          sha1.update(tmp, 0, tmp.length);
+          sha1.update(passphrase, 0, passphrase.length);
+          System.arraycopy(sha1.digest(), 0, key, i*20, 20);
+        }
+      }
     }
     catch(Exception e){
       System.err.println(e);
@@ -364,6 +472,9 @@ public abstract class KeyPair{
     return key;
   } 
 
+  /**
+   * @deprecated use #writePrivateKey(java.io.OutputStream out, byte[] passphrase)
+   */
   public void setPassphrase(String passphrase){
     if(passphrase==null || passphrase.length()==0){
       setPassphrase((byte[])null);
@@ -372,14 +483,18 @@ public abstract class KeyPair{
       setPassphrase(Util.str2byte(passphrase));
     }
   }
+
+  /**
+   * @deprecated use #writePrivateKey(String name, byte[] passphrase)
+   */
   public void setPassphrase(byte[] passphrase){
     if(passphrase!=null && passphrase.length==0) 
       passphrase=null;
     this.passphrase=passphrase;
   }
 
-  private boolean encrypted=false;
-  private byte[] data=null;
+  protected boolean encrypted=false;
+  protected byte[] data=null;
   private byte[] iv=null;
   private byte[] publickeyblob=null;
 
@@ -391,6 +506,7 @@ public abstract class KeyPair{
     return decrypt(Util.str2byte(_passphrase));
   }
   public boolean decrypt(byte[] _passphrase){
+
     if(!encrypted){
       return true;
     }
@@ -415,7 +531,41 @@ public abstract class KeyPair{
     }
     return load(jsch, prvkey, pubkey);
   }
-  public static KeyPair load(JSch jsch, String prvkey, String pubkey) throws JSchException{
+  public static KeyPair load(JSch jsch, String prvfile, String pubfile) throws JSchException{
+
+    byte[] prvkey=null;
+    byte[] pubkey=null;
+
+    try{
+      prvkey = Util.fromFile(prvfile);
+    }
+    catch(IOException e){
+      throw new JSchException(e.toString(), (Throwable)e);
+    }
+
+    String _pubfile=pubfile;
+    if(pubfile==null){
+      _pubfile=prvfile+".pub";
+    }
+
+    try{
+      pubkey = Util.fromFile(_pubfile);
+    }
+    catch(IOException e){
+      if(pubfile!=null){  
+        throw new JSchException(e.toString(), (Throwable)e);
+      }
+    }
+
+    try {
+      return load(jsch, prvkey, pubkey);
+    }
+    finally {
+      Util.bzero(prvkey);
+    }
+  }
+
+  public static KeyPair load(JSch jsch, byte[] prvkey, byte[] pubkey) throws JSchException{
 
     byte[] iv=new byte[8];       // 8
     boolean encrypted=true;
@@ -428,21 +578,49 @@ public abstract class KeyPair{
     String publicKeyComment = "";
     Cipher cipher=null;
 
+    // prvkey from "ssh-add" command on the remote.
+    if(pubkey==null &&
+       prvkey!=null && 
+       (prvkey.length>11 &&
+        prvkey[0]==0 && prvkey[1]==0 && prvkey[2]==0 &&
+        (prvkey[3]==7 || prvkey[3]==19))){
+
+      Buffer buf=new Buffer(prvkey);
+      buf.skip(prvkey.length);  // for using Buffer#available()
+      String _type = new String(buf.getString()); // ssh-rsa or ssh-dss
+      buf.rewind();
+
+      KeyPair kpair=null;
+      if(_type.equals("ssh-rsa")){
+        kpair=KeyPairRSA.fromSSHAgent(jsch, buf);
+      }
+      else if(_type.equals("ssh-dss")){
+        kpair=KeyPairDSA.fromSSHAgent(jsch, buf);
+      }
+      else if(_type.equals("ecdsa-sha2-nistp256") ||
+              _type.equals("ecdsa-sha2-nistp384") ||
+              _type.equals("ecdsa-sha2-nistp512")){
+        kpair=KeyPairECDSA.fromSSHAgent(jsch, buf);
+      }
+      else{
+        throw new JSchException("privatekey: invalid key "+new String(prvkey, 4, 7));
+      }
+      return kpair;
+    }
+
     try{
-      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){
         if(buf[i] == '-' && i+4<len && 
            buf[i+1] == '-' && buf[i+2] == '-' && 
@@ -454,13 +632,34 @@ public abstract class KeyPair{
 
       while(i<len){
         if(buf[i]=='B'&& i+3<len && buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I'){
-          i+=6;            
+          i+=6;
+          if(i+2 >= 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<len){
-        if(buf[i]==0x0a){
-         boolean xd=(buf[i-1]==0x0d);
-          System.arraycopy(buf, i+1, 
-                          buf, 
-                          i-(xd ? 1 : 0), 
-                          len-i-1-(xd ? 1 : 0)
-                          );
-         if(xd)len--;
-          len--;
-          continue;
+        if(type==ERROR){
+          throw new JSchException("invalid privatekey: "+prvkey);
         }
-        if(buf[i]=='-'){  break; }
-        i++;
+
+        int start = i;
+        while(i < len){
+          if(buf[i] == '-'){  break; }
+          i++;
+        }
+
+        if((len-i) == 0 || (i-start) == 0){
+          throw new JSchException("invalid privatekey: "+prvkey);
+        }
+
+        // The content of 'buf' will be changed, so it should be copied.
+        byte[] tmp = new byte[i-start];
+        System.arraycopy(buf, start, tmp, 0, tmp.length);
+        byte[] _buf=tmp;
+
+        start = 0;
+        i = 0;
+
+        int _len = _buf.length;
+        while(i<_len){
+          if(_buf[i]==0x0a){
+            boolean xd=(_buf[i-1]==0x0d);
+            // ignore 0x0a (or 0x0d0x0a)
+            System.arraycopy(_buf, i+1, _buf, i-(xd ? 1 : 0), _len-(i+1));
+            if(xd)_len--;
+            _len--;
+            continue;
+          }
+          if(_buf[i]=='-'){  break; }
+          i++;
+        }
+        
+        if(i-start > 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 && i<len){
              if(buf[i]==0x0a){
                System.arraycopy(buf, i+1, buf, i, len-i-1);
@@ -646,7 +859,7 @@ public abstract class KeyPair{
            }
            if(valid){
              publickeyblob=Util.fromBase64(buf, start, i-start);
-             if(type==UNKNOWN){
+             if(prvkey==null || type==UNKNOWN){
                if(publickeyblob[8]=='d'){ type=DSA; }
                else if(publickeyblob[8]=='r'){ type=RSA; }
              }
@@ -654,21 +867,47 @@ public abstract class KeyPair{
          }
          else{
            if(buf[0]=='s'&& buf[1]=='s'&& buf[2]=='h' && buf[3]=='-'){
+              if(prvkey==null &&
+                 buf.length>7){
+               if(buf[4]=='d'){ type=DSA; }
+               else if(buf[4]=='r'){ type=RSA; }
+              }
              i=0;
              while(i<len){ if(buf[i]==' ')break; i++;} i++;
              if(i<len){
-               start=i;
+               int start=i;
                while(i<len){ if(buf[i]==' ')break; i++;}
                publickeyblob=Util.fromBase64(buf, start, i-start);
              }
               if(i++<len){
-                int s=i;
+                int start=i;
                 while(i<len){ if(buf[i]=='\n')break; i++;}
-                if(i<len){
-                  publicKeyComment = new String(buf, s, i-s);
+                if(i>0 && buf[i-1]==0x0d) i--;
+                if(start<i){
+                  publicKeyComment = new String(buf, start, i-start);
                 }
               } 
            }
+            else if(buf[0]=='e'&& buf[1]=='c'&& buf[2]=='d' && buf[3]=='s'){
+              if(prvkey==null && buf.length>7){
+               type=ECDSA;
+              }
+              i=0;
+              while(i<len){ if(buf[i]==' ')break; i++;} i++;
+              if(i<len){
+                int start=i;
+                while(i<len){ if(buf[i]==' ')break; i++;}
+                publickeyblob=Util.fromBase64(buf, start, i-start);
+              }
+              if(i++<len){
+                int start=i;
+                while(i<len){ if(buf[i]=='\n')break; i++;}
+                if(i>0 && buf[i-1]==0x0d) i--;
+                if(start<i){
+                  publicKeyComment = new String(buf, start, i-start);
+                }
+              } 
+            }
          }
        }
        catch(Exception ee){
@@ -685,6 +924,8 @@ 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); }
+    else if(vendor==VENDOR_PKCS8){ kpair = new KeyPairPKCS8(jsch); }
 
     if(kpair!=null){
       kpair.encrypted=encrypted;
@@ -694,11 +935,13 @@ public abstract class KeyPair{
       kpair.cipher=cipher;
 
       if(encrypted){
+        kpair.encrypted=true;
        kpair.iv=iv;
        kpair.data=data;
       }
       else{
        if(kpair.parse(data)){
+          kpair.encrypted=false;
          return kpair;
        }
        else{
@@ -726,4 +969,287 @@ public abstract class KeyPair{
   public void finalize (){
     dispose();
   }
+
+  private static final String[] header1 = {
+    "PuTTY-User-Key-File-2: ",
+    "Encryption: ",
+    "Comment: ",
+    "Public-Lines: "
+  };
+
+  private static final String[] header2 = {
+    "Private-Lines: "
+  };
+
+  private static final String[] header3 = {
+    "Private-MAC: "
+  };
+
+  static KeyPair loadPPK(JSch jsch, byte[] buf) throws JSchException {
+    byte[] pubkey = null;
+    byte[] prvkey = null;
+    int lines = 0;
+
+    Buffer buffer = new Buffer(buf);
+    java.util.Hashtable v = new java.util.Hashtable();
+
+    while(true){
+      if(!parseHeader(buffer, v))
+        break;
+    } 
+
+    String typ = (String)v.get("PuTTY-User-Key-File-2");
+    if(typ == null){
+      return null;
+    }
+
+    lines = Integer.parseInt((String)v.get("Public-Lines"));
+    pubkey = parseLines(buffer, lines); 
+
+    while(true){
+      if(!parseHeader(buffer, v))
+        break;
+    } 
+    
+    lines = Integer.parseInt((String)v.get("Private-Lines"));
+    prvkey = parseLines(buffer, lines); 
+
+    while(true){
+      if(!parseHeader(buffer, v))
+        break;
+    } 
+
+    prvkey = Util.fromBase64(prvkey, 0, prvkey.length);
+    pubkey = Util.fromBase64(pubkey, 0, pubkey.length);
+
+    KeyPair kpair = null;
+
+    if(typ.equals("ssh-rsa")) {
+
+      Buffer _buf = new Buffer(pubkey);
+      _buf.skip(pubkey.length);
+
+      int len = _buf.getInt();
+      _buf.getByte(new byte[len]);             // ssh-rsa
+      byte[] pub_array = new byte[_buf.getInt()];
+      _buf.getByte(pub_array);
+      byte[] n_array = new byte[_buf.getInt()];
+      _buf.getByte(n_array);
+
+      kpair = new KeyPairRSA(jsch, n_array, pub_array, null);
+    }
+    else if(typ.equals("ssh-dss")){
+      Buffer _buf = new Buffer(pubkey);
+      _buf.skip(pubkey.length);
+
+      int len = _buf.getInt();
+      _buf.getByte(new byte[len]);              // ssh-dss
+
+      byte[] p_array = new byte[_buf.getInt()];
+      _buf.getByte(p_array);
+      byte[] q_array = new byte[_buf.getInt()];
+      _buf.getByte(q_array);
+      byte[] g_array = new byte[_buf.getInt()];
+      _buf.getByte(g_array);
+      byte[] y_array = new byte[_buf.getInt()];
+      _buf.getByte(y_array);
+
+      kpair = new KeyPairDSA(jsch, p_array, q_array, g_array, y_array, null);
+    }
+    else {
+      return null;
+    }
+
+    if(kpair == null)
+      return null;
+
+    kpair.encrypted = !v.get("Encryption").equals("none");
+    kpair.vendor = VENDOR_PUTTY;
+    kpair.publicKeyComment = (String)v.get("Comment");
+    if(kpair.encrypted){
+      if(Session.checkCipher((String)jsch.getConfig("aes256-cbc"))){
+        try {
+          Class c=Class.forName((String)jsch.getConfig("aes256-cbc"));
+          kpair.cipher=(Cipher)(c.newInstance());
+          kpair.iv=new byte[kpair.cipher.getIVSize()];
+        }
+        catch(Exception e){
+          throw new JSchException("The cipher 'aes256-cbc' is required, but it is not available.");
+        }
+      }
+      else {
+        throw new JSchException("The cipher 'aes256-cbc' is required, but it is not available.");
+      }
+      kpair.data = prvkey;
+    }
+    else {
+      kpair.data = prvkey;
+      kpair.parse(prvkey);
+    }
+    return kpair;
+  }
+
+  private static byte[] parseLines(Buffer buffer, int lines){
+    byte[] buf = buffer.buffer;
+    int index = buffer.index;
+    byte[] data = null;
+
+    int i = index;
+    while(lines-->0){
+      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 <values.size(); i++) {
+        result[i]=(ASN1)values.elementAt(i);
+      }
+      return result;
+    }
+  }
 }
index f65d8c00fe4d1a0b24d6b69268e983a523ed7e39..ca5b708c16204b1bbca21bda3651e2164ab4e4a0 100644 (file)
@@ -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:
@@ -40,7 +40,23 @@ public class KeyPairDSA extends KeyPair{
   private int key_size=1024;
 
   public KeyPairDSA(JSch jsch){
+    this(jsch, null, null, null, null, null);
+  }
+
+  public KeyPairDSA(JSch jsch,
+                    byte[] P_array,
+                    byte[] Q_array,
+                    byte[] G_array,
+                    byte[] pub_array,
+                    byte[] prv_array){
     super(jsch);
+    this.P_array = P_array;
+    this.Q_array = Q_array;
+    this.G_array = G_array;
+    this.pub_array = pub_array;
+    this.prv_array = prv_array;
+    if(P_array!=null)
+      key_size = (new java.math.BigInteger(P_array)).bitLength();
   }
 
   void generate(int key_size) throws JSchException{
@@ -107,10 +123,26 @@ public class KeyPairDSA extends KeyPair{
          Q_array=buf.getMPIntBits();
          pub_array=buf.getMPIntBits();
          prv_array=buf.getMPIntBits();
+          if(P_array!=null)
+            key_size = (new java.math.BigInteger(P_array)).bitLength();
          return true;
        }
        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;
+      }
 
       int index=0;
       int length=0;
@@ -181,6 +213,9 @@ public class KeyPairDSA extends KeyPair{
       prv_array=new byte[length];
       System.arraycopy(plain, index, prv_array, 0, length);
       index+=length;
+
+      if(P_array!=null)
+        key_size = (new java.math.BigInteger(P_array)).bitLength();
     }
     catch(Exception e){
       //System.err.println(e);
@@ -195,25 +230,101 @@ public class KeyPairDSA extends KeyPair{
     if(foo!=null) return foo;
 
     if(P_array==null) return null;
+    byte[][] tmp = new byte[5][];
+    tmp[0] = sshdss;
+    tmp[1] = P_array;
+    tmp[2] = Q_array;
+    tmp[3] = G_array;
+    tmp[4] = pub_array;
+    return Buffer.fromBytes(tmp).buffer;
+  }
+
+  private static final byte[] sshdss=Util.str2byte("ssh-dss");
+  byte[] getKeyTypeName(){return sshdss;}
+  public int getKeyType(){return DSA;}
+
+  public int getKeySize(){
+    return key_size;
+  }
+
+  public byte[] getSignature(byte[] data){
+    try{      
+      Class c=Class.forName((String)jsch.getConfig("signature.dss"));
+      SignatureDSA dsa=(SignatureDSA)(c.newInstance());
+      dsa.init();
+      dsa.setPrvKey(prv_array, P_array, Q_array, G_array);
 
-    Buffer buf=new Buffer(sshdss.length+4+
-                         P_array.length+4+ 
-                         Q_array.length+4+ 
-                         G_array.length+4+ 
-                         pub_array.length+4);
+      dsa.update(data);
+      byte[] sig = dsa.sign();
+      byte[][] tmp = new byte[2][];
+      tmp[0] = sshdss;
+      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.dss"));
+      SignatureDSA dsa=(SignatureDSA)(c.newInstance());
+      dsa.init();
+
+      if(pub_array == null && P_array == null && getPublicKeyBlob()!=null){
+        Buffer buf = new Buffer(getPublicKeyBlob());
+        buf.getString();
+        P_array = buf.getString();
+        Q_array = buf.getString();
+        G_array = buf.getString();
+        pub_array = buf.getString();
+      } 
+
+      dsa.setPubKey(pub_array, P_array, Q_array, G_array);
+      return dsa;
+    }
+    catch(Exception e){
+      //System.err.println("e "+e);
+    }
+    return null;
+  }
+
+  static KeyPair fromSSHAgent(JSch jsch, Buffer buf) throws JSchException {
+
+    byte[][] tmp = buf.getBytes(7, "invalid key format");
+
+    byte[] P_array = tmp[1];
+    byte[] Q_array = tmp[2];
+    byte[] G_array = tmp[3];
+    byte[] pub_array = tmp[4];
+    byte[] prv_array = tmp[5];
+    KeyPairDSA kpair = new KeyPairDSA(jsch,
+                                      P_array, Q_array, G_array,
+                                      pub_array, prv_array);
+    kpair.publicKeyComment = new String(tmp[6]);
+    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(sshdss);
     buf.putString(P_array);
     buf.putString(Q_array);
     buf.putString(G_array);
     buf.putString(pub_array);
-    return buf.buffer;
+    buf.putString(prv_array);
+    buf.putString(Util.str2byte(publicKeyComment));
+    byte[] result = new byte[buf.getLength()];
+    buf.getByte(result, 0, result.length);
+    return result;
   }
 
-  private static final byte[] sshdss=Util.str2byte("ssh-dss");
-  byte[] getKeyTypeName(){return sshdss;}
-  public int getKeyType(){return DSA;}
-
-  public int getKeySize(){return key_size; }
   public void dispose(){
     super.dispose();
     Util.bzero(prv_array);
diff --git a/java/com/jcraft/jsch/KeyPairECDSA.java b/java/com/jcraft/jsch/KeyPairECDSA.java
new file mode 100644 (file)
index 0000000..aa25a6e
--- /dev/null
@@ -0,0 +1,391 @@
+/* -*-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 KeyPairECDSA extends KeyPair{
+
+  private static byte[][] oids = {
+    {(byte)0x06, (byte)0x08, (byte)0x2a, (byte)0x86, (byte)0x48, // 256
+     (byte)0xce, (byte)0x3d, (byte)0x03, (byte)0x01, (byte)0x07},
+    {(byte)0x06, (byte)0x05, (byte)0x2b, (byte)0x81, (byte)0x04, // 384
+     (byte)0x00, (byte)0x22},
+    {(byte)0x06, (byte)0x05, (byte)0x2b, (byte)0x81, (byte)0x04, //521
+     (byte)0x00, (byte)0x23},
+  };
+
+  private static String[] names = {
+    "nistp256", "nistp384", "nistp521"
+  };
+
+  private byte[] name=Util.str2byte(names[0]);
+  private byte[] r_array;
+  private byte[] s_array;
+  private byte[] prv_array;
+
+  private int key_size=256;
+
+  public KeyPairECDSA(JSch jsch){
+    this(jsch, null, null, null, null);
+  }
+
+  public KeyPairECDSA(JSch jsch,
+                      byte[] name,
+                      byte[] r_array,
+                      byte[] s_array,
+                      byte[] prv_array){
+    super(jsch);
+    if(name!=null)
+      this.name = name;
+    this.r_array = r_array;
+    this.s_array = s_array;
+    this.prv_array = prv_array;
+    if(prv_array!=null)
+      key_size = prv_array.length>=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; i<oids.length; i++){
+        if(Util.array_equals(oids[i], oid_array)){
+          name = Util.str2byte(names[i]);
+          break;
+        }
+      }
+
+      index++;  // 0xa1
+
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ 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);
+  }
+}
index f6507f24710d92b251c0efca9f3f6f92b7221457..6d7e21c96bb09fa8c3b83f392ee4439fa0691354 100644 (file)
@@ -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 (file)
index 0000000..b0d6bbf
--- /dev/null
@@ -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();
+}
index 3a8490744170521df661defa605d667561eef5f7..ecb97a413e059b579c48a09234e792c414654d94 100644 (file)
@@ -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 (file)
index 0000000..47c2a93
--- /dev/null
@@ -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;
+  }
+}
index dfc202f99adb158685e5f4eb5ef194163e8152a5..4221b75ed7c7eeac9140d0f57231f301821c1919 100644 (file)
@@ -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<n_array.length; i++){
-System.err.print(Integer.toHexString(n_array[i]&0xff)+":");
-}
-System.err.println("");
-*/
+
       index++;
       length=plain[index++]&0xff;
       if((length&0x80)!=0){
@@ -180,13 +223,7 @@ System.err.println("");
       pub_array=new byte[length];
       System.arraycopy(plain, index, pub_array, 0, length);
       index+=length;
-/*
-System.err.println("int: E len="+length);
-for(int i=0; i<pub_array.length; i++){
-System.err.print(Integer.toHexString(pub_array[i]&0xff)+":");
-}
-System.err.println("");
-*/
+
       index++;
       length=plain[index++]&0xff;
       if((length&0x80)!=0){
@@ -196,13 +233,6 @@ System.err.println("");
       prv_array=new byte[length];
       System.arraycopy(plain, index, prv_array, 0, length);
       index+=length;
-/*
-System.err.println("int: prv len="+length);
-for(int i=0; i<prv_array.length; i++){
-System.err.print(Integer.toHexString(prv_array[i]&0xff)+":");
-}
-System.err.println("");
-*/
 
       index++;
       length=plain[index++]&0xff;
@@ -213,13 +243,7 @@ System.err.println("");
       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; i<p_array.length; i++){
-System.err.print(Integer.toHexString(p_array[i]&0xff)+":");
-}
-System.err.println("");
-*/
+
       index++;
       length=plain[index++]&0xff;
       if((length&0x80)!=0){
@@ -229,13 +253,7 @@ System.err.println("");
       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; i<q_array.length; i++){
-System.err.print(Integer.toHexString(q_array[i]&0xff)+":");
-}
-System.err.println("");
-*/
+
       index++;
       length=plain[index++]&0xff;
       if((length&0x80)!=0){
@@ -245,13 +263,7 @@ System.err.println("");
       ep_array=new byte[length];
       System.arraycopy(plain, index, ep_array, 0, length);
       index+=length;
-/*
-System.err.println("int: ep len="+length);
-for(int i=0; i<ep_array.length; i++){
-System.err.print(Integer.toHexString(ep_array[i]&0xff)+":");
-}
-System.err.println("");
-*/
+
       index++;
       length=plain[index++]&0xff;
       if((length&0x80)!=0){
@@ -261,13 +273,7 @@ System.err.println("");
       eq_array=new byte[length];
       System.arraycopy(plain, index, eq_array, 0, length);
       index+=length;
-/*
-System.err.println("int: eq len="+length);
-for(int i=0; i<eq_array.length; i++){
-System.err.print(Integer.toHexString(eq_array[i]&0xff)+":");
-}
-System.err.println("");
-*/
+
       index++;
       length=plain[index++]&0xff;
       if((length&0x80)!=0){
@@ -277,13 +283,11 @@ System.err.println("");
       c_array=new byte[length];
       System.arraycopy(plain, index, c_array, 0, length);
       index+=length;
-/*
-System.err.println("int: c len="+length);
-for(int i=0; i<c_array.length; i++){
-System.err.print(Integer.toHexString(c_array[i]&0xff)+":");
-}
-System.err.println("");
-*/
+
+      if(n_array!=null){
+        key_size = (new java.math.BigInteger(n_array)).bitLength();
+      }
+
     }
     catch(Exception e){
       //System.err.println(e);
@@ -292,27 +296,121 @@ System.err.println("");
     return true;
   }
 
-
   public byte[] getPublicKeyBlob(){
     byte[] foo=super.getPublicKeyBlob();
     if(foo!=null) return foo;
 
     if(pub_array==null) return null;
-
-    Buffer buf=new Buffer(sshrsa.length+4+
-                         pub_array.length+4+ 
-                         n_array.length+4);
-    buf.putString(sshrsa);
-    buf.putString(pub_array);
-    buf.putString(n_array);
-    return buf.buffer;
+    byte[][] tmp = new byte[3][];
+    tmp[0] = sshrsa;
+    tmp[1] = pub_array;
+    tmp[2] = n_array;
+    return Buffer.fromBytes(tmp).buffer;
   }
 
   private static final byte[] sshrsa=Util.str2byte("ssh-rsa");
   byte[] getKeyTypeName(){return sshrsa;}
   public int getKeyType(){return RSA;}
 
-  public int getKeySize(){return key_size; }
+  public int getKeySize(){
+    return key_size;
+  }
+
+  public byte[] getSignature(byte[] data){
+    try{      
+      Class c=Class.forName((String)jsch.getConfig("signature.rsa"));
+      SignatureRSA rsa=(SignatureRSA)(c.newInstance());
+      rsa.init();
+      rsa.setPrvKey(prv_array, n_array);
+
+      rsa.update(data);
+      byte[] sig = rsa.sign();
+      byte[][] tmp = new byte[2][];
+      tmp[0] = sshrsa;
+      tmp[1] = sig;
+      return Buffer.fromBytes(tmp).buffer;
+    }
+    catch(Exception e){
+    }
+    return null;
+  }
+
+  public Signature getVerifier(){
+    try{      
+      Class c=Class.forName((String)jsch.getConfig("signature.rsa"));
+      SignatureRSA rsa=(SignatureRSA)(c.newInstance());
+      rsa.init();
+
+      if(pub_array == null && n_array == null && getPublicKeyBlob()!=null){
+        Buffer buf = new Buffer(getPublicKeyBlob());
+        buf.getString();
+        pub_array = buf.getString();
+        n_array = buf.getString();
+      } 
+
+      rsa.setPubKey(pub_array, n_array);
+      return rsa;
+    }
+    catch(Exception e){
+    }
+    return null;
+  }
+
+  static KeyPair fromSSHAgent(JSch jsch, Buffer buf) throws JSchException {
+
+    byte[][] tmp = buf.getBytes(8, "invalid key format");
+
+    byte[] n_array = tmp[1];
+    byte[] pub_array = tmp[2];
+    byte[] prv_array = tmp[3];
+    KeyPairRSA kpair = new KeyPairRSA(jsch, n_array, pub_array, prv_array);
+    kpair.c_array = tmp[4];     // iqmp
+    kpair.p_array = tmp[5];
+    kpair.q_array = tmp[6];
+    kpair.publicKeyComment = new String(tmp[7]);
+    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(sshrsa);
+    buf.putString(n_array);
+    buf.putString(pub_array);
+    buf.putString(prv_array);
+    buf.putString(getCArray());
+    buf.putString(p_array);
+    buf.putString(q_array);
+    buf.putString(Util.str2byte(publicKeyComment));
+    byte[] result = new byte[buf.getLength()];
+    buf.getByte(result, 0, result.length);
+    return result;
+  }
+
+  private byte[] getEPArray(){
+    if(ep_array==null){
+      ep_array=(new BigInteger(prv_array)).mod(new BigInteger(p_array).subtract(BigInteger.ONE)).toByteArray();
+    }
+    return ep_array;
+  } 
+
+  private byte[] getEQArray(){
+    if(eq_array==null){
+      eq_array=(new BigInteger(prv_array)).mod(new BigInteger(q_array).subtract(BigInteger.ONE)).toByteArray();
+    }
+    return eq_array;
+  } 
+
+  private byte[] getCArray(){
+    if(c_array==null){
+      c_array=(new BigInteger(q_array)).modInverse(new BigInteger(p_array)).toByteArray();
+    }
+    return c_array;
+  } 
+
   public void dispose(){
     super.dispose();
     Util.bzero(prv_array);
index 342d774354147ae65d7115b2736de156a9aeec05..b86fa25cc3e80fcfaa6fe9f37f84c1f815b31c26 100644 (file)
@@ -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,17 +31,10 @@ package com.jcraft.jsch;
 
 import java.io.*;
 
-@SuppressWarnings({"rawtypes","unchecked","static"})
 public
 class KnownHosts implements HostKeyRepository{
   private static final String _known_hosts="known_hosts";
 
-  /*
-  static final int SSHDSS=0;
-  static final int SSHRSA=1;
-  static final int UNKNOWN=2;
-  */
-
   private JSch jsch=null;
   private String known_hosts=null;
   private java.util.Vector pool=null;
@@ -54,23 +47,24 @@ class KnownHosts implements HostKeyRepository{
     pool=new java.util.Vector();
   }
 
-  void setKnownHosts(String foo) throws JSchException{
+  void setKnownHosts(String filename) throws JSchException{
     try{
-      known_hosts=foo;
-      FileInputStream fis=new FileInputStream(foo);
+      known_hosts = filename;
+      FileInputStream fis=new FileInputStream(Util.checkTilde(filename));
       setKnownHosts(fis);
     }
     catch(FileNotFoundException e){
+      throw new JSchException(e.toString(), (Throwable)e);
     } 
   }
-  void setKnownHosts(InputStream foo) throws JSchException{
+  void setKnownHosts(InputStream input) throws JSchException{
     pool.removeAllElements();
     StringBuffer sb=new StringBuffer();
     byte i;
     int j;
     boolean error=false;
     try{
-      InputStream fis=foo;
+      InputStream fis=input;
       String host;
       String key=null;
       int type;
@@ -123,6 +117,35 @@ loop:
          continue loop; 
        }
 
+        while(j<bufl){
+          i=buf[j];
+         if(i==' '||i=='\t'){ j++; continue; }
+          break;
+        }
+
+        String marker="";
+        if(host.charAt(0) == '@'){
+          marker = host;
+
+          sb.setLength(0);
+          while(j<bufl){
+            i=buf[j++];
+            if(i==0x20 || i=='\t'){ break; }
+            sb.append((char)i);
+          }
+          host=sb.toString();
+          if(j>=bufl || host.length()==0){
+            addInvalidLine(Util.byte2str(buf, 0, bufl));
+            continue loop; 
+          }
+
+          while(j<bufl){
+            i=buf[j];
+            if(i==' '||i=='\t'){ j++; continue; }
+            break;
+          }
+        }
+
         sb.setLength(0);
        type=-1;
         while(j<bufl){
@@ -130,19 +153,28 @@ loop:
           if(i==0x20 || i=='\t'){ break; }
           sb.append((char)i);
        }
-       if(sb.toString().equals("ssh-dss")){ type=HostKey.SSHDSS; }
-       else if(sb.toString().equals("ssh-rsa")){ type=HostKey.SSHRSA; }
+       String tmp = sb.toString();
+       if(HostKey.name2type(tmp)!=HostKey.UNKNOWN){
+         type=HostKey.name2type(tmp);
+       }
        else { j=bufl; }
        if(j>=bufl){
          addInvalidLine(Util.byte2str(buf, 0, bufl));
          continue loop; 
        }
 
+        while(j<bufl){
+          i=buf[j];
+         if(i==' '||i=='\t'){ j++; continue; }
+          break;
+        }
+
         sb.setLength(0);
         while(j<bufl){
           i=buf[j++];
           if(i==0x0d){ continue; }
           if(i==0x0a){ break; }
+          if(i==0x20 || i=='\t'){ break; }
           sb.append((char)i);
        }
        key=sb.toString();
@@ -151,16 +183,43 @@ loop:
          continue loop; 
        }
 
+        while(j<bufl){
+          i=buf[j];
+         if(i==' '||i=='\t'){ j++; continue; }
+          break;
+        }
+
+        /**
+          "man sshd" has following descriptions,
+            Note that the lines in these files are typically hundreds
+            of characters long, and you definitely don't want to type
+            in the host keys by hand.  Rather, generate them by a script,
+            ssh-keyscan(1) or by taking /usr/local/etc/ssh_host_key.pub and
+            adding the host names at the front.
+          This means that a comment is allowed to appear at the end of each
+          key entry.
+        */
+        String comment=null;
+        if(j<bufl){
+          sb.setLength(0);
+          while(j<bufl){
+            i=buf[j++];
+            if(i==0x0d){ continue; }
+            if(i==0x0a){ break; }
+            sb.append((char)i);
+          }
+          comment=sb.toString();
+        }
+
        //System.err.println(host);
        //System.err.println("|"+key+"|");
 
        HostKey hk = null;
-        hk = new HashedHostKey(host, type, 
+        hk = new HashedHostKey(marker, host, type, 
                                Util.fromBase64(Util.str2byte(key), 0, 
-                                               key.length()));
+                                               key.length()), comment);
        pool.addElement(hk);
       }
-      fis.close();
       if(error){
        throw new JSchException("KnownHosts: invalid format");
       }
@@ -172,6 +231,12 @@ loop:
         throw new JSchException(e.toString(), (Throwable)e);
       throw new JSchException(e.toString());
     }
+    finally {
+      try{ input.close(); }
+      catch(IOException e){
+        throw new JSchException(e.toString(), (Throwable)e);
+      }
+    }
   }
   private void addInvalidLine(String line) throws JSchException {
     HostKey hk = new HostKey(line, HostKey.UNKNOWN, null);
@@ -186,14 +251,19 @@ loop:
       return result;
     }
 
-    int type=getType(key);
-    HostKey hk;
+    HostKey hk = null;
+    try {
+      hk = new HostKey(host, HostKey.GUESS, key);
+    }
+    catch(JSchException e){  // unsupported key
+      return result;
+    }
 
     synchronized(pool){
       for(int i=0; i<pool.size(); i++){
-        hk=(HostKey)(pool.elementAt(i));
-        if(hk.isMatched(host) && hk.type==type){
-          if(Util.array_equals(hk.key, key)){
+        HostKey _hk=(HostKey)(pool.elementAt(i));
+        if(_hk.isMatched(host) && _hk.type==hk.type){
+          if(Util.array_equals(_hk.key, key)){
             return OK;
           }
           else{
@@ -212,6 +282,7 @@ loop:
 
     return result;
   }
+
   public void add(HostKey hostkey, UserInfo userinfo){
     int type=hostkey.type;
     String host=hostkey.getHost();
@@ -244,7 +315,7 @@ loop:
     String bar=getKnownHostsRepositoryID();
     if(bar!=null){
       boolean foo=true;
-      File goo=new File(bar);
+      File goo=new File(Util.checkTilde(bar));
       if(!goo.exists()){
         foo=false;
         if(userinfo!=null){
@@ -279,31 +350,33 @@ loop:
   }
 
   public HostKey[] getHostKey(){
-    return getHostKey(null, null);
+    return getHostKey(null, (String)null);
   }
   public HostKey[] getHostKey(String host, String type){
     synchronized(pool){
-      int count=0;
+      java.util.ArrayList v = new java.util.ArrayList();
       for(int i=0; i<pool.size(); i++){
        HostKey hk=(HostKey)pool.elementAt(i);
        if(hk.type==HostKey.UNKNOWN) continue;
        if(host==null || 
           (hk.isMatched(host) && 
            (type==null || hk.getType().equals(type)))){
-         count++;
+          v.add(hk);
        }
       }
-      if(count==0)return null;
-      HostKey[] foo=new HostKey[count];
-      int j=0;
-      for(int i=0; i<pool.size(); i++){
-       HostKey hk=(HostKey)pool.elementAt(i);
-       if(hk.type==HostKey.UNKNOWN) continue;
-       if(host==null || 
-          (hk.isMatched(host) && 
-           (type==null || hk.getType().equals(type)))){
-         foo[j++]=hk;
-       }
+      HostKey[] foo = new HostKey[v.size()];
+      for(int i=0; i<v.size(); i++){
+        foo[i] = (HostKey)v.get(i);
+      }
+      if(host != null && host.startsWith("[") && host.indexOf("]:")>1){
+        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; i<pool.size(); i++){
         hk=(HostKey)(pool.elementAt(i));
         //hk.dump(out);
+       String marker=hk.getMarker();
        String host=hk.getHost();
        String type=hk.getType();
+        String comment = hk.getComment();
        if(type.equals("UNKNOWN")){
          out.write(Util.str2byte(host));
          out.write(cr);
          continue;
        }
+        if(marker.length()!=0){
+          out.write(Util.str2byte(marker));
+          out.write(space);
+        }
        out.write(Util.str2byte(host));
        out.write(space);
        out.write(Util.str2byte(type));
        out.write(space);
        out.write(Util.str2byte(hk.getKey()));
+        if(comment!=null){
+          out.write(space);
+          out.write(Util.str2byte(comment));
+        }
        out.write(cr);
       }
       }
@@ -378,11 +461,7 @@ loop:
       System.err.println(e);
     }
   }
-  private int getType(byte[] key){
-    if(key[8]=='d') return HostKey.SSHDSS;
-    if(key[8]=='r') return HostKey.SSHRSA;
-    return HostKey.UNKNOWN;
-  }
+
   private String deleteSubString(String hosts, String host){
     int i=0;
     int hostlen=host.length();
@@ -429,12 +508,14 @@ loop:
     byte[] salt=null;
     byte[] hash=null;
 
-
     HashedHostKey(String host, byte[] key) throws JSchException {
       this(host, GUESS, key);
     }
     HashedHostKey(String host, int type, byte[] key) throws JSchException {
-      super(host, type, key);
+      this("", host, type, key, null);
+    }
+    HashedHostKey(String marker, String host, int type, byte[] key, String comment) throws JSchException {
+      super(marker, host, type, key, comment);
       if(this.host.startsWith(HASH_MAGIC) &&
          this.host.substring(HASH_MAGIC.length()).indexOf(HASH_DELIM)>0){
         String data=this.host.substring(HASH_MAGIC.length());
index 81c8eacf4f7348b098cecb82a7cb933dcf39a74a..303096bf35298ed19a9fc42c8fc91d1b955337ce 100644 (file)
@@ -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
index 7dde42e78b39f7d3dc6f98d195af7c641e133570..bc463498416882dda961aaec831b57ce58f588e6 100644 (file)
@@ -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<identities.size(); i++){
       v.addElement(identities.elementAt(i));
@@ -51,6 +60,23 @@ class LocalIdentityRepository implements IdentityRepository {
 
   public synchronized void add(Identity identity) {
     if(!identities.contains(identity)) {
+      byte[] blob1 = identity.getPublicKeyBlob();
+      if(blob1 == null) {
+        identities.addElement(identity);
+        return;
+      }
+      for(int i = 0; i<identities.size(); i++){
+        byte[] blob2 = ((Identity)identities.elementAt(i)).getPublicKeyBlob();
+        if(blob2 != null && Util.array_equals(blob1, blob2)){
+          if(!identity.isEncrypted() && 
+             ((Identity)identities.elementAt(i)).isEncrypted()){
+            remove(blob2);
+          }
+          else {  
+            return;
+          }
+        }
+      }
       identities.addElement(identity);
     }
   }
@@ -59,7 +85,7 @@ class LocalIdentityRepository implements IdentityRepository {
     try{
       Identity _identity =
         IdentityFile.newInstance("from remote:", identity, null, jsch);
-      identities.addElement(_identity);
+      add(_identity);
       return true;
     }
     catch(JSchException e){
@@ -67,6 +93,16 @@ class LocalIdentityRepository implements IdentityRepository {
     }
   }
 
+  synchronized void remove(Identity identity) {
+    if(identities.contains(identity)) {
+      identities.removeElement(identity);
+      identity.clear();
+    }
+    else {
+      remove(identity.getPublicKeyBlob());
+    }
+  }
+
   public synchronized boolean remove(byte[] blob) {
     if(blob == null) return false;
     for(int i=0; i<identities.size(); i++) {
@@ -88,4 +124,28 @@ class LocalIdentityRepository implements IdentityRepository {
     }
     identities.removeAllElements();
   } 
+
+  private void removeDupulicates(){
+    Vector v = new Vector();
+    int len = identities.size();
+    if(len == 0) return;
+    for(int i=0; i<len; i++){
+      Identity foo = (Identity)identities.elementAt(i);
+      byte[] foo_blob = foo.getPublicKeyBlob();
+      if(foo_blob == null) continue;
+      for(int j=i+1; j<len; j++){
+        Identity bar = (Identity)identities.elementAt(j);
+        byte[] bar_blob = bar.getPublicKeyBlob();
+        if(bar_blob == null) continue;
+        if(Util.array_equals(foo_blob, bar_blob) &&
+           foo.isEncrypted() == bar.isEncrypted()){
+          v.addElement(foo_blob);
+          break;
+        }
+      }
+    }
+    for(int i=0; i<v.size(); i++){
+      remove((byte[])v.elementAt(i));
+    }
+  }
 }
index 1263722b3c1feb9cdf530090209c2fa21e904b24..b9704f898702e041f25697f9d2988e541dd49d8b 100644 (file)
@@ -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:
index 0475ce2ce5209d3e136a4a38fb034f2bffc7aa64..199c8888a26e64ce32267665637937dc46088ea4 100644 (file)
@@ -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/OpenSSHConfig.java b/java/com/jcraft/jsch/OpenSSHConfig.java
new file mode 100644 (file)
index 0000000..9b1bff8
--- /dev/null
@@ -0,0 +1,264 @@
+/* -*-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.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.FileReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * This class implements ConfigRepository interface, and parses
+ * OpenSSH's configuration file.  The following keywords will be recognized,
+ * <ul>
+ *   <li>Host</li>
+ *   <li>User</li>
+ *   <li>Hostname</li>
+ *   <li>Port</li>
+ *   <li>PreferredAuthentications</li>
+ *   <li>IdentityFile</li>
+ *   <li>NumberOfPasswordPrompts</li>
+ *   <li>ConnectTimeout</li>
+ *   <li>HostKeyAlias</li>
+ *   <li>UserKnownHostsFile</li>
+ *   <li>KexAlgorithms</li>
+ *   <li>HostKeyAlgorithms</li>
+ *   <li>Ciphers</li>
+ *   <li>Macs</li>
+ *   <li>Compression</li>
+ *   <li>CompressionLevel</li>
+ *   <li>ForwardAgent</li>
+ *   <li>RequestTTY</li>
+ *   <li>ServerAliveInterval</li>  
+ *   <li>LocalForward</li>
+ *   <li>RemoteForward</li>
+ *   <li>ClearAllForwardings</li>
+ * </ul>
+ *
+ * @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/*<String[]>*/ 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 (file)
index 0000000..44031fc
--- /dev/null
@@ -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);
+}
index 9c44157789b661938186352bd8508c1ee2c39bdf..c163b78651491a947a06e4fd91b2cbc27c91c6ee 100644 (file)
@@ -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:
index b5fc37bbcf19dded4345fc0db0ada42dc9e61a07..2fdcd961b6646234558954d38d8d21e42dc73683 100644 (file)
@@ -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;
+  }
 }
index 7d05caa85c221eec3b60e85ead473faebc69068c..be196b608fb1268b185b38e8e71f298cc957d515 100644 (file)
@@ -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:
index df23114ab44d79de8f12c68198bd36f8ad07c297..09a1623d9afd1756d8fff384c0957f18da1f553b 100644 (file)
@@ -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:
index cb5061654a21d2b9d58ece9a82af54c778075f8e..5cd97ed5f753769173eb8cdafab355c34393d9b6 100644 (file)
@@ -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:
index 7960135a96b1e2c9558ae2033e574e2272a2b247..33311bab537fec976974de08889312a17ef94c4d 100644 (file)
@@ -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:
index a52886e52d62926e47f1d91303840de8fafc5906..d00a219248f21a3396f98cc0b548585a06eda7dd 100644 (file)
@@ -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
index 879b7770ab382f4eef64d6ef9866e2594913befc..5718ba393420ecf4bd5c77dea1d697096662c03e 100644 (file)
@@ -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:
index 94f9b0138fa6bff1a03a66416248c2124a421d0b..8bedb6acea9c9f81eac3feeeaac4dfaab721b4ca 100644 (file)
@@ -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:
index 66d328cd992df0c0773be43ed6dab028c6d66c54..252a0844a34deb7b0a88f7b4e6be0b62b59239cf 100644 (file)
@@ -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:
index cccda4df1772d558301fed70c8d6071c813a9401..fcbcd3d789e519775ddb82e7f0984c61a27e4aec 100644 (file)
@@ -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:
index 318d99ad0363ad22f0857def8953d502df2e5e48..badc90f1e26dafcd1a0ac3f4e5ee2a18b3b4006e 100644 (file)
@@ -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:
index 86bf4f138da552fb94a9ef0a441a1e7296a79388..d0dfef16e2212502e018bd6992f8fd0c1367967b 100644 (file)
@@ -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:
index 483c296bd7a2242fcceeb9a2fc50e7c22f9bbfdd..b1a1ea517f9e5776cb889cef7df73c01b8723fdf 100644 (file)
@@ -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:
index e037ba9e6bbf38c4389fcd1820ff4dcb2d309274..1266ad7dc77d9c9c0fcc97f8081913e9507fd115 100644 (file)
@@ -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:
index a6926177c79fc6557c42736cecbea87d0d8d62c5..3a88d0688dc964254253168f2762d7de97416125 100644 (file)
@@ -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:
index b6fee4f41368091f65ed95eaa184fcdef2c7a160..4de2b1c479a31066b896703c8c68a02789c69a33 100644 (file)
@@ -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:
index 43600ac40341dd7bfe91b79893cffd91c31a6f16..53a31e630ee586b852d79e37b9efd8ebf96538fe 100644 (file)
@@ -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:
index 3bdaca9f38e9a5decd2ddfae49d522c5353c0aa7..870a352d1474aa568c907aaf7aaae0f159b04aed 100644 (file)
@@ -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:
index 682b4c4f2aad7a88a04c5c4f55b60cade718ff83..c405577cb3bce592eb4a294e0f54b5531217eed9 100644 (file)
@@ -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:
index 900d96d6043b69a96efffbd8e70076f299cef56c..39e9029aa8d4485339aa80a5593d34b1e904e49e 100644 (file)
@@ -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 <code>lport</code> is <code>0</code>, 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 <code>bind_address</code> is an empty string
+   * or '*', the port should be available from all interfaces.
+   * If <code>bind_address</code> is <code>"localhost"</code> or
+   * <code>null</code>, the listening port will be bound for local use only.
+   * If <code>lport</code> is <code>0</code>, 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 <code>bind_address</code> is an empty string or <code>"*"</code>,
+   * the port should be available from all interfaces.
+   * If <code>bind_address</code> is <code>"localhost"</code> or
+   * <code>null</code>, the listening port will be bound for local use only.
+   * If <code>lport</code> is <code>0</code>, 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 <code>bind_address</code> is an empty string
+   * or <code>"*"</code>, the port should be available from all interfaces.
+   * If <code>bind_address</code> is <code>"localhost"</code> or
+   * <code>null</code>, the listening port will be bound for local use only.
+   * If <code>lport</code> is <code>0</code>, 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 <code>lport</code> 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 <code>lport</code> on <code>bind_address</code> 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 <code>bind_address</code> is an empty string or <code>"*"</code>,
+   * the port should be available from all interfaces.
+   * If <code>bind_address</code> is <code>"localhost"</code> or is not given,
+   * the listening port will be bound for local use only.
+   * Note that if <code>GatewayPorts</code> is <code>"no"</code> on the
+   * remote, <code>"localhost"</code> 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 <code>bind_address</code> is an empty string or <code>"*"</code>,
+   * the port should be available from all interfaces.
+   * If <code>bind_address</code> is <code>"localhost"</code> or is not given,
+   * the listening port will be bound for local use only.
+   * Note that if <code>GatewayPorts</code> is <code>"no"</code> on the
+   * remote, <code>"localhost"</code> is always used as a bind_address.
+   * If <code>rport</code> is <code>0</code>, 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 <code>rport</code> on the remote will be
+   * forwarded to an instance of the class <code>daemon</code>.
+   * The class specified by <code>daemon</code> must implement
+   * <code>ForwardedTCPIPDaemon</code>.
+   *
+   * @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 <code>rport</code> on the remote will be
+   * forwarded to an instance of the class <code>daemon</code> with
+   * the argument <code>arg</code>.
+   * The class specified by <code>daemon</code> must implement <code>ForwardedTCPIPDaemon</code>.
+   *
+   * @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 <code>bind_address</code> is an empty string
+   * or <code>"*"</code>, the port should be available from all interfaces.
+   * If <code>bind_address</code> is <code>"localhost"</code> or is not given,
+   * the listening port will be bound for local use only.
+   * Note that if <code>GatewayPorts</code> is <code>"no"</code> on the
+   * remote, <code>"localhost"</code> is always used as a bind_address.
+   * The TCP connection to <code>rport</code> on the remote will be
+   * forwarded to an instance of the class <code>daemon</code> with the
+   * argument <code>arg</code>. 
+   * The class specified by <code>daemon</code> must implement <code>ForwardedTCPIPDaemon</code>.
+   *
+   * @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; i<tmp.length; i++){
+        if(tmp[i].length()==0) continue;
+        foo.addElement(tmp[i].trim());
+      }
+      StringBuffer sb = new StringBuffer(); // join
+      for(int i=0; i<foo.size(); i++){
+        sb.append((String)(foo.elementAt(i)));
+        if(i+1<foo.size())
+          sb.append(":");
+      }
+      conf = sb.toString(); 
+    }
+
+    String org = conf;
+    Forwarding f = new Forwarding();
+    try {
+      if(conf.lastIndexOf(":") == -1)
+        throw new JSchException ("parseForwarding: "+org);
+      f.hostport = Integer.parseInt(conf.substring(conf.lastIndexOf(":")+1));
+      conf = conf.substring(0, conf.lastIndexOf(":"));
+      if(conf.lastIndexOf(":") == -1)
+        throw new JSchException ("parseForwarding: "+org);
+      f.host = conf.substring(conf.lastIndexOf(":")+1);
+      conf = conf.substring(0, conf.lastIndexOf(":"));
+      if(conf.lastIndexOf(":") != -1){
+        f.port = Integer.parseInt(conf.substring(conf.lastIndexOf(":")+1));
+        conf = conf.substring(0, conf.lastIndexOf(":"));
+        if(conf.length() ==0 || conf.equals("*")) conf="0.0.0.0";
+        if(conf.equals("localhost")) conf="127.0.0.1";
+        f.bind_address = conf;
+      }
+      else {
+        f.port = Integer.parseInt(conf);
+        f.bind_address = "127.0.0.1";
+      }
+    }
+    catch(NumberFormatException e){
+      throw new JSchException ("parseForwarding: "+e.toString());
+    }
+    return f;
+  }
+
+  /**
+   * Registers the local port forwarding.  The argument should be
+   * in the format like "[bind_address:]port:host:hostport".
+   * If <code>bind_address</code> is an empty string or <code>"*"</code>,
+   * the port should be available from all interfaces.
+   * If <code>bind_address</code> is <code>"localhost"</code> 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 <code>"*"</code> or an empty string,
+   * then the forwarding is requested to listen on all interfaces.
+   * Note that if <code>GatewayPorts</code> is <code>"no"</code> on the remote,
+   * <code>"localhost"</code> is always used for bind_address.
+   * If the specified remote is <code>"0"</code>,
+   * 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 <code>host</code>:<code>port</code>.
+   * 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 <code>rport</code>.
+   *
+   * @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 <code>rport</code> bound on the interface at
+   * <code>bind_address</code>.
+   *
+   * @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; i<foo.length; i++){
+        JSch.getLogger().log(Logger.INFO, 
+                             foo[i]+" is not available.");
+      }
+    }
+    return foo;
+  }
+
+  /**
+   * Sets the identityRepository, which will be referred
+   * in the public key authentication.  The default value is <code>null</code>.
+   *
+   * @param identityRepository 
+   * @see #getIdentityRepository()
+   */
+  public void setIdentityRepository(IdentityRepository identityRepository){
+    this.identityRepository = identityRepository;
+  }
+
+  /**
+   * Gets the identityRepository.
+   * If this.identityRepository is <code>null</code>,
+   * 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 <code>null</code>,
+   * 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);
+  }
 }
index e89b24355cdfc237935ec32f19e6274527654838..3195def9a866482d5aa61253bdbfcd4881332c1c 100644 (file)
@@ -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; }
index 6a6c1ff818819d485cebc5d14b527c871bfb773b..7fb630e4dafbe81e5e1c7b3f8e9c0c85b78f7049 100644 (file)
@@ -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:
index bd91688db7088fd38b13ed0bb0d9a48cc56b6d42..cfc69e6bf55c11d7fa626742790201e394d45e6d 100644 (file)
@@ -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 (file)
index 0000000..872eddb
--- /dev/null
@@ -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 (file)
index 0000000..a517cfd
--- /dev/null
@@ -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;
+}
index 6f44b7ff4887d4a8df8d63ceb42eea3fd66edbd2..9cc0651e059f788c3e02d2095067a549869714d6 100644 (file)
@@ -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 (file)
index 0000000..516a490
--- /dev/null
@@ -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;
+}
index e8e61059c038324dfeda948f03d9e380d899ffba..b31a8dcfc0da4cc0a154d46b3c1ff7725606d6d6 100644 (file)
@@ -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;
 }
index aaac0dceedd8f87846a8775dc0d0204a203e23b6..532b7d4d4700a1259f3fc7b34b6f2ec6a45fe791 100644 (file)
@@ -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:
index 23af9c31458455162092aa9d81a04a834ef3d11f..afc5217ebe5d3ddd040d9c8b8489c5b24227d671 100644 (file)
@@ -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:
index 085a9508faf1c4a27bdd826b5a523cfe7e9d8366..8a74dc624186c6cf55ee470bf4dbb90208686f14 100644 (file)
@@ -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:
index 15856cbc51da823d0b780da8f57aec696bcacf83..2b0bdc7da21808edbbe8e5d3dc56dd93826389c9 100644 (file)
@@ -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:
index 2994796527cb775eec9f21bd937a76bcd72433b9..389733e634426c42729acad94abc16e1d224651d 100644 (file)
@@ -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;
index b3b0b077cc05cece3bc507ce8d1e579afb469e3b..4b04a1fa35c89b406a561cd2749e2631fdd71021 100644 (file)
@@ -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:
index 9b5837f589d7acaa683331f6ba946ba82348276f..b10f4622edfcbf9126a1b12ef74f406432536e83 100644 (file)
@@ -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:
index 234ad0ac22b54a365a40fabb870e2feaccdac3ed..129c124d696bf09956a37ebc533f4b722b0eefe7 100644 (file)
@@ -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);
index 22552edec33303928b6667de082a9caa6bedfb37..c7f9f478ef69d1a87cd704f7d475a857d3e537d1 100644 (file)
@@ -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:
index 8d51fc61918c9ae8bd9d1a48a3ed3097f3fa8a64..5974b0cbf580366bdabbada0c13ab8cc08edd13e 100644 (file)
@@ -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<start+length;i+=4){
-      foo[j]=(byte)((val(buf[i])<<2)|((val(buf[i+1])&0x30)>>>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<start+length;i+=4){
+        foo[j]=(byte)((val(buf[i])<<2)|((val(buf[i+1])&0x30)>>>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; i<str.length; i++){
+      String foo = Integer.toHexString(str[i]&0xff);
+      sb.append("0x"+(foo.length() == 1 ? "0" : "")+foo);
+      if(i+1<str.length)
+        sb.append(":");
+    }
+    return sb.toString();
+  }
+
   static final byte[] empty = str2byte("");
 
   /*
@@ -466,10 +484,43 @@ class Util{
     return result;
   }
 
+  static String checkTilde(String str){
+    try{
+      if(str.startsWith("~")){
+        str = str.replace("~", System.getProperty("user.home"));
+      }
+    }
+    catch(SecurityException e){
+    }
+    return str;
+  }
+
   private static int skipUTF8Char(byte b){
     if((byte)(b&0x80)==0) return 1;
     if((byte)(b&0xe0)==(byte)0xc0) return 2;
     if((byte)(b&0xf0)==(byte)0xe0) return 3;
     return 1;
   }
+
+  static byte[] fromFile(String _file) throws IOException {
+    _file = checkTilde(_file);
+    File file = new File(_file);
+    FileInputStream fis = new FileInputStream(_file);
+    try {
+      byte[] result = new byte[(int)(file.length())];
+      int len=0;
+      while(true){
+        int i=fis.read(result, len, result.length-len);
+        if(i<=0)
+          break;
+        len+=i;
+      }
+      fis.close();
+      return result;
+    }
+    finally {
+      if(fis!=null)
+        fis.close();
+    }
+  }
 }
index 8c2b43b52ee4f02c55561adb506a51a69b1f0908..1042776d42680b7697efa2b5c0156ff174daaba6 100644 (file)
@@ -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:
@@ -55,10 +55,12 @@ public class AES128CBC implements Cipher{
     try{
       SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
       cipher=javax.crypto.Cipher.getInstance("AES/CBC/"+pad);
-      cipher.init((mode==ENCRYPT_MODE?
-                   javax.crypto.Cipher.ENCRYPT_MODE:
-                   javax.crypto.Cipher.DECRYPT_MODE),
-                  keyspec, new IvParameterSpec(iv));
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    keyspec, new IvParameterSpec(iv));
+      }
     }
     catch(Exception e){
       cipher=null;
index 470a896b09ec571f68683c8a0d09ee53da08fc60..6a1839e1d263a8ddfa84471c996cc4829cbced95 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2008-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2008-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:
@@ -55,10 +55,12 @@ public class AES128CTR implements Cipher{
     try{
       SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
       cipher=javax.crypto.Cipher.getInstance("AES/CTR/"+pad);
-      cipher.init((mode==ENCRYPT_MODE?
-                   javax.crypto.Cipher.ENCRYPT_MODE:
-                   javax.crypto.Cipher.DECRYPT_MODE),
-                  keyspec, new IvParameterSpec(iv));
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    keyspec, new IvParameterSpec(iv));
+      }
     }
     catch(Exception e){
       cipher=null;
index 615d49437201a73dcc2c06532c9aa16a084a0624..f08dd7e6ff8eb79eb8093c197758df28f07214fe 100644 (file)
@@ -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:
@@ -54,10 +54,12 @@ public class AES192CBC implements Cipher{
     try{
       SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
       cipher=javax.crypto.Cipher.getInstance("AES/CBC/"+pad);
-      cipher.init((mode==ENCRYPT_MODE?
-                   javax.crypto.Cipher.ENCRYPT_MODE:
-                   javax.crypto.Cipher.DECRYPT_MODE),
-                  keyspec, new IvParameterSpec(iv));
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    keyspec, new IvParameterSpec(iv));
+      }
     }
     catch(Exception e){
       cipher=null;
index 74090bf9831fb8a4ee106bab13ed338dd7a41fbb..93da4780c2fc8d81378763c777af32063b0c7d72 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2008-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2008-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,10 +54,12 @@ public class AES192CTR implements Cipher{
     try{
       SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
       cipher=javax.crypto.Cipher.getInstance("AES/CTR/"+pad);
-      cipher.init((mode==ENCRYPT_MODE?
-                   javax.crypto.Cipher.ENCRYPT_MODE:
-                   javax.crypto.Cipher.DECRYPT_MODE),
-                  keyspec, new IvParameterSpec(iv));
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    keyspec, new IvParameterSpec(iv));
+      }
     }
     catch(Exception e){
       cipher=null;
index 9018a20468d84dfc077d058c07ee9766d6399a42..3dbce6444141a3a294cb304b754c8fe22bc7c539 100644 (file)
@@ -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:
@@ -54,10 +54,12 @@ public class AES256CBC implements Cipher{
     try{
       SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
       cipher=javax.crypto.Cipher.getInstance("AES/CBC/"+pad);
-      cipher.init((mode==ENCRYPT_MODE?
-                   javax.crypto.Cipher.ENCRYPT_MODE:
-                   javax.crypto.Cipher.DECRYPT_MODE),
-                  keyspec, new IvParameterSpec(iv));
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    keyspec, new IvParameterSpec(iv));
+      }
     }
     catch(Exception e){
       cipher=null;
index b7472e96d9eaa94d04dd27d127c5ca1885fb4844..30e17e697885b2de9dc1b1fae1a35ebb4841f95a 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2008-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2008-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,10 +54,12 @@ public class AES256CTR implements Cipher{
     try{
       SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
       cipher=javax.crypto.Cipher.getInstance("AES/CTR/"+pad);
-      cipher.init((mode==ENCRYPT_MODE?
-                   javax.crypto.Cipher.ENCRYPT_MODE:
-                   javax.crypto.Cipher.DECRYPT_MODE),
-                  keyspec, new IvParameterSpec(iv));
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    keyspec, new IvParameterSpec(iv));
+      }
     }
     catch(Exception e){
       cipher=null;
index 9f6537c391f1e6845070409848aadd1dfa55a434..5fd3e7a8e9d5311667735fe3114ddf800d800266 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2008-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2008-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:
@@ -51,10 +51,12 @@ public class ARCFOUR implements Cipher{
     try{
       cipher=javax.crypto.Cipher.getInstance("RC4");
       SecretKeySpec _key = new SecretKeySpec(key, "RC4");
-      cipher.init((mode==ENCRYPT_MODE?
-                  javax.crypto.Cipher.ENCRYPT_MODE:
-                  javax.crypto.Cipher.DECRYPT_MODE),
-                 _key);
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                   _key);
+      }
     }
     catch(Exception e){
       cipher=null;
index d8b4613739a36196ad20d218a245a7fe68855dd2..51f568f915bf731a73d7d478f74cbd17797e9e44 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2008-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2008-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:
@@ -50,10 +50,12 @@ public class ARCFOUR128 implements Cipher{
     try{
       cipher=javax.crypto.Cipher.getInstance("RC4");
       SecretKeySpec _key = new SecretKeySpec(key, "RC4");
-      cipher.init((mode==ENCRYPT_MODE?
-                  javax.crypto.Cipher.ENCRYPT_MODE:
-                  javax.crypto.Cipher.DECRYPT_MODE),
-                 _key);
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    _key);
+      }
       byte[] foo=new byte[1];
       for(int i=0; i<skip; i++){
         cipher.update(foo, 0, 1, foo, 0);
index a4a9f690d4822718ee813a6f238cf97c661d4b9d..226545fcaaffbead69c8798690b52301e64cb0a6 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2008-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2008-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:
@@ -50,10 +50,12 @@ public class ARCFOUR256 implements Cipher{
     try{
       cipher=javax.crypto.Cipher.getInstance("RC4");
       SecretKeySpec _key = new SecretKeySpec(key, "RC4");
-      cipher.init((mode==ENCRYPT_MODE?
-                  javax.crypto.Cipher.ENCRYPT_MODE:
-                  javax.crypto.Cipher.DECRYPT_MODE),
-                 _key);
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    _key);
+      }
       byte[] foo=new byte[1];
       for(int i=0; i<skip; i++){
         cipher.update(foo, 0, 1, foo, 0);
index 3853ab72d3f189e23ad8ca32582b2c0052d348b5..df63fe94c8e30f36d48df213882fa6439747243e 100644 (file)
@@ -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:
@@ -55,10 +55,12 @@ public class BlowfishCBC implements Cipher{
     try{
       SecretKeySpec skeySpec = new SecretKeySpec(key, "Blowfish");
       cipher=javax.crypto.Cipher.getInstance("Blowfish/CBC/"+pad);
-      cipher.init((mode==ENCRYPT_MODE?
-                  javax.crypto.Cipher.ENCRYPT_MODE:
-                  javax.crypto.Cipher.DECRYPT_MODE),
-                 skeySpec, new IvParameterSpec(iv));
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    skeySpec, new IvParameterSpec(iv));
+      }
     }
     catch(Exception e){
       throw e;
index da03c1de0fe485cc441dd0f1b602d2bf13415ac4..d0503ad70fb46e029d388864e7e58ce875e2796f 100644 (file)
@@ -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,6 +33,7 @@ import java.math.BigInteger;
 import java.security.*;
 import javax.crypto.*;
 import javax.crypto.spec.*;
+import com.jcraft.jsch.JSchException;
 
 public class DH implements com.jcraft.jsch.DH{
   BigInteger p;
@@ -47,9 +48,7 @@ public class DH implements com.jcraft.jsch.DH{
   private KeyAgreement myKeyAgree;
   public void init() throws Exception{
     myKpairGen=KeyPairGenerator.getInstance("DH");
-//    myKpairGen=KeyPairGenerator.getInstance("DiffieHellman");
     myKeyAgree=KeyAgreement.getInstance("DH");
-//    myKeyAgree=KeyAgreement.getInstance("DiffieHellman");
   }
   public byte[] getE() throws Exception{
     if(e==null){
@@ -57,8 +56,6 @@ public class DH implements com.jcraft.jsch.DH{
       myKpairGen.initialize(dhSkipParamSpec);
       KeyPair myKpair=myKpairGen.generateKeyPair();
       myKeyAgree.init(myKpair.getPrivate());
-//    BigInteger x=((javax.crypto.interfaces.DHPrivateKey)(myKpair.getPrivate())).getX();
-      byte[] myPubKeyEnc=myKpair.getPublic().getEncoded();
       e=((javax.crypto.interfaces.DHPublicKey)(myKpair.getPublic())).getY();
       e_array=e.toByteArray();
     }
@@ -71,21 +68,33 @@ public class DH implements com.jcraft.jsch.DH{
       PublicKey yourPubKey=myKeyFac.generatePublic(keySpec);
       myKeyAgree.doPhase(yourPubKey, true);
       byte[] mySharedSecret=myKeyAgree.generateSecret();
-      K=new BigInteger(mySharedSecret);
+      K=new BigInteger(1, mySharedSecret);
       K_array=K.toByteArray();
-
-//System.err.println("K.signum(): "+K.signum()+
-//                " "+Integer.toHexString(mySharedSecret[0]&0xff)+
-//                " "+Integer.toHexString(K_array[0]&0xff));
-
       K_array=mySharedSecret;
     }
     return K_array;
   }
-  public void setP(byte[] p){ setP(new BigInteger(p)); }
-  public void setG(byte[] g){ setG(new BigInteger(g)); }
-  public void setF(byte[] f){ setF(new BigInteger(f)); }
+  public void setP(byte[] p){ setP(new BigInteger(1, p)); }
+  public void setG(byte[] g){ setG(new BigInteger(1, g)); }
+  public void setF(byte[] f){ setF(new BigInteger(1, f)); }
   void setP(BigInteger p){this.p=p;}
   void setG(BigInteger g){this.g=g;}
   void setF(BigInteger f){this.f=f;}
+
+  // e, f must be in [1, p-1].
+  public void checkRange() throws Exception {
+    /*
+    checkRange(e);
+    checkRange(f);
+    */
+  }
+
+  private void checkRange(BigInteger tmp) throws Exception {
+    BigInteger one = BigInteger.ONE;
+    BigInteger p_1 = p.subtract(one);
+    // !(1<tmp && tmp<p-1)  We expect tmp is in the range [2, p-2].
+    if(!(one.compareTo(tmp) < 0 && tmp.compareTo(p_1) < 0)){
+      throw new JSchException("invalid DH value");
+   }
+  }
 }
diff --git a/java/com/jcraft/jsch/jce/ECDH256.java b/java/com/jcraft/jsch/jce/ECDH256.java
new file mode 100644 (file)
index 0000000..5efa20d
--- /dev/null
@@ -0,0 +1,36 @@
+/* -*-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;
+public class ECDH256 extends ECDHN implements com.jcraft.jsch.ECDH {
+  public void init() throws Exception {
+    super.init(256);
+  }
+}
diff --git a/java/com/jcraft/jsch/jce/ECDH384.java b/java/com/jcraft/jsch/jce/ECDH384.java
new file mode 100644 (file)
index 0000000..26decd2
--- /dev/null
@@ -0,0 +1,36 @@
+/* -*-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;
+public class ECDH384 extends ECDHN implements com.jcraft.jsch.ECDH {
+  public void init() throws Exception {
+    super.init(384);
+  }
+}
diff --git a/java/com/jcraft/jsch/jce/ECDH521.java b/java/com/jcraft/jsch/jce/ECDH521.java
new file mode 100644 (file)
index 0000000..6a1ba81
--- /dev/null
@@ -0,0 +1,36 @@
+/* -*-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;
+public class ECDH521 extends ECDHN implements com.jcraft.jsch.ECDH {
+  public void init() throws Exception {
+    super.init(521);
+  }
+}
diff --git a/java/com/jcraft/jsch/jce/ECDHN.java b/java/com/jcraft/jsch/jce/ECDHN.java
new file mode 100644 (file)
index 0000000..20119ce
--- /dev/null
@@ -0,0 +1,146 @@
+/* -*-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.math.BigInteger;
+import java.security.*;
+import javax.crypto.*;
+import java.security.spec.*;
+import java.security.interfaces.*;
+public class ECDHN implements com.jcraft.jsch.ECDH {
+  byte[] Q_array;
+  ECPublicKey publicKey;
+
+  private KeyAgreement myKeyAgree;
+  public void init(int size) throws Exception{
+    myKeyAgree = KeyAgreement.getInstance("ECDH");
+    KeyPairGenECDSA kpair = new KeyPairGenECDSA();
+    kpair.init(size);
+    publicKey = kpair.getPublicKey();
+    byte[] r = kpair.getR();
+    byte[] s = kpair.getS();
+    Q_array = toPoint(r, s);
+    myKeyAgree.init(kpair.getPrivateKey());
+  }
+
+  public byte[] getQ() throws Exception{
+    return Q_array;
+  }
+
+  public byte[] getSecret(byte[] r, byte[] s) throws Exception{
+
+    KeyFactory kf = KeyFactory.getInstance("EC");
+    ECPoint w = new ECPoint(new BigInteger(1, r), new BigInteger(1, s));
+    ECPublicKeySpec spec = new ECPublicKeySpec(w, publicKey.getParams());
+    PublicKey theirPublicKey = kf.generatePublic(spec);
+    myKeyAgree.doPhase(theirPublicKey, true);
+    return myKeyAgree.generateSecret();
+  }
+
+  private static BigInteger two = BigInteger.ONE.add(BigInteger.ONE);
+  private static BigInteger three = two.add(BigInteger.ONE);
+
+  // SEC 1: Elliptic Curve Cryptography, Version 2.0
+  // http://www.secg.org/sec1-v2.pdf
+  // 3.2.2.1 Elliptic Curve Public Key Validation Primitive
+  public boolean validate(byte[] r, byte[] s) throws Exception{
+    BigInteger x = new BigInteger(1, r);
+    BigInteger y = new BigInteger(1, s);
+
+    // Step.1
+    //   Check that Q != O
+    ECPoint w = new ECPoint(x, y);
+    if(w.equals(ECPoint.POINT_INFINITY)){
+      return false;
+    }
+
+    // Step.2
+    // If T represents elliptic curve domain parameters over Fp,
+    // check that xQ and yQ are integers in the interval [0, p-1],
+    // and that:
+    //   y^2 = x^3 + x*a + b (mod p)
+
+    ECParameterSpec params = publicKey.getParams();
+    EllipticCurve curve = params.getCurve();
+    BigInteger p=((ECFieldFp)curve.getField()).getP(); //nistp should be Fp. 
+
+    // xQ and yQ should be integers in the interval [0, p-1]
+    BigInteger p_sub1=p.subtract(BigInteger.ONE);
+    if(!(x.compareTo(p_sub1)<=0 && y.compareTo(p_sub1)<=0)){
+      return false;
+    }
+
+    // y^2 = x^3 + x*a + b (mod p)
+    BigInteger tmp=x.multiply(curve.getA()).
+                     add(curve.getB()).
+                     add(x.modPow(three, p)).
+                     mod(p);
+    BigInteger y_2=y.modPow(two, p);
+    if(!(y_2.equals(tmp))){ 
+      return false;
+    }
+
+    // Step.3
+    //   Check that nQ = O.
+    // Unfortunately, JCE does not provide the point multiplication method.
+    /*
+    if(!w.multiply(params.getOrder()).equals(ECPoint.POINT_INFINITY)){
+      return false;
+    }
+    */
+    return true;
+  }
+
+  private 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;
+  }
+  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; i<buf.length; i++) buf[i]=0;
+  }
+}
diff --git a/java/com/jcraft/jsch/jce/HMAC.java b/java/com/jcraft/jsch/jce/HMAC.java
new file mode 100644 (file)
index 0000000..7a301dc
--- /dev/null
@@ -0,0 +1,82 @@
+/* -*-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;
+
+import com.jcraft.jsch.MAC;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+abstract class HMAC implements MAC {
+  protected String name;
+  protected int bsize;
+  protected String algorithm;
+  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, 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;
+  }
+}
index def3747b18db498e7a9c27cb30333fbb1fce0bee..6249c0b6fcb63ed4ebe91b341ef057e1499daea8 100644 (file)
@@ -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";
   }
 }
index a296a5df56564560148431cbe55adb53b8261fa8..b980931654f1bed274d7ac506370f5d5af4e779b 100644 (file)
@@ -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;
-  }
 }
index 13feaabf09514c28942d68129022da38d161d6ba..12f3de5f74fd0022551156567ed472c4ea8f4b4a 100644 (file)
@@ -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";
   }
 }
index e8791762ad5110ca3d35be89c21f7eba6b1f2a3d..ab3b07b91e71f7e8b3b5a632bf0bf0c18ac138a7 100644 (file)
@@ -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 (file)
index 0000000..d3cebf4
--- /dev/null
@@ -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 (file)
index 0000000..4143343
--- /dev/null
@@ -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";
+  }
+}
index 67ad54ebbc6638a79028eb4749224b5f1443ec16..722e70430f72eab0d7f0cfdd4cfb3b4c14be99b3 100644 (file)
@@ -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 (file)
index 0000000..54b1e8e
--- /dev/null
@@ -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<r.length){
+      d=insert0(d);
+    }
+  }
+  public byte[] getD(){return d;}
+  public byte[] getR(){return r;}
+  public byte[] getS(){return s;}
+  ECPublicKey getPublicKey(){ return pubKey; }
+  ECPrivateKey getPrivateKey(){ return prvKey; }
+
+  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 || (buf[1]&0x80)==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; i<buf.length; i++) buf[i]=0;
+  }
+}
index 543f0f79f816fb993d7e51cdebefcd941a0c1e97..8d4b86ef997d74882b71e5a9a9d7de1add86fc9c 100644 (file)
@@ -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:
index 538ae340144f7f3dd4c901d8f96b432cffc50153..96db7ae77b975d2d82a90d86c52982cfb4c52ac5 100644 (file)
@@ -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/PBKDF.java b/java/com/jcraft/jsch/jce/PBKDF.java
new file mode 100644 (file)
index 0000000..7b03bf6
--- /dev/null
@@ -0,0 +1,59 @@
+/* -*-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.jce;
+
+import com.jcraft.jsch.HASH;
+
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.SecretKeyFactory;
+import java.security.spec.InvalidKeySpecException;
+import java.security.NoSuchAlgorithmException;
+
+public class PBKDF implements com.jcraft.jsch.PBKDF{
+  public byte[] getKey(byte[] _pass, byte[] salt, int iterations, int size){
+    char[] pass=new char[_pass.length];
+    for(int i = 0; i < _pass.length; i++){
+      pass[i]=(char)(_pass[i]&0xff);
+    }
+    try {
+      PBEKeySpec spec =
+        new PBEKeySpec(pass, salt, iterations, size*8);
+      SecretKeyFactory skf =
+        SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
+      byte[] key = skf.generateSecret(spec).getEncoded();
+      return key;
+    }
+    catch(InvalidKeySpecException e){
+    }
+    catch(NoSuchAlgorithmException e){
+    }
+    return null;
+  }
+}
index 8668a01af7d610b9ba4b0d1eaeeb7e993f42c3cf..aebdaa52eb74a1422aada2898f71f2a068f7464e 100644 (file)
@@ -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:
index 08fce4b098edef185300f651e1870a13d76ddedd..2bc6c97fb8133058abec550101d80a986dc3e02e 100644 (file)
@@ -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/SHA256.java b/java/com/jcraft/jsch/jce/SHA256.java
new file mode 100644 (file)
index 0000000..70a88b0
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*-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.jce;
+
+import com.jcraft.jsch.HASH;
+
+import java.security.*;
+
+public class SHA256 implements HASH {
+  MessageDigest md;
+  public int getBlockSize(){return 32;}
+  public void init() throws Exception {
+    try{ md=MessageDigest.getInstance("SHA-256"); }
+    catch(Exception e){
+      System.err.println(e);
+    }
+  }
+  public void update(byte[] foo, int start, int len) throws Exception {
+    md.update(foo, start, len);
+  }
+  public byte[] digest() throws Exception {
+    return md.digest();
+  }
+}
diff --git a/java/com/jcraft/jsch/jce/SHA384.java b/java/com/jcraft/jsch/jce/SHA384.java
new file mode 100644 (file)
index 0000000..eeb5b1e
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*-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.*;
+
+public class SHA384 implements com.jcraft.jsch.HASH {
+  MessageDigest md;
+  public int getBlockSize(){return 48;}
+  public void init() throws Exception {
+    try{ md=MessageDigest.getInstance("SHA-384"); }
+    catch(Exception e){
+      System.err.println(e);
+    }
+  }
+  public void update(byte[] foo, int start, int len) throws Exception {
+    md.update(foo, start, len);
+  }
+  public byte[] digest() throws Exception {
+    return md.digest();
+  }
+}
diff --git a/java/com/jcraft/jsch/jce/SHA512.java b/java/com/jcraft/jsch/jce/SHA512.java
new file mode 100644 (file)
index 0000000..d56eafd
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*-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.*;
+
+public class SHA512 implements com.jcraft.jsch.HASH {
+  MessageDigest md;
+  public int getBlockSize(){return 64;}
+  public void init() throws Exception {
+    try{ md=MessageDigest.getInstance("SHA-512"); }
+    catch(Exception e){
+      System.err.println(e);
+    }
+  }
+  public void update(byte[] foo, int start, int len) throws Exception {
+    md.update(foo, start, len);
+  }
+  public byte[] digest() throws Exception {
+    return md.digest();
+  }
+}
index 262dfc5e628054521c4dfac232570d85f26cd875..0f7ec4a521cc75beaa0328eaa88a68b4e0f1af40 100644 (file)
@@ -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/SignatureECDSA.java b/java/com/jcraft/jsch/jce/SignatureECDSA.java
new file mode 100644 (file)
index 0000000..1f3e0aa
--- /dev/null
@@ -0,0 +1,186 @@
+/* -*-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.math.BigInteger;
+import java.security.*;
+import java.security.spec.*;
+import com.jcraft.jsch.Buffer;
+
+public class SignatureECDSA implements com.jcraft.jsch.SignatureECDSA {
+
+  Signature signature;
+  KeyFactory keyFactory;
+
+  public void init() throws Exception{
+    signature=java.security.Signature.getInstance("SHA256withECDSA");
+    keyFactory=KeyFactory.getInstance("EC");
+  }     
+
+  public void setPubKey(byte[] r, byte[] s) throws Exception{
+
+    // r and s must be unsigned values.
+    r=insert0(r);
+    s=insert0(s);
+
+    String name="secp256r1";
+    if(r.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; i<buf.length; i++) buf[i]=0;
+  }
+}
index 50d8b5a8fca9f3d7c112fb3c0fdd3cd5c824a046..07dff18c2536ca7790807e7b3f1e8789614fa595 100644 (file)
@@ -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:
index 2cbf9b75c3d60e24932beb344989710d2166a22f..ec084959c8d70c0567109ace87b2d3ab20084523 100644 (file)
@@ -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:
@@ -67,10 +67,12 @@ public class TripleDESCBC implements Cipher{
       DESedeKeySpec keyspec=new DESedeKeySpec(key);
       SecretKeyFactory keyfactory=SecretKeyFactory.getInstance("DESede");
       SecretKey _key=keyfactory.generateSecret(keyspec);
-      cipher.init((mode==ENCRYPT_MODE?
-                  javax.crypto.Cipher.ENCRYPT_MODE:
-                  javax.crypto.Cipher.DECRYPT_MODE),
-                 _key, new IvParameterSpec(iv));
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    _key, new IvParameterSpec(iv));
+      }
     }
     catch(Exception e){
       cipher=null;
index 899f03bd67eb04107e85110f881cce8e49bfbd14..3793e9dd3a26575e1258a00452702a9401815eec 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
 /*
-Copyright (c) 2008-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2008-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:
@@ -67,10 +67,12 @@ public class TripleDESCTR implements Cipher{
       DESedeKeySpec keyspec=new DESedeKeySpec(key);
       SecretKeyFactory keyfactory=SecretKeyFactory.getInstance("DESede");
       SecretKey _key=keyfactory.generateSecret(keyspec);
-      cipher.init((mode==ENCRYPT_MODE?
-                  javax.crypto.Cipher.ENCRYPT_MODE:
-                  javax.crypto.Cipher.DECRYPT_MODE),
-                 _key, new IvParameterSpec(iv));
+      synchronized(javax.crypto.Cipher.class){
+        cipher.init((mode==ENCRYPT_MODE?
+                     javax.crypto.Cipher.ENCRYPT_MODE:
+                     javax.crypto.Cipher.DECRYPT_MODE),
+                    _key, new IvParameterSpec(iv));
+      }
     }
     catch(Exception e){
       cipher=null;
index cb1f317025060f92b19cd38efb92325650f7a19a..05963febfb002858086dc69bccf3038dedb82430 100644 (file)
@@ -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.jcraft;
 import com.jcraft.jzlib.*;
 import com.jcraft.jsch.*;
 
-@SuppressWarnings({"deprecation"})
 public class Compression implements com.jcraft.jsch.Compression {
   static private final int BUF_SIZE=4096;
   private final int buffer_margin=32+20; // AES256 + HMACSHA1
index 9aedc27f0c73131d5ddc14adeb88d4574335a528..34f3cdd4c136b3b28720863c194994e7578c36b3 100644 (file)
@@ -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:
@@ -58,6 +58,7 @@ class HMAC{
 
   public int getBlockSize(){return bsize;};
   public void init(byte[] key) throws Exception{
+    md.reset();
     if(key.length>bsize){
       byte[] tmp=new byte[bsize];
       System.arraycopy(key, 0, tmp, 0, bsize);   
index 90960113190313bdd2648d080f24eb1f4a8f1763..850e81dbecc0522101a12ec980b41bb54d174169 100644 (file)
@@ -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:
index 95c6f60d620929441b9cd48fc4f2b36067fd8f16..565939394aeee9ca99ce574b30e3a307817db028 100644 (file)
@@ -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:
index ea9eccf1cfb98a4b2cc21290c8f68b295055abaa..6dbb9de0e195dbf39603ed83697c3f4cf2525910 100644 (file)
@@ -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:
index 86a81b5b8d55758efb8265a2fe91b9db85ed835e..0a49f5485d963915354601fd664f64236d17c4e4 100644 (file)
@@ -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:
index 9ee1560e9cf58543170315e5ce23f6c8af3fc516..8f72f35d5255e2458f81b6edd170107da64f26fb 100644 (file)
@@ -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:
index baaac9beba0142aade8ad132aa07713d0ad833c5..cfda0f0bc2534854cf4e415776370917b89e2303 100644 (file)
@@ -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 (file)
index 0000000..ce0580d
--- /dev/null
@@ -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 (file)
index 0000000..4c9f0d2
--- /dev/null
@@ -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 (file)
index 0000000..0beef40
--- /dev/null
@@ -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 (file)
index 0000000..5d29dca
--- /dev/null
@@ -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<len);
+    return n;
+  }
+}
\ No newline at end of file
diff --git a/java/com/jcraft/jzlib/GZIPOutputStream.java b/java/com/jcraft/jzlib/GZIPOutputStream.java
new file mode 100644 (file)
index 0000000..54dcf8e
--- /dev/null
@@ -0,0 +1,90 @@
+/* -*-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 GZIPOutputStream extends DeflaterOutputStream {
+
+  public GZIPOutputStream(OutputStream out) throws IOException {
+    this(out, DEFAULT_BUFSIZE);
+  }
+
+  public GZIPOutputStream(OutputStream out, int size) throws IOException {
+    this(out, size, true);
+  }
+
+  public GZIPOutputStream(OutputStream out, 
+                          int size,
+                          boolean close_out) throws IOException {
+    this(out,
+         new Deflater(JZlib.Z_DEFAULT_COMPRESSION, 15+16),
+         size, close_out);
+    mydeflater=true; 
+  }
+
+  public GZIPOutputStream(OutputStream out, 
+                          Deflater deflater,
+                          int size,
+                          boolean close_out) throws IOException{
+    super(out, deflater, size, close_out);
+  }
+
+
+  private void check() throws GZIPException {
+    if(deflater.dstate.status != 42 /*INIT_STATUS*/)
+      throw new GZIPException("header is already written.");
+  }
+
+  public void setModifiedTime(long mtime) throws GZIPException {
+    check();
+    deflater.dstate.getGZIPHeader().setModifiedTime(mtime);
+  }
+
+  public void setOS(int os) throws GZIPException {
+    check();
+    deflater.dstate.getGZIPHeader().setOS(os);
+  }
+
+  public void setName(String name) throws GZIPException {
+    check();
+    deflater.dstate.getGZIPHeader().setName(name);
+  }
+
+  public void setComment(String comment) throws GZIPException {
+    check();
+    deflater.dstate.getGZIPHeader().setComment(comment);
+  }
+
+  public long getCRC() throws GZIPException {
+    if(deflater.dstate.status != 666 /*FINISH_STATE*/)
+      throw new GZIPException("checksum is not calculated yet.");
+    return deflater.dstate.getGZIPHeader().getCRC();
+  }
+}
index 6aa6240cc36048adf392315d774f9849c5df5e43..a96933254c2222928677e99544071d7d4e3f605c 100644 (file)
@@ -85,6 +85,8 @@ final class Inflate{
   static final private int HCRC=22;
   static final private int FLAGS=23;
 
+  static final int INFLATE_ANY=0x40000000;
+
   int mode;                            // current inflate mode
 
   // mode dependent information
@@ -99,6 +101,11 @@ final class Inflate{
 
   // mode independent information
   int  wrap;          // flag for no wrapper
+                      // 0: no wrapper
+                      // 1: zlib header
+                      // 2: gzip header
+                      // 4: auto detection
+
   int wbits;            // log2(window size)  (8..15, defaults to 15)
 
   InfBlocks blocks;     // current inflate_blocks state
@@ -143,6 +150,16 @@ final class Inflate{
     if(w < 0){
       w = - w;
     }
+    else if((w&INFLATE_ANY) != 0){
+      wrap = 4;
+      w &= ~INFLATE_ANY;
+      if(w < 48)
+        w &= 15;
+    }
+    else if((w & ~31) != 0) { // for example, DEF_WBITS + 32
+      wrap = 4;               // zlib and gzip wrapped data should be accepted.
+      w &= 15;
+    }
     else {
       wrap = (w >> 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 (file)
index 0000000..0fb0b09
--- /dev/null
@@ -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 (file)
index 0000000..0420582
--- /dev/null
@@ -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
index 8fd98ea7f4efd025f8850497c681495977628bda..a4bb3410fd3f7bc40d200001c8cbe62cb134bc54 100644 (file)
@@ -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;
index 40b6ba87870f647cea0f4459a34c9be96f640768..38cb40f2aa3f6828ba94452ae58df4454da9a490 100644 (file)
@@ -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;
index 0054645e51150a9f9452d6f1f10521de1e3e63d5..cbd38e1519021efe751ecdc68da703db4f294d29 100644 (file)
@@ -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;
   }
 
index dd0a5256d36da583f8f99d6a2c46bde2af51e318..0afa4fd0447f9b60ed9065b4b2545ce414d9f987 100644 (file)
@@ -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);
index 308bb8a1e5e098b91ab52394de6e6b5f98587d68..424b74b78ec333e458a0547c014829bfea5e5ba3 100644 (file)
@@ -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; -*- */\r
+/*\r
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions are met:\r
+\r
+  1. Redistributions of source code must retain the above copyright notice,\r
+     this list of conditions and the following disclaimer.\r
+\r
+  2. Redistributions in binary form must reproduce the above copyright \r
+     notice, this list of conditions and the following disclaimer in \r
+     the documentation and/or other materials provided with the distribution.\r
+\r
+  3. The names of the authors may not be used to endorse or promote products\r
+     derived from this software without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,\r
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\r
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,\r
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+/*\r
+ * This program is based on zlib-1.1.3, so all credit should go authors\r
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)\r
+ * and contributors of zlib.\r
+ */\r
+\r
+package com.jcraft.jzlib;\r
+\r
+public class ZStreamException extends java.io.IOException {\r
+  public ZStreamException() {\r
+    super();\r
+  }\r
+  public ZStreamException(String s) {\r
+    super(s);\r
+  }\r
+}\r