aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian P. Hinz <bphinz@users.sf.net>2015-12-26 21:48:11 -0500
committerBrian P. Hinz <bphinz@users.sf.net>2015-12-26 21:53:45 -0500
commitce48cc8962233d97a39d1f61d661d4e57b7eb1e4 (patch)
tree812a0c1d02173325415b014d8523bd46394a9e90
parent928bd74249e737dc2d00d6fc95559f6a26dbb6ab (diff)
downloadtigervnc-ce48cc8962233d97a39d1f61d661d4e57b7eb1e4.tar.gz
tigervnc-ce48cc8962233d97a39d1f61d661d4e57b7eb1e4.zip
Upgrade in-tree jsch and jzlib to latest upstream versions
-rw-r--r--java/CMakeLists.txt47
-rw-r--r--java/com/jcraft/jsch/Buffer.java49
-rw-r--r--java/com/jcraft/jsch/ChangeLog629
-rw-r--r--java/com/jcraft/jsch/Channel.java137
-rw-r--r--java/com/jcraft/jsch/ChannelAgentForwarding.java5
-rw-r--r--java/com/jcraft/jsch/ChannelDirectTCPIP.java21
-rw-r--r--java/com/jcraft/jsch/ChannelExec.java2
-rw-r--r--java/com/jcraft/jsch/ChannelForwardedTCPIP.java161
-rw-r--r--java/com/jcraft/jsch/ChannelSession.java19
-rw-r--r--java/com/jcraft/jsch/ChannelSftp.java440
-rw-r--r--java/com/jcraft/jsch/ChannelShell.java2
-rw-r--r--java/com/jcraft/jsch/ChannelSubsystem.java2
-rw-r--r--java/com/jcraft/jsch/ChannelX11.java3
-rw-r--r--java/com/jcraft/jsch/Cipher.java2
-rw-r--r--java/com/jcraft/jsch/CipherNone.java2
-rw-r--r--java/com/jcraft/jsch/Compression.java2
-rw-r--r--java/com/jcraft/jsch/ConfigRepository.java55
-rw-r--r--java/com/jcraft/jsch/DH.java6
-rw-r--r--java/com/jcraft/jsch/DHEC256.java37
-rw-r--r--java/com/jcraft/jsch/DHEC384.java37
-rw-r--r--java/com/jcraft/jsch/DHEC521.java37
-rw-r--r--java/com/jcraft/jsch/DHECN.java187
-rw-r--r--java/com/jcraft/jsch/DHG1.java129
-rw-r--r--java/com/jcraft/jsch/DHG14.java110
-rw-r--r--java/com/jcraft/jsch/DHGEX.java158
-rw-r--r--java/com/jcraft/jsch/DHGEX256.java36
-rw-r--r--java/com/jcraft/jsch/ECDH.java37
-rw-r--r--java/com/jcraft/jsch/ForwardedTCPIPDaemon.java2
-rw-r--r--java/com/jcraft/jsch/GSSContext.java2
-rw-r--r--java/com/jcraft/jsch/HASH.java2
-rw-r--r--java/com/jcraft/jsch/HostKey.java50
-rw-r--r--java/com/jcraft/jsch/HostKeyRepository.java52
-rw-r--r--java/com/jcraft/jsch/IO.java2
-rw-r--r--java/com/jcraft/jsch/Identity.java44
-rw-r--r--java/com/jcraft/jsch/IdentityFile.java950
-rw-r--r--java/com/jcraft/jsch/IdentityRepository.java79
-rw-r--r--java/com/jcraft/jsch/JSch.java340
-rw-r--r--java/com/jcraft/jsch/JSchAuthCancelException.java2
-rw-r--r--java/com/jcraft/jsch/JSchException.java2
-rw-r--r--java/com/jcraft/jsch/JSchPartialAuthException.java2
-rw-r--r--java/com/jcraft/jsch/KeyExchange.java199
-rw-r--r--java/com/jcraft/jsch/KeyPair.java660
-rw-r--r--java/com/jcraft/jsch/KeyPairDSA.java135
-rw-r--r--java/com/jcraft/jsch/KeyPairECDSA.java391
-rw-r--r--java/com/jcraft/jsch/KeyPairGenDSA.java2
-rw-r--r--java/com/jcraft/jsch/KeyPairGenECDSA.java37
-rw-r--r--java/com/jcraft/jsch/KeyPairGenRSA.java2
-rw-r--r--java/com/jcraft/jsch/KeyPairPKCS8.java363
-rw-r--r--java/com/jcraft/jsch/KeyPairRSA.java268
-rw-r--r--java/com/jcraft/jsch/KnownHosts.java173
-rw-r--r--java/com/jcraft/jsch/LICENSE.txt2
-rw-r--r--java/com/jcraft/jsch/LocalIdentityRepository.java66
-rw-r--r--java/com/jcraft/jsch/Logger.java2
-rw-r--r--java/com/jcraft/jsch/MAC.java2
-rw-r--r--java/com/jcraft/jsch/OpenSSHConfig.java264
-rw-r--r--java/com/jcraft/jsch/PBKDF.java34
-rw-r--r--java/com/jcraft/jsch/Packet.java2
-rw-r--r--java/com/jcraft/jsch/PortWatcher.java22
-rw-r--r--java/com/jcraft/jsch/Proxy.java2
-rw-r--r--java/com/jcraft/jsch/ProxyHTTP.java2
-rw-r--r--java/com/jcraft/jsch/ProxySOCKS4.java2
-rw-r--r--java/com/jcraft/jsch/ProxySOCKS5.java2
-rw-r--r--java/com/jcraft/jsch/README16
-rw-r--r--java/com/jcraft/jsch/Random.java2
-rw-r--r--java/com/jcraft/jsch/Request.java2
-rw-r--r--java/com/jcraft/jsch/RequestAgentForwarding.java2
-rw-r--r--java/com/jcraft/jsch/RequestEnv.java2
-rw-r--r--java/com/jcraft/jsch/RequestExec.java2
-rw-r--r--java/com/jcraft/jsch/RequestPtyReq.java2
-rw-r--r--java/com/jcraft/jsch/RequestSftp.java2
-rw-r--r--java/com/jcraft/jsch/RequestShell.java2
-rw-r--r--java/com/jcraft/jsch/RequestSignal.java2
-rw-r--r--java/com/jcraft/jsch/RequestSubsystem.java2
-rw-r--r--java/com/jcraft/jsch/RequestWindowChange.java2
-rw-r--r--java/com/jcraft/jsch/RequestX11.java2
-rw-r--r--java/com/jcraft/jsch/ServerSocketFactory.java2
-rw-r--r--java/com/jcraft/jsch/Session.java922
-rw-r--r--java/com/jcraft/jsch/SftpATTRS.java49
-rw-r--r--java/com/jcraft/jsch/SftpException.java2
-rw-r--r--java/com/jcraft/jsch/SftpProgressMonitor.java2
-rw-r--r--java/com/jcraft/jsch/SftpStatVFS.java122
-rw-r--r--java/com/jcraft/jsch/Signature.java37
-rw-r--r--java/com/jcraft/jsch/SignatureDSA.java8
-rw-r--r--java/com/jcraft/jsch/SignatureECDSA.java35
-rw-r--r--java/com/jcraft/jsch/SignatureRSA.java8
-rw-r--r--java/com/jcraft/jsch/SocketFactory.java2
-rw-r--r--java/com/jcraft/jsch/UIKeyboardInteractive.java2
-rw-r--r--java/com/jcraft/jsch/UserAuth.java2
-rw-r--r--java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java2
-rw-r--r--java/com/jcraft/jsch/UserAuthKeyboardInteractive.java4
-rw-r--r--java/com/jcraft/jsch/UserAuthNone.java2
-rw-r--r--java/com/jcraft/jsch/UserAuthPassword.java2
-rw-r--r--java/com/jcraft/jsch/UserAuthPublicKey.java33
-rw-r--r--java/com/jcraft/jsch/UserInfo.java2
-rw-r--r--java/com/jcraft/jsch/Util.java83
-rw-r--r--java/com/jcraft/jsch/jce/AES128CBC.java12
-rw-r--r--java/com/jcraft/jsch/jce/AES128CTR.java12
-rw-r--r--java/com/jcraft/jsch/jce/AES192CBC.java12
-rw-r--r--java/com/jcraft/jsch/jce/AES192CTR.java12
-rw-r--r--java/com/jcraft/jsch/jce/AES256CBC.java12
-rw-r--r--java/com/jcraft/jsch/jce/AES256CTR.java12
-rw-r--r--java/com/jcraft/jsch/jce/ARCFOUR.java12
-rw-r--r--java/com/jcraft/jsch/jce/ARCFOUR128.java12
-rw-r--r--java/com/jcraft/jsch/jce/ARCFOUR256.java12
-rw-r--r--java/com/jcraft/jsch/jce/BlowfishCBC.java12
-rw-r--r--java/com/jcraft/jsch/jce/DH.java37
-rw-r--r--java/com/jcraft/jsch/jce/ECDH256.java36
-rw-r--r--java/com/jcraft/jsch/jce/ECDH384.java36
-rw-r--r--java/com/jcraft/jsch/jce/ECDH521.java36
-rw-r--r--java/com/jcraft/jsch/jce/ECDHN.java146
-rw-r--r--java/com/jcraft/jsch/jce/HMAC.java82
-rw-r--r--java/com/jcraft/jsch/jce/HMACMD5.java45
-rw-r--r--java/com/jcraft/jsch/jce/HMACMD596.java49
-rw-r--r--java/com/jcraft/jsch/jce/HMACSHA1.java49
-rw-r--r--java/com/jcraft/jsch/jce/HMACSHA196.java49
-rw-r--r--java/com/jcraft/jsch/jce/HMACSHA256.java38
-rw-r--r--java/com/jcraft/jsch/jce/HMACSHA512.java38
-rw-r--r--java/com/jcraft/jsch/jce/KeyPairGenDSA.java2
-rw-r--r--java/com/jcraft/jsch/jce/KeyPairGenECDSA.java96
-rw-r--r--java/com/jcraft/jsch/jce/KeyPairGenRSA.java2
-rw-r--r--java/com/jcraft/jsch/jce/MD5.java2
-rw-r--r--java/com/jcraft/jsch/jce/PBKDF.java59
-rw-r--r--java/com/jcraft/jsch/jce/Random.java2
-rw-r--r--java/com/jcraft/jsch/jce/SHA1.java2
-rw-r--r--java/com/jcraft/jsch/jce/SHA256.java51
-rw-r--r--java/com/jcraft/jsch/jce/SHA384.java49
-rw-r--r--java/com/jcraft/jsch/jce/SHA512.java49
-rw-r--r--java/com/jcraft/jsch/jce/SignatureDSA.java2
-rw-r--r--java/com/jcraft/jsch/jce/SignatureECDSA.java186
-rw-r--r--java/com/jcraft/jsch/jce/SignatureRSA.java2
-rw-r--r--java/com/jcraft/jsch/jce/TripleDESCBC.java12
-rw-r--r--java/com/jcraft/jsch/jce/TripleDESCTR.java12
-rw-r--r--java/com/jcraft/jsch/jcraft/Compression.java3
-rw-r--r--java/com/jcraft/jsch/jcraft/HMAC.java3
-rw-r--r--java/com/jcraft/jsch/jcraft/HMACMD5.java2
-rw-r--r--java/com/jcraft/jsch/jcraft/HMACMD596.java2
-rw-r--r--java/com/jcraft/jsch/jcraft/HMACSHA1.java2
-rw-r--r--java/com/jcraft/jsch/jcraft/HMACSHA196.java2
-rw-r--r--java/com/jcraft/jsch/jgss/GSSContextKrb5.java2
-rw-r--r--java/com/jcraft/jzlib/Deflate.java20
-rw-r--r--java/com/jcraft/jzlib/Deflater.java171
-rw-r--r--java/com/jcraft/jzlib/DeflaterOutputStream.java181
-rw-r--r--java/com/jcraft/jzlib/GZIPException.java44
-rw-r--r--java/com/jcraft/jzlib/GZIPInputStream.java145
-rw-r--r--java/com/jcraft/jzlib/GZIPOutputStream.java90
-rw-r--r--java/com/jcraft/jzlib/Inflate.java46
-rw-r--r--java/com/jcraft/jzlib/Inflater.java168
-rw-r--r--java/com/jcraft/jzlib/InflaterInputStream.java247
-rw-r--r--java/com/jcraft/jzlib/JZlib.java9
-rw-r--r--java/com/jcraft/jzlib/Tree.java15
-rw-r--r--java/com/jcraft/jzlib/ZInputStream.java2
-rw-r--r--java/com/jcraft/jzlib/ZStream.java36
-rw-r--r--java/com/jcraft/jzlib/ZStreamException.java88
153 files changed, 8073 insertions, 2368 deletions
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index 8dd09d1b..a076d958 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -36,9 +36,15 @@ set(JAVA_CLASSES "")
set(JSCH_CLASSNAMES
DH
+ DHEC256
+ DHEC384
+ DHEC521
+ DHECN
+ DHGEX256
DHG1
DHG14
DHGEX
+ ECDH
JSch
Session
UserAuth
@@ -47,28 +53,41 @@ set(JSCH_CLASSNAMES
UserAuthPublicKey
UserAuthNone
jce/AES128CBC
- jce/AES192CTR
- jce/ARCFOUR128
- jce/BlowfishCBC
- jce/HMACMD5
- jce/KeyPairGenDSA
- jce/Random
- jce/SignatureRSA
jce/AES128CTR
- jce/AES256CBC
- jce/ARCFOUR256
- jce/DH
- jce/HMACSHA196
- jce/KeyPairGenRSA
- jce/SHA1
- jce/TripleDESCBC
jce/AES192CBC
+ jce/AES192CTR
+ jce/AES256CBC
jce/AES256CTR
jce/ARCFOUR
+ jce/ARCFOUR128
+ jce/ARCFOUR256
+ jce/BlowfishCBC
+ jce/DH
+ jce/ECDH256
+ jce/ECDH384
+ jce/ECDH521
+ jce/ECDHN
+ jce/HMAC
+ jce/HMACMD5
jce/HMACMD596
jce/HMACSHA1
+ jce/HMACSHA196
+ jce/HMACSHA256
+ jce/HMACSHA512
+ jce/KeyPairGenDSA
+ jce/KeyPairGenECDSA
+ jce/KeyPairGenRSA
jce/MD5
+ jce/PBKDF
+ jce/Random
+ jce/SHA1
+ jce/SHA256
+ jce/SHA384
+ jce/SHA512
jce/SignatureDSA
+ jce/SignatureECDSA
+ jce/SignatureRSA
+ jce/TripleDESCBC
jce/TripleDESCTR
jcraft/Compression
jcraft/HMAC
diff --git a/java/com/jcraft/jsch/Buffer.java b/java/com/jcraft/jsch/Buffer.java
index a3135a15..c54e4292 100644
--- a/java/com/jcraft/jsch/Buffer.java
+++ b/java/com/jcraft/jsch/Buffer.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -213,13 +213,56 @@ public class Buffer{
}
void checkFreeSize(int n){
- if(buffer.length<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"
diff --git a/java/com/jcraft/jsch/ChangeLog b/java/com/jcraft/jsch/ChangeLog
index 7642c28a..a88f8332 100644
--- a/java/com/jcraft/jsch/ChangeLog
+++ b/java/com/jcraft/jsch/ChangeLog
@@ -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.
diff --git a/java/com/jcraft/jsch/Channel.java b/java/com/jcraft/jsch/Channel.java
index 73cc4dbf..8c060dd6 100644
--- a/java/com/jcraft/jsch/Channel.java
+++ b/java/com/jcraft/jsch/Channel.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -35,7 +35,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
-@SuppressWarnings({"rawtypes","unchecked"})
+
public abstract class Channel implements Runnable{
static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION= 91;
@@ -192,29 +192,38 @@ public abstract class Channel implements Runnable{
io.setExtOutputStream(out, dontclose);
}
public InputStream getInputStream() throws IOException {
- PipedInputStream in=
+ int max_input_buffer_size = 32*1024;
+ try {
+ max_input_buffer_size =
+ Integer.parseInt(getSession().getConfig("max_input_buffer_size"));
+ }
+ catch(Exception e){}
+ PipedInputStream in =
new MyPipedInputStream(
- 32*1024 // this value should be customizable.
+ 32*1024, // this value should be customizable.
+ max_input_buffer_size
);
- io.setOutputStream(new PassiveOutputStream(in), false);
+ boolean resizable = 32*1024<max_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);
}
diff --git a/java/com/jcraft/jsch/ChannelAgentForwarding.java b/java/com/jcraft/jsch/ChannelAgentForwarding.java
index 52e2db19..32db395d 100644
--- a/java/com/jcraft/jsch/ChannelAgentForwarding.java
+++ b/java/com/jcraft/jsch/ChannelAgentForwarding.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -32,7 +32,6 @@ package com.jcraft.jsch;
import java.net.*;
import java.util.Vector;
-@SuppressWarnings({"rawtypes"})
class ChannelAgentForwarding extends Channel{
static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
@@ -122,7 +121,7 @@ class ChannelAgentForwarding extends Channel{
throw new java.io.IOException(e.toString());
}
- IdentityRepository irepo = _session.jsch.getIdentityRepository();
+ IdentityRepository irepo = _session.getIdentityRepository();
UserInfo userinfo=_session.getUserInfo();
mbuf.reset();
diff --git a/java/com/jcraft/jsch/ChannelDirectTCPIP.java b/java/com/jcraft/jsch/ChannelDirectTCPIP.java
index c8af6a2b..dde42442 100644
--- a/java/com/jcraft/jsch/ChannelDirectTCPIP.java
+++ b/java/com/jcraft/jsch/ChannelDirectTCPIP.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -54,7 +54,8 @@ public class ChannelDirectTCPIP extends Channel{
io=new IO();
}
- public void connect() throws JSchException{
+ public void connect(int connectTimeout) throws JSchException{
+ this.connectTimeout=connectTimeout;
try{
Session _session=getSession();
if(!_session.isConnected()){
@@ -69,6 +70,9 @@ public class ChannelDirectTCPIP extends Channel{
}
thread.start();
}
+ else {
+ sendChannelOpen();
+ }
}
catch(Exception e){
io.close();
@@ -116,7 +120,16 @@ public class ChannelDirectTCPIP extends Channel{
}
}
catch(Exception e){
+ // Whenever an exception is thrown by sendChannelOpen(),
+ // 'connected' is false.
+ if(!connected){
+ connected=true;
+ }
+ disconnect();
+ return;
}
+
+ eof();
disconnect();
}
@@ -133,7 +146,9 @@ public class ChannelDirectTCPIP extends Channel{
public void setOrgPort(int foo){this.originator_port=foo;}
protected Packet genChannelOpenPacket(){
- Buffer buf = new Buffer(150);
+ Buffer buf = new Buffer(50 + // 6 + 4*8 + 12
+ host.length() + originator_IP_address.length() +
+ Session.buffer_margin);
Packet packet = new Packet(buf);
// byte SSH_MSG_CHANNEL_OPEN(90)
// string channel type //
diff --git a/java/com/jcraft/jsch/ChannelExec.java b/java/com/jcraft/jsch/ChannelExec.java
index 45322b63..10722c22 100644
--- a/java/com/jcraft/jsch/ChannelExec.java
+++ b/java/com/jcraft/jsch/ChannelExec.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/ChannelForwardedTCPIP.java b/java/com/jcraft/jsch/ChannelForwardedTCPIP.java
index 39972e19..41f9bebf 100644
--- a/java/com/jcraft/jsch/ChannelForwardedTCPIP.java
+++ b/java/com/jcraft/jsch/ChannelForwardedTCPIP.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,11 +31,11 @@ package com.jcraft.jsch;
import java.net.*;
import java.io.*;
+import java.util.Vector;
-@SuppressWarnings({"rawtypes","unchecked"})
public class ChannelForwardedTCPIP extends Channel{
- static java.util.Vector pool=new java.util.Vector();
+ private static Vector pool = new Vector();
static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
//static private final int LOCAL_WINDOW_SIZE_MAX=0x100000;
@@ -43,12 +43,9 @@ public class ChannelForwardedTCPIP extends Channel{
static private final int TIMEOUT=10*1000;
- SocketFactory factory=null;
private Socket socket=null;
private ForwardedTCPIPDaemon daemon=null;
- String target;
- int lport;
- int rport;
+ private Config config = null;
ChannelForwardedTCPIP(){
super();
@@ -61,8 +58,9 @@ public class ChannelForwardedTCPIP extends Channel{
public void run(){
try{
- if(lport==-1){
- Class c=Class.forName(target);
+ if(config instanceof ConfigDaemon){
+ ConfigDaemon _config = (ConfigDaemon)config;
+ Class c=Class.forName(_config.target);
daemon=(ForwardedTCPIPDaemon)c.newInstance();
PipedOutputStream out=new PipedOutputStream();
@@ -71,15 +69,14 @@ public class ChannelForwardedTCPIP extends Channel{
), false);
daemon.setChannel(this, getInputStream(), out);
- Object[] foo=getPort(getSession(), rport);
- daemon.setArg((Object[])foo[3]);
-
+ daemon.setArg(_config.arg);
new Thread(daemon).start();
}
else{
- socket=(factory==null) ?
- Util.createSocket(target, lport, TIMEOUT) :
- factory.createSocket(target, lport);
+ ConfigLHost _config = (ConfigLHost)config;
+ socket=(_config.factory==null) ?
+ Util.createSocket(_config.target, _config.lport, TIMEOUT) :
+ _config.factory.createSocket(_config.target, _config.lport);
socket.setTcpNoDelay(true);
io.setInputStream(socket.getInputStream());
io.setOutputStream(socket.getOutputStream());
@@ -155,32 +152,29 @@ public class ChannelForwardedTCPIP extends Channel{
// session has been already down.
}
- synchronized(pool){
- for(int i=0; i<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;
}
}
diff --git a/java/com/jcraft/jsch/ChannelSession.java b/java/com/jcraft/jsch/ChannelSession.java
index 70dea2d2..8d12869e 100644
--- a/java/com/jcraft/jsch/ChannelSession.java
+++ b/java/com/jcraft/jsch/ChannelSession.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,7 +31,6 @@ package com.jcraft.jsch;
import java.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);
diff --git a/java/com/jcraft/jsch/ChannelSftp.java b/java/com/jcraft/jsch/ChannelSftp.java
index a278ed61..d2c0913d 100644
--- a/java/com/jcraft/jsch/ChannelSftp.java
+++ b/java/com/jcraft/jsch/ChannelSftp.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -33,7 +33,6 @@ import java.io.*;
import java.util.Vector;
-@SuppressWarnings({"rawtypes","unchecked"})
public class ChannelSftp extends ChannelSession{
static private final int LOCAL_MAXIMUM_PACKET_SIZE=32*1024;
@@ -150,6 +149,11 @@ public class ChannelSftp extends ChannelSession{
private java.util.Hashtable extensions=null;
private InputStream io_in=null;
+ private boolean extension_posix_rename = false;
+ private boolean extension_statvfs = false;
+ // private boolean extension_fstatvfs = false;
+ private boolean extension_hardlink = false;
+
/*
10. Changes from previous protocol versions
The SSH File Transfer Protocol has changed over time, before it's
@@ -178,7 +182,15 @@ public class ChannelSftp extends ChannelSession{
private String fEncoding=UTF8;
private boolean fEncoding_is_utf8=true;
- private RequestQueue rq = new RequestQueue(10);
+ private RequestQueue rq = new RequestQueue(16);
+
+ /**
+ * Specify how many requests may be sent at any one time.
+ * Increasing this value may slightly improve file transfer speed but will
+ * increase memory usage. The default is 16 requests.
+ *
+ * @param bulk_requests how many requests may be outstanding at any one time.
+ */
public void setBulkRequests(int bulk_requests) throws JSchException {
if(bulk_requests>0)
rq = new RequestQueue(bulk_requests);
@@ -186,11 +198,18 @@ public class ChannelSftp extends ChannelSession{
throw new JSchException("setBulkRequests: "+
bulk_requests+" must be greater than 0.");
}
+
+ /**
+ * This method will return the value how many requests may be
+ * sent at any one time.
+ *
+ * @return how many requests may be sent at any one time.
+ */
public int getBulkRequests(){
return rq.size();
}
- ChannelSftp(){
+ public ChannelSftp(){
super();
setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX);
setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX);
@@ -249,8 +268,8 @@ public class ChannelSftp extends ChannelSession{
type=header.type; // 2 -> SSH_FXP_VERSION
server_version=header.rid;
//System.err.println("SFTP protocol server-version="+server_version);
+ extensions=new java.util.Hashtable();
if(length>0){
- extensions=new java.util.Hashtable();
// extension data
fill(buf, length);
byte[] extension_name=null;
@@ -265,6 +284,28 @@ public class ChannelSftp extends ChannelSession{
}
}
+ if(extensions.get("posix-rename@openssh.com")!=null &&
+ extensions.get("posix-rename@openssh.com").equals("1")){
+ extension_posix_rename = true;
+ }
+
+ if(extensions.get("statvfs@openssh.com")!=null &&
+ extensions.get("statvfs@openssh.com").equals("2")){
+ extension_statvfs = true;
+ }
+
+ /*
+ if(extensions.get("fstatvfs@openssh.com")!=null &&
+ extensions.get("fstatvfs@openssh.com").equals("2")){
+ extension_fstatvfs = true;
+ }
+ */
+
+ if(extensions.get("hardlink@openssh.com")!=null &&
+ extensions.get("hardlink@openssh.com").equals("1")){
+ extension_hardlink = true;
+ }
+
lcwd=new File(".").getCanonicalPath();
}
catch(Exception e){
@@ -330,6 +371,17 @@ public class ChannelSftp extends ChannelSession{
SftpProgressMonitor monitor) throws SftpException{
put(src, dst, monitor, OVERWRITE);
}
+
+ /**
+ * Sends data from <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);
+ }
}
diff --git a/java/com/jcraft/jsch/ChannelShell.java b/java/com/jcraft/jsch/ChannelShell.java
index eeb24a39..25fad048 100644
--- a/java/com/jcraft/jsch/ChannelShell.java
+++ b/java/com/jcraft/jsch/ChannelShell.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/ChannelSubsystem.java b/java/com/jcraft/jsch/ChannelSubsystem.java
index 3f33bf3e..6df855c7 100644
--- a/java/com/jcraft/jsch/ChannelSubsystem.java
+++ b/java/com/jcraft/jsch/ChannelSubsystem.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2005-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/ChannelX11.java b/java/com/jcraft/jsch/ChannelX11.java
index eb66bb66..6a0d248c 100644
--- a/java/com/jcraft/jsch/ChannelX11.java
+++ b/java/com/jcraft/jsch/ChannelX11.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,7 +31,6 @@ package com.jcraft.jsch;
import java.net.*;
-@SuppressWarnings({"rawtypes","unchecked"})
class ChannelX11 extends Channel{
static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
diff --git a/java/com/jcraft/jsch/Cipher.java b/java/com/jcraft/jsch/Cipher.java
index cc7084e6..1fe1c540 100644
--- a/java/com/jcraft/jsch/Cipher.java
+++ b/java/com/jcraft/jsch/Cipher.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/CipherNone.java b/java/com/jcraft/jsch/CipherNone.java
index 61f836ab..542b6bcd 100644
--- a/java/com/jcraft/jsch/CipherNone.java
+++ b/java/com/jcraft/jsch/CipherNone.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/Compression.java b/java/com/jcraft/jsch/Compression.java
index 7ae79220..ad80abc1 100644
--- a/java/com/jcraft/jsch/Compression.java
+++ b/java/com/jcraft/jsch/Compression.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/ConfigRepository.java b/java/com/jcraft/jsch/ConfigRepository.java
new file mode 100644
index 00000000..5afa4eaf
--- /dev/null
+++ b/java/com/jcraft/jsch/ConfigRepository.java
@@ -0,0 +1,55 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2013-2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public interface ConfigRepository {
+
+ public Config getConfig(String host);
+
+ public interface Config {
+ public String getHostname();
+ public String getUser();
+ public int getPort();
+ public String getValue(String key);
+ public String[] getValues(String key);
+ }
+
+ static final Config defaultConfig = new Config() {
+ public String getHostname() {return null;}
+ public String getUser() {return null;}
+ public int getPort() {return -1;}
+ public String getValue(String key) {return null;}
+ public String[] getValues(String key) {return null;}
+ };
+
+ static final ConfigRepository nullConfig = new ConfigRepository(){
+ public Config getConfig(String host) { return defaultConfig; }
+ };
+}
diff --git a/java/com/jcraft/jsch/DH.java b/java/com/jcraft/jsch/DH.java
index 963f13c2..565d1cfa 100644
--- a/java/com/jcraft/jsch/DH.java
+++ b/java/com/jcraft/jsch/DH.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -36,4 +36,8 @@ public interface DH{
byte[] getE() throws Exception;
void setF(byte[] f);
byte[] getK() throws Exception;
+
+ // checkRange() will check if e and f are in [1,p-1]
+ // as defined at https://tools.ietf.org/html/rfc4253#section-8
+ void checkRange() throws Exception;
}
diff --git a/java/com/jcraft/jsch/DHEC256.java b/java/com/jcraft/jsch/DHEC256.java
new file mode 100644
index 00000000..13016889
--- /dev/null
+++ b/java/com/jcraft/jsch/DHEC256.java
@@ -0,0 +1,37 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public class DHEC256 extends DHECN {
+ public DHEC256(){
+ sha_name="sha-256";
+ key_size=256;
+ }
+}
diff --git a/java/com/jcraft/jsch/DHEC384.java b/java/com/jcraft/jsch/DHEC384.java
new file mode 100644
index 00000000..47cdf5d3
--- /dev/null
+++ b/java/com/jcraft/jsch/DHEC384.java
@@ -0,0 +1,37 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public class DHEC384 extends DHECN {
+ public DHEC384(){
+ sha_name="sha-384";
+ key_size=384;
+ }
+}
diff --git a/java/com/jcraft/jsch/DHEC521.java b/java/com/jcraft/jsch/DHEC521.java
new file mode 100644
index 00000000..0bc070a8
--- /dev/null
+++ b/java/com/jcraft/jsch/DHEC521.java
@@ -0,0 +1,37 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public class DHEC521 extends DHECN {
+ public DHEC521(){
+ sha_name="sha-512";
+ key_size=521;
+ }
+}
diff --git a/java/com/jcraft/jsch/DHECN.java b/java/com/jcraft/jsch/DHECN.java
new file mode 100644
index 00000000..f4aa123c
--- /dev/null
+++ b/java/com/jcraft/jsch/DHECN.java
@@ -0,0 +1,187 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public abstract class DHECN extends KeyExchange{
+
+ private static final int SSH_MSG_KEX_ECDH_INIT = 30;
+ private static final int SSH_MSG_KEX_ECDH_REPLY= 31;
+ private int state;
+
+ byte[] Q_C;
+
+ byte[] V_S;
+ byte[] V_C;
+ byte[] I_S;
+ byte[] I_C;
+
+ byte[] e;
+
+ private Buffer buf;
+ private Packet packet;
+
+ private ECDH ecdh;
+
+ protected String sha_name;
+ protected int key_size;
+
+ public void init(Session session,
+ byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{
+ this.session=session;
+ this.V_S=V_S;
+ this.V_C=V_C;
+ this.I_S=I_S;
+ this.I_C=I_C;
+
+ try{
+ Class c=Class.forName(session.getConfig(sha_name));
+ sha=(HASH)(c.newInstance());
+ sha.init();
+ }
+ catch(Exception e){
+ System.err.println(e);
+ }
+
+ buf=new Buffer();
+ packet=new Packet(buf);
+
+ packet.reset();
+ buf.putByte((byte)SSH_MSG_KEX_ECDH_INIT);
+
+ try{
+ Class c=Class.forName(session.getConfig("ecdh-sha2-nistp"));
+ ecdh=(ECDH)(c.newInstance());
+ ecdh.init(key_size);
+
+ Q_C = ecdh.getQ();
+ buf.putString(Q_C);
+ }
+ catch(Exception e){
+ if(e instanceof Throwable)
+ throw new JSchException(e.toString(), (Throwable)e);
+ throw new JSchException(e.toString());
+ }
+
+ if(V_S==null){ // This is a really ugly hack for Session.checkKexes ;-(
+ return;
+ }
+
+ session.write(packet);
+
+ if(JSch.getLogger().isEnabled(Logger.INFO)){
+ JSch.getLogger().log(Logger.INFO,
+ "SSH_MSG_KEX_ECDH_INIT sent");
+ JSch.getLogger().log(Logger.INFO,
+ "expecting SSH_MSG_KEX_ECDH_REPLY");
+ }
+
+ state=SSH_MSG_KEX_ECDH_REPLY;
+ }
+
+ public boolean next(Buffer _buf) throws Exception{
+ int i,j;
+ switch(state){
+ case SSH_MSG_KEX_ECDH_REPLY:
+ // The server responds with:
+ // byte SSH_MSG_KEX_ECDH_REPLY
+ // string K_S, server's public host key
+ // string Q_S, server's ephemeral public key octet string
+ // string the signature on the exchange hash
+ j=_buf.getInt();
+ j=_buf.getByte();
+ j=_buf.getByte();
+ if(j!=31){
+ System.err.println("type: must be 31 "+j);
+ return false;
+ }
+
+ K_S=_buf.getString();
+
+ byte[] Q_S=_buf.getString();
+
+ byte[][] r_s = KeyPairECDSA.fromPoint(Q_S);
+
+ // RFC 5656,
+ // 4. ECDH Key Exchange
+ // All elliptic curve public keys MUST be validated after they are
+ // received. An example of a validation algorithm can be found in
+ // Section 3.2.2 of [SEC1]. If a key fails validation,
+ // the key exchange MUST fail.
+ if(!ecdh.validate(r_s[0], r_s[1])){
+ return false;
+ }
+
+ K = ecdh.getSecret(r_s[0], r_s[1]);
+ K=normalize(K);
+
+ byte[] sig_of_H=_buf.getString();
+
+ //The hash H is computed as the HASH hash of the concatenation of the
+ //following:
+ // string V_C, client's identification string (CR and LF excluded)
+ // string V_S, server's identification string (CR and LF excluded)
+ // string I_C, payload of the client's SSH_MSG_KEXINIT
+ // string I_S, payload of the server's SSH_MSG_KEXINIT
+ // string K_S, server's public host key
+ // string Q_C, client's ephemeral public key octet string
+ // string Q_S, server's ephemeral public key octet string
+ // mpint K, shared secret
+
+ // This value is called the exchange hash, and it is used to authenti-
+ // cate the key exchange.
+ buf.reset();
+ buf.putString(V_C); buf.putString(V_S);
+ buf.putString(I_C); buf.putString(I_S);
+ buf.putString(K_S);
+ buf.putString(Q_C); buf.putString(Q_S);
+ buf.putMPInt(K);
+ byte[] foo=new byte[buf.getLength()];
+ buf.getByte(foo);
+
+ sha.update(foo, 0, foo.length);
+ H=sha.digest();
+
+ i=0;
+ j=0;
+ j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+ ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+ String alg=Util.byte2str(K_S, i, j);
+ i+=j;
+
+ boolean result = verify(alg, K_S, i, sig_of_H);
+
+ state=STATE_END;
+ return result;
+ }
+ return false;
+ }
+
+ public int getState(){return state; }
+}
diff --git a/java/com/jcraft/jsch/DHG1.java b/java/com/jcraft/jsch/DHG1.java
index 655c196c..aa371fed 100644
--- a/java/com/jcraft/jsch/DHG1.java
+++ b/java/com/jcraft/jsch/DHG1.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;
-@SuppressWarnings({"rawtypes"})
public class DHG1 extends KeyExchange{
static final byte[] g={ 2 };
@@ -56,25 +55,15 @@ public class DHG1 extends KeyExchange{
private static final int SSH_MSG_KEXDH_INIT= 30;
private static final int SSH_MSG_KEXDH_REPLY= 31;
- static final int RSA=0;
- static final int DSS=1;
- private int type=0;
-
private int state;
DH dh;
-// HASH sha;
-
-// byte[] K;
-// byte[] H;
byte[] V_S;
byte[] V_C;
byte[] I_S;
byte[] I_C;
-// byte[] K_S;
-
byte[] e;
private Buffer buf;
@@ -88,8 +77,6 @@ public class DHG1 extends KeyExchange{
this.I_S=I_S;
this.I_C=I_C;
-// sha=new SHA1();
-// sha.init();
try{
Class c=Class.forName(session.getConfig("sha-1"));
sha=(HASH)(c.newInstance());
@@ -156,25 +143,15 @@ public class DHG1 extends KeyExchange{
}
K_S=_buf.getString();
- // K_S is server_key_blob, which includes ....
- // string ssh-dss
- // impint p of dsa
- // impint q of dsa
- // impint g of dsa
- // impint pub_key of dsa
- //System.err.print("K_S: "); //dump(K_S, 0, K_S.length);
+
byte[] f=_buf.getMPInt();
byte[] sig_of_H=_buf.getString();
- /*
-for(int ii=0; 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; }
}
diff --git a/java/com/jcraft/jsch/DHG14.java b/java/com/jcraft/jsch/DHG14.java
index e46fb6fd..4ea2aea4 100644
--- a/java/com/jcraft/jsch/DHG14.java
+++ b/java/com/jcraft/jsch/DHG14.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;
-@SuppressWarnings({"rawtypes"})
public class 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; }
}
diff --git a/java/com/jcraft/jsch/DHGEX.java b/java/com/jcraft/jsch/DHGEX.java
index 0f0da104..8a9a17c8 100644
--- a/java/com/jcraft/jsch/DHGEX.java
+++ b/java/com/jcraft/jsch/DHGEX.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;
-@SuppressWarnings({"rawtypes"})
public class 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
index 00000000..ecd41761
--- /dev/null
+++ b/java/com/jcraft/jsch/DHGEX256.java
@@ -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
index 00000000..d7085db2
--- /dev/null
+++ b/java/com/jcraft/jsch/ECDH.java
@@ -0,0 +1,37 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public interface 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;
+}
diff --git a/java/com/jcraft/jsch/ForwardedTCPIPDaemon.java b/java/com/jcraft/jsch/ForwardedTCPIPDaemon.java
index 4176aef4..1fc829f7 100644
--- a/java/com/jcraft/jsch/ForwardedTCPIPDaemon.java
+++ b/java/com/jcraft/jsch/ForwardedTCPIPDaemon.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/GSSContext.java b/java/com/jcraft/jsch/GSSContext.java
index 23c58ee3..cacb9a98 100644
--- a/java/com/jcraft/jsch/GSSContext.java
+++ b/java/com/jcraft/jsch/GSSContext.java
@@ -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:
diff --git a/java/com/jcraft/jsch/HASH.java b/java/com/jcraft/jsch/HASH.java
index 6bfff886..250b6816 100644
--- a/java/com/jcraft/jsch/HASH.java
+++ b/java/com/jcraft/jsch/HASH.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/HostKey.java b/java/com/jcraft/jsch/HostKey.java
index 6ed420ad..6269469a 100644
--- a/java/com/jcraft/jsch/HostKey.java
+++ b/java/com/jcraft/jsch/HostKey.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,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);
diff --git a/java/com/jcraft/jsch/HostKeyRepository.java b/java/com/jcraft/jsch/HostKeyRepository.java
index adfe633c..c3cea124 100644
--- a/java/com/jcraft/jsch/HostKeyRepository.java
+++ b/java/com/jcraft/jsch/HostKeyRepository.java
@@ -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);
}
diff --git a/java/com/jcraft/jsch/IO.java b/java/com/jcraft/jsch/IO.java
index 65535ba3..866d4c36 100644
--- a/java/com/jcraft/jsch/IO.java
+++ b/java/com/jcraft/jsch/IO.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/Identity.java b/java/com/jcraft/jsch/Identity.java
index 2f8cb80e..331ae7e9 100644
--- a/java/com/jcraft/jsch/Identity.java
+++ b/java/com/jcraft/jsch/Identity.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -30,12 +30,54 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;
public interface Identity{
+
+ /**
+ * Decrypts this identity with the specified pass-phrase.
+ * @param passphrase the pass-phrase for this identity.
+ * @return <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();
}
diff --git a/java/com/jcraft/jsch/IdentityFile.java b/java/com/jcraft/jsch/IdentityFile.java
index cc66dfe2..4ffdaa7a 100644
--- a/java/com/jcraft/jsch/IdentityFile.java
+++ b/java/com/jcraft/jsch/IdentityFile.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,926 +31,100 @@ package com.jcraft.jsch;
import java.io.*;
-@SuppressWarnings({"rawtypes","static"})
class IdentityFile implements Identity{
- String identity;
- byte[] key;
- byte[] iv;
private JSch jsch;
- private HASH hash;
- private byte[] encoded_data;
-
- private Cipher cipher;
-
- // DSA
- private byte[] P_array;
- private byte[] Q_array;
- private byte[] G_array;
- private byte[] pub_array;
- private byte[] prv_array;
-
- // RSA
- private byte[] n_array; // modulus
- private byte[] e_array; // public exponent
- private byte[] d_array; // private exponent
-
-// private String algname="ssh-dss";
- private String algname="ssh-rsa";
-
- private static final int ERROR=0;
- private static final int RSA=1;
- private static final int DSS=2;
- private static final int UNKNOWN=3;
-
- private static final int OPENSSH=0;
- private static final int FSECURE=1;
- private static final int PUTTY=2;
-
- private int type=ERROR;
- private int keytype=OPENSSH;
-
- private byte[] publickeyblob=null;
-
- private boolean encrypted=true;
+ private KeyPair kpair;
+ private String identity;
static IdentityFile newInstance(String prvfile, String pubfile, JSch jsch) throws JSchException{
- byte[] prvkey=null;
- byte[] pubkey=null;
-
- File file=null;
- FileInputStream fis=null;
- try{
- file=new File(prvfile);
- fis=new FileInputStream(prvfile);
- prvkey=new byte[(int)(file.length())];
- int len=0;
- while(true){
- int i=fis.read(prvkey, len, prvkey.length-len);
- if(i<=0)
- break;
- len+=i;
- }
- fis.close();
- }
- catch(Exception e){
- try{ if(fis!=null) fis.close();}
- catch(Exception ee){}
- if(e instanceof Throwable)
- throw new JSchException(e.toString(), (Throwable)e);
- throw new JSchException(e.toString());
- }
-
- String _pubfile=pubfile;
- if(pubfile==null){
- _pubfile=prvfile+".pub";
- }
-
- try{
- file=new File(_pubfile);
- fis = new FileInputStream(_pubfile);
- pubkey=new byte[(int)(file.length())];
- int len=0;
- while(true){
- int i=fis.read(pubkey, len, pubkey.length-len);
- if(i<=0)
- break;
- len+=i;
- }
- fis.close();
- }
- catch(Exception e){
- try{ if(fis!=null) fis.close();}
- catch(Exception ee){}
- if(pubfile!=null){
- // The pubfile is explicitry given, but not accessible.
- if(e instanceof Throwable)
- throw new JSchException(e.toString(), (Throwable)e);
- throw new JSchException(e.toString());
- }
- }
- return newInstance(prvfile, prvkey, pubkey, jsch);
+ KeyPair kpair = KeyPair.load(jsch, prvfile, pubfile);
+ return new IdentityFile(jsch, prvfile, kpair);
}
static IdentityFile newInstance(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{
- try{
- return new IdentityFile(name, prvkey, pubkey, jsch);
- }
- finally{
- Util.bzero(prvkey);
- }
- }
-
- private IdentityFile(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{
- this.identity=name;
- this.jsch=jsch;
-
- // prvkey from "ssh-add" command on the remote.
- if(pubkey==null &&
- prvkey!=null &&
- (prvkey.length>11 &&
- prvkey[0]==0 && prvkey[1]==0 && prvkey[2]==0 && prvkey[3]==7)){
-
- Buffer buf=new Buffer(prvkey);
- String _type = new String(buf.getString()); // ssh-rsa
-
- if(_type.equals("ssh-rsa")){
- type=RSA;
- n_array=buf.getString();
- e_array=buf.getString();
- d_array=buf.getString();
- buf.getString();
- buf.getString();
- buf.getString();
- this.identity += new String(buf.getString());
- }
- else if(_type.equals("ssh-dss")){
- type=DSS;
- P_array=buf.getString();
- Q_array=buf.getString();
- G_array=buf.getString();
- pub_array=buf.getString();
- prv_array=buf.getString();
- this.identity += new String(buf.getString());
- }
- else{
- throw new JSchException("privatekey: invalid key "+new String(prvkey, 4, 7));
- }
- encoded_data=prvkey;
- encrypted=false;
- keytype=OPENSSH;
- return;
- }
-
- /* TODO: IdentityFile should use KeyPair.
- * The following logic exists also in KeyPair. It is redundant.
- */
- try{
- Class c;
- c=Class.forName((String)jsch.getConfig("3des-cbc"));
- cipher=(Cipher)(c.newInstance());
- key=new byte[cipher.getBlockSize()]; // 24
- iv=new byte[cipher.getIVSize()]; // 8
- c=Class.forName((String)jsch.getConfig("md5"));
- hash=(HASH)(c.newInstance());
- hash.init();
-
- byte[] buf=prvkey;
- int len=buf.length;
-
- int i=0;
-
- while(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;
}
}
diff --git a/java/com/jcraft/jsch/IdentityRepository.java b/java/com/jcraft/jsch/IdentityRepository.java
index c6b60d1c..018f3fa2 100644
--- a/java/com/jcraft/jsch/IdentityRepository.java
+++ b/java/com/jcraft/jsch/IdentityRepository.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2012-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,10 +31,85 @@ package com.jcraft.jsch;
import java.util.Vector;
-@SuppressWarnings({"rawtypes"})
public interface IdentityRepository {
+ public static final int UNAVAILABLE=0;
+ public static final int NOTRUNNING=1;
+ public static final int RUNNING=2;
+ public String getName();
+ public int getStatus();
public Vector getIdentities();
public boolean add(byte[] identity);
public boolean remove(byte[] blob);
public void removeAll();
+
+ /**
+ * JSch will accept ciphered keys, but some implementations of
+ * IdentityRepository can not. For example, IdentityRepository for
+ * ssh-agent and pageant only accept plain keys. The following class has
+ * been introduced to cache ciphered keys for them, and pass them
+ * whenever they are de-ciphered.
+ */
+ static class Wrapper implements IdentityRepository {
+ private IdentityRepository ir;
+ private Vector cache = new Vector();
+ private boolean keep_in_cache = false;
+ Wrapper(IdentityRepository ir){
+ this(ir, false);
+ }
+ Wrapper(IdentityRepository ir, boolean keep_in_cache){
+ this.ir = ir;
+ this.keep_in_cache = keep_in_cache;
+ }
+ public String getName() {
+ return ir.getName();
+ }
+ public int getStatus() {
+ return ir.getStatus();
+ }
+ public boolean add(byte[] identity) {
+ return ir.add(identity);
+ }
+ public boolean remove(byte[] blob) {
+ return ir.remove(blob);
+ }
+ public void removeAll() {
+ cache.removeAllElements();
+ ir.removeAll();
+ }
+ public Vector getIdentities() {
+ Vector result = new Vector();
+ for(int i = 0; i< cache.size(); i++){
+ Identity identity = (Identity)(cache.elementAt(i));
+ result.add(identity);
+ }
+ Vector tmp = ir.getIdentities();
+ for(int i = 0; i< tmp.size(); i++){
+ result.add(tmp.elementAt(i));
+ }
+ return result;
+ }
+ void add(Identity identity) {
+ if(!keep_in_cache &&
+ !identity.isEncrypted() && (identity instanceof IdentityFile)) {
+ try {
+ ir.add(((IdentityFile)identity).getKeyPair().forSSHAgent());
+ }
+ catch(JSchException e){
+ // an exception will not be thrown.
+ }
+ }
+ else
+ cache.addElement(identity);
+ }
+ void check() {
+ if(cache.size() > 0){
+ Object[] identities = cache.toArray();
+ for(int i = 0; i < identities.length; i++){
+ Identity identity = (Identity)(identities[i]);
+ cache.removeElement(identity);
+ add(identity);
+ }
+ }
+ }
+ }
}
diff --git a/java/com/jcraft/jsch/JSch.java b/java/com/jcraft/jsch/JSch.java
index 47fa29ae..b6bc84b7 100644
--- a/java/com/jcraft/jsch/JSch.java
+++ b/java/com/jcraft/jsch/JSch.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -32,28 +32,25 @@ package com.jcraft.jsch;
import java.io.InputStream;
import java.util.Vector;
-@SuppressWarnings({"rawtypes","unchecked"})
public class JSch{
- public static final String VERSION = "0.1.46";
+ /**
+ * The version number.
+ */
+ public static final String VERSION = "0.1.53";
static java.util.Hashtable config=new java.util.Hashtable();
static{
-// config.put("kex", "diffie-hellman-group-exchange-sha1");
- config.put("kex", "diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1");
- config.put("server_host_key", "ssh-rsa,ssh-dss");
-// config.put("server_host_key", "ssh-dss,ssh-rsa");
-
+ config.put("kex", "ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1");
+ config.put("server_host_key", "ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521");
config.put("cipher.s2c",
- "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc");
+ "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc");
config.put("cipher.c2s",
- "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc");
+ "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc");
- config.put("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96");
- config.put("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96");
+ config.put("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96");
+ config.put("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96");
config.put("compression.s2c", "none");
- // config.put("compression.s2c", "zlib@openssh.com,zlib,none");
config.put("compression.c2s", "none");
- // config.put("compression.c2s", "zlib@openssh.com,zlib,none");
config.put("lang.s2c", "");
config.put("lang.c2s", "");
@@ -65,21 +62,42 @@ public class JSch{
config.put("diffie-hellman-group1-sha1",
"com.jcraft.jsch.DHG1");
config.put("diffie-hellman-group14-sha1",
- "com.jcraft.jsch.DHG14");
+ "com.jcraft.jsch.DHG14"); // available since JDK8.
+ config.put("diffie-hellman-group-exchange-sha256",
+ "com.jcraft.jsch.DHGEX256"); // available since JDK1.4.2.
+ // On JDK8, 2048bits will be used.
+ config.put("ecdsa-sha2-nistp256", "com.jcraft.jsch.jce.SignatureECDSA");
+ config.put("ecdsa-sha2-nistp384", "com.jcraft.jsch.jce.SignatureECDSA");
+ config.put("ecdsa-sha2-nistp521", "com.jcraft.jsch.jce.SignatureECDSA");
+
+ config.put("ecdh-sha2-nistp256", "com.jcraft.jsch.DHEC256");
+ config.put("ecdh-sha2-nistp384", "com.jcraft.jsch.DHEC384");
+ config.put("ecdh-sha2-nistp521", "com.jcraft.jsch.DHEC521");
+
+ config.put("ecdh-sha2-nistp", "com.jcraft.jsch.jce.ECDHN");
config.put("dh", "com.jcraft.jsch.jce.DH");
config.put("3des-cbc", "com.jcraft.jsch.jce.TripleDESCBC");
config.put("blowfish-cbc", "com.jcraft.jsch.jce.BlowfishCBC");
config.put("hmac-sha1", "com.jcraft.jsch.jce.HMACSHA1");
config.put("hmac-sha1-96", "com.jcraft.jsch.jce.HMACSHA196");
+ config.put("hmac-sha2-256", "com.jcraft.jsch.jce.HMACSHA256");
+ // The "hmac-sha2-512" will require the key-length 2048 for DH,
+ // but Sun's JCE has not allowed to use such a long key.
+ //config.put("hmac-sha2-512", "com.jcraft.jsch.jce.HMACSHA512");
config.put("hmac-md5", "com.jcraft.jsch.jce.HMACMD5");
config.put("hmac-md5-96", "com.jcraft.jsch.jce.HMACMD596");
config.put("sha-1", "com.jcraft.jsch.jce.SHA1");
+ config.put("sha-256", "com.jcraft.jsch.jce.SHA256");
+ config.put("sha-384", "com.jcraft.jsch.jce.SHA384");
+ config.put("sha-512", "com.jcraft.jsch.jce.SHA512");
config.put("md5", "com.jcraft.jsch.jce.MD5");
config.put("signature.dss", "com.jcraft.jsch.jce.SignatureDSA");
config.put("signature.rsa", "com.jcraft.jsch.jce.SignatureRSA");
+ config.put("signature.ecdsa", "com.jcraft.jsch.jce.SignatureECDSA");
config.put("keypairgen.dsa", "com.jcraft.jsch.jce.KeyPairGenDSA");
config.put("keypairgen.rsa", "com.jcraft.jsch.jce.KeyPairGenRSA");
+ config.put("keypairgen.ecdsa", "com.jcraft.jsch.jce.KeyPairGenECDSA");
config.put("random", "com.jcraft.jsch.jce.Random");
config.put("none", "com.jcraft.jsch.CipherNone");
@@ -106,30 +124,60 @@ public class JSch{
config.put("zlib", "com.jcraft.jsch.jcraft.Compression");
config.put("zlib@openssh.com", "com.jcraft.jsch.jcraft.Compression");
+ config.put("pbkdf", "com.jcraft.jsch.jce.PBKDF");
+
config.put("StrictHostKeyChecking", "ask");
config.put("HashKnownHosts", "no");
- //config.put("HashKnownHosts", "yes");
+
config.put("PreferredAuthentications", "gssapi-with-mic,publickey,keyboard-interactive,password");
config.put("CheckCiphers", "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256");
- config.put("CheckKexes", "diffie-hellman-group14-sha1");
+ config.put("CheckKexes", "diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521");
+ config.put("CheckSignatures", "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521");
config.put("MaxAuthTries", "6");
+ config.put("ClearAllForwardings", "no");
}
private java.util.Vector sessionPool = new java.util.Vector();
- private IdentityRepository identityRepository =
+ private IdentityRepository defaultIdentityRepository =
new LocalIdentityRepository(this);
+ private IdentityRepository identityRepository = defaultIdentityRepository;
+
+ private ConfigRepository configRepository = null;
+
+ /**
+ * Sets the <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;
}
diff --git a/java/com/jcraft/jsch/JSchAuthCancelException.java b/java/com/jcraft/jsch/JSchAuthCancelException.java
index 65e71f19..4e7eb8f4 100644
--- a/java/com/jcraft/jsch/JSchAuthCancelException.java
+++ b/java/com/jcraft/jsch/JSchAuthCancelException.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/JSchException.java b/java/com/jcraft/jsch/JSchException.java
index 1e9056ce..666d3a41 100644
--- a/java/com/jcraft/jsch/JSchException.java
+++ b/java/com/jcraft/jsch/JSchException.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/JSchPartialAuthException.java b/java/com/jcraft/jsch/JSchPartialAuthException.java
index aa7ac9e4..93986069 100644
--- a/java/com/jcraft/jsch/JSchPartialAuthException.java
+++ b/java/com/jcraft/jsch/JSchPartialAuthException.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/KeyExchange.java b/java/com/jcraft/jsch/KeyExchange.java
index 77e7b83b..c74c22f4 100644
--- a/java/com/jcraft/jsch/KeyExchange.java
+++ b/java/com/jcraft/jsch/KeyExchange.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;
-@SuppressWarnings({"rawtypes"})
public abstract class KeyExchange{
static final int PROPOSAL_KEX_ALGS=0;
@@ -71,25 +70,43 @@ public abstract class KeyExchange{
public abstract void init(Session session,
byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception;
public abstract boolean next(Buffer buf) throws Exception;
- public abstract String getKeyType();
+
public abstract int getState();
- /*
- void dump(byte[] foo){
- for(int i=0; i<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;
+ }
+
}
diff --git a/java/com/jcraft/jsch/KeyPair.java b/java/com/jcraft/jsch/KeyPair.java
index b3f681cb..7c31f15b 100644
--- a/java/com/jcraft/jsch/KeyPair.java
+++ b/java/com/jcraft/jsch/KeyPair.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -32,15 +32,20 @@ package com.jcraft.jsch;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.File;
+import java.io.IOException;
public abstract class KeyPair{
public static final int ERROR=0;
public static final int DSA=1;
public static final int RSA=2;
- public static final int UNKNOWN=3;
+ public static final int ECDSA=3;
+ public static final int UNKNOWN=4;
static final int VENDOR_OPENSSH=0;
static final int VENDOR_FSECURE=1;
+ static final int VENDOR_PUTTY=2;
+ static final int VENDOR_PKCS8=3;
+
int vendor=VENDOR_OPENSSH;
private static final byte[] cr=Util.str2byte("\n");
@@ -52,6 +57,7 @@ public abstract class KeyPair{
KeyPair kpair=null;
if(type==DSA){ kpair=new KeyPairDSA(jsch); }
else if(type==RSA){ kpair=new KeyPairRSA(jsch); }
+ else if(type==ECDSA){ kpair=new KeyPairECDSA(jsch); }
if(kpair!=null){
kpair.generate(key_size);
}
@@ -64,10 +70,20 @@ public abstract class KeyPair{
abstract byte[] getEnd();
abstract int getKeySize();
+ public abstract byte[] getSignature(byte[] data);
+ public abstract Signature getVerifier();
+
+ public abstract byte[] forSSHAgent() throws JSchException;
+
public String getPublicKeyComment(){
return publicKeyComment;
}
- private String publicKeyComment = "";
+
+ public void setPublicKeyComment(String publicKeyComment){
+ this.publicKeyComment = publicKeyComment;
+ }
+
+ protected String publicKeyComment = "no comment";
JSch jsch=null;
private Cipher cipher;
@@ -85,10 +101,27 @@ public abstract class KeyPair{
abstract byte[] getPrivateKey();
+ /**
+ * Writes the plain private key to the given output stream.
+ * @param out output stream
+ * @see #writePrivateKey(java.io.OutputStream out, byte[] passphrase)
+ */
public void writePrivateKey(java.io.OutputStream out){
+ this.writePrivateKey(out, null);
+ }
+
+ /**
+ * Writes the cyphered private key to the given output stream.
+ * @param out output stream
+ * @param passphrase a passphrase to encrypt the private key
+ */
+ public void writePrivateKey(java.io.OutputStream out, byte[] passphrase){
+ if(passphrase == null)
+ passphrase = this.passphrase;
+
byte[] plain=getPrivateKey();
byte[][] _iv=new byte[1][];
- byte[] encoded=encrypt(plain, _iv);
+ byte[] encoded=encrypt(plain, _iv, passphrase);
if(encoded!=plain)
Util.bzero(plain);
byte[] iv=_iv[0];
@@ -130,8 +163,22 @@ public abstract class KeyPair{
abstract byte[] getKeyTypeName();
public abstract int getKeyType();
- public byte[] getPublicKeyBlob(){ return publickeyblob; }
+ /**
+ * Returns the blob of the public key.
+ * @return blob of the public key
+ */
+ public byte[] getPublicKeyBlob() {
+ // TODO JSchException should be thrown
+ //if(publickeyblob == null)
+ // throw new JSchException("public-key blob is not available");
+ return publickeyblob;
+ }
+ /**
+ * Writes the public key with the specified comment to the output stream.
+ * @param out output stream
+ * @param comment comment
+ */
public void writePublicKey(java.io.OutputStream out, String comment){
byte[] pubblob=getPublicKeyBlob();
byte[] pub=Util.toBase64(pubblob, 0, pubblob.length);
@@ -145,12 +192,24 @@ public abstract class KeyPair{
}
}
+ /**
+ * Writes the public key with the specified comment to the file.
+ * @param name file name
+ * @param comment comment
+ * @see #writePublicKey(java.io.OutputStream out, String comment)
+ */
public void writePublicKey(String name, String comment) throws java.io.FileNotFoundException, java.io.IOException{
FileOutputStream fos=new FileOutputStream(name);
writePublicKey(fos, comment);
fos.close();
}
+ /**
+ * Writes the public key with the specified comment to the output stream in
+ * the format defined in http://www.ietf.org/rfc/rfc4716.txt
+ * @param out output stream
+ * @param comment comment
+ */
public void writeSECSHPublicKey(java.io.OutputStream out, String comment){
byte[] pubblob=getPublicKeyBlob();
byte[] pub=Util.toBase64(pubblob, 0, pubblob.length);
@@ -170,27 +229,52 @@ public abstract class KeyPair{
}
}
+ /**
+ * Writes the public key with the specified comment to the output stream in
+ * the format defined in http://www.ietf.org/rfc/rfc4716.txt
+ * @param name file name
+ * @param comment comment
+ * @see #writeSECSHPublicKey(java.io.OutputStream out, String comment)
+ */
public void writeSECSHPublicKey(String name, String comment) throws java.io.FileNotFoundException, java.io.IOException{
FileOutputStream fos=new FileOutputStream(name);
writeSECSHPublicKey(fos, comment);
fos.close();
}
-
+ /**
+ * Writes the plain private key to the file.
+ * @param name file name
+ * @see #writePrivateKey(String name, byte[] passphrase)
+ */
public void writePrivateKey(String name) throws java.io.FileNotFoundException, java.io.IOException{
+ this.writePrivateKey(name, null);
+ }
+
+ /**
+ * Writes the cyphered private key to the file.
+ * @param name file name
+ * @param passphrase a passphrase to encrypt the private key
+ * @see #writePrivateKey(java.io.OutputStream out, byte[] passphrase)
+ */
+ public void writePrivateKey(String name, byte[] passphrase) throws java.io.FileNotFoundException, java.io.IOException{
FileOutputStream fos=new FileOutputStream(name);
- writePrivateKey(fos);
+ writePrivateKey(fos, passphrase);
fos.close();
}
+ /**
+ * Returns the finger-print of the public key.
+ * @return finger print
+ */
public String getFingerPrint(){
if(hash==null) hash=genHash();
byte[] kblob=getPublicKeyBlob();
if(kblob==null) return null;
- return getKeySize()+" "+Util.getFingerPrint(hash, kblob);
+ return Util.getFingerPrint(hash, kblob);
}
- private byte[] encrypt(byte[] plain, byte[][] _iv){
+ private byte[] encrypt(byte[] plain, byte[][] _iv, byte[] passphrase){
if(passphrase==null) return plain;
if(cipher==null) cipher=genCipher();
@@ -229,12 +313,7 @@ public abstract class KeyPair{
abstract boolean parse(byte[] data);
private byte[] decrypt(byte[] data, byte[] passphrase, byte[] iv){
- /*
- if(iv==null){ // FSecure
- iv=new byte[8];
- for(int i=0; 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;
+ }
+ }
}
diff --git a/java/com/jcraft/jsch/KeyPairDSA.java b/java/com/jcraft/jsch/KeyPairDSA.java
index f65d8c00..ca5b708c 100644
--- a/java/com/jcraft/jsch/KeyPairDSA.java
+++ b/java/com/jcraft/jsch/KeyPairDSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -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
index 00000000..aa25a6eb
--- /dev/null
+++ b/java/com/jcraft/jsch/KeyPairECDSA.java
@@ -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);
+ }
+}
diff --git a/java/com/jcraft/jsch/KeyPairGenDSA.java b/java/com/jcraft/jsch/KeyPairGenDSA.java
index f6507f24..6d7e21c9 100644
--- a/java/com/jcraft/jsch/KeyPairGenDSA.java
+++ b/java/com/jcraft/jsch/KeyPairGenDSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/KeyPairGenECDSA.java b/java/com/jcraft/jsch/KeyPairGenECDSA.java
new file mode 100644
index 00000000..b0d6bbf4
--- /dev/null
+++ b/java/com/jcraft/jsch/KeyPairGenECDSA.java
@@ -0,0 +1,37 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public interface KeyPairGenECDSA{
+ void init(int key_size) throws Exception;
+ byte[] getD();
+ byte[] getR();
+ byte[] getS();
+}
diff --git a/java/com/jcraft/jsch/KeyPairGenRSA.java b/java/com/jcraft/jsch/KeyPairGenRSA.java
index 3a849074..ecb97a41 100644
--- a/java/com/jcraft/jsch/KeyPairGenRSA.java
+++ b/java/com/jcraft/jsch/KeyPairGenRSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/KeyPairPKCS8.java b/java/com/jcraft/jsch/KeyPairPKCS8.java
new file mode 100644
index 00000000..47c2a933
--- /dev/null
+++ b/java/com/jcraft/jsch/KeyPairPKCS8.java
@@ -0,0 +1,363 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2013-2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+import java.util.Vector;
+import java.math.BigInteger;
+
+public class KeyPairPKCS8 extends KeyPair {
+ private static final byte[] rsaEncryption = {
+ (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86,
+ (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01
+ };
+
+ private static final byte[] dsaEncryption = {
+ (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0xce,
+ (byte)0x38, (byte)0x04, (byte)0x1
+ };
+
+ private static final byte[] pbes2 = {
+ (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7,
+ (byte)0x0d, (byte)0x01, (byte)0x05, (byte)0x0d
+ };
+
+ private static final byte[] pbkdf2 = {
+ (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7,
+ (byte)0x0d, (byte)0x01, (byte)0x05, (byte)0x0c
+ };
+
+ private static final byte[] aes128cbc = {
+ (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65,
+ (byte)0x03, (byte)0x04, (byte)0x01, (byte)0x02
+ };
+
+ private static final byte[] aes192cbc = {
+ (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65,
+ (byte)0x03, (byte)0x04, (byte)0x01, (byte)0x16
+ };
+
+ private static final byte[] aes256cbc = {
+ (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65,
+ (byte)0x03, (byte)0x04, (byte)0x01, (byte)0x2a
+ };
+
+ private static final byte[] pbeWithMD5AndDESCBC = {
+ (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7,
+ (byte)0x0d, (byte)0x01, (byte)0x05, (byte)0x03
+ };
+
+ private KeyPair kpair = null;
+
+ public KeyPairPKCS8(JSch jsch){
+ super(jsch);
+ }
+
+ void generate(int key_size) throws JSchException{
+ }
+
+ private static final byte[] begin=Util.str2byte("-----BEGIN DSA PRIVATE KEY-----");
+ private static final byte[] end=Util.str2byte("-----END DSA PRIVATE KEY-----");
+
+ byte[] getBegin(){ return begin; }
+ byte[] getEnd(){ return end; }
+
+ byte[] getPrivateKey(){
+ return null;
+ }
+
+ boolean parse(byte[] plain){
+
+ /* from RFC5208
+ PrivateKeyInfo ::= SEQUENCE {
+ version Version,
+ privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ privateKey PrivateKey,
+ attributes [0] IMPLICIT Attributes OPTIONAL
+ }
+ Version ::= INTEGER
+ PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ PrivateKey ::= OCTET STRING
+ Attributes ::= SET OF Attribute
+ }
+ */
+
+ try{
+ Vector values = new Vector();
+
+ ASN1[] contents = null;
+ ASN1 asn1 = new ASN1(plain);
+ contents = asn1.getContents();
+
+ ASN1 privateKeyAlgorithm = contents[1];
+ ASN1 privateKey = contents[2];
+
+ contents = privateKeyAlgorithm.getContents();
+ byte[] privateKeyAlgorithmID = contents[0].getContent();
+ contents = contents[1].getContents();
+ if(contents.length>0){
+ for(int i = 0; i < contents.length; i++){
+ values.addElement(contents[i].getContent());
+ }
+ }
+
+ byte[] _data = privateKey.getContent();
+
+ KeyPair _kpair = null;
+ if(Util.array_equals(privateKeyAlgorithmID, rsaEncryption)){
+ _kpair = new KeyPairRSA(jsch);
+ _kpair.copy(this);
+ if(_kpair.parse(_data)){
+ kpair = _kpair;
+ }
+ }
+ else if(Util.array_equals(privateKeyAlgorithmID, dsaEncryption)){
+ asn1 = new ASN1(_data);
+ if(values.size() == 0) { // embedded DSA parameters format
+ /*
+ SEQUENCE
+ SEQUENCE
+ INTEGER // P_array
+ INTEGER // Q_array
+ INTEGER // G_array
+ INTEGER // prv_array
+ */
+ contents = asn1.getContents();
+ byte[] bar = contents[1].getContent();
+ contents = contents[0].getContents();
+ for(int i = 0; i < contents.length; i++){
+ values.addElement(contents[i].getContent());
+ }
+ values.addElement(bar);
+ }
+ else {
+ /*
+ INTEGER // prv_array
+ */
+ values.addElement(asn1.getContent());
+ }
+
+ byte[] P_array = (byte[])values.elementAt(0);
+ byte[] Q_array = (byte[])values.elementAt(1);
+ byte[] G_array = (byte[])values.elementAt(2);
+ byte[] prv_array = (byte[])values.elementAt(3);
+ // Y = g^X mode p
+ byte[] pub_array =
+ (new BigInteger(G_array)).
+ modPow(new BigInteger(prv_array), new BigInteger(P_array)).
+ toByteArray();
+
+ KeyPairDSA _key = new KeyPairDSA(jsch,
+ P_array, Q_array, G_array,
+ pub_array, prv_array);
+ plain = _key.getPrivateKey();
+
+ _kpair = new KeyPairDSA(jsch);
+ _kpair.copy(this);
+ if(_kpair.parse(plain)){
+ kpair = _kpair;
+ }
+ }
+ }
+ catch(ASN1Exception e){
+ return false;
+ }
+ catch(Exception e){
+ //System.err.println(e);
+ return false;
+ }
+ return kpair != null;
+ }
+
+ public byte[] getPublicKeyBlob(){
+ return kpair.getPublicKeyBlob();
+ }
+
+ byte[] getKeyTypeName(){ return kpair.getKeyTypeName();}
+ public int getKeyType(){return kpair.getKeyType();}
+
+ public int getKeySize(){
+ return kpair.getKeySize();
+ }
+
+ public byte[] getSignature(byte[] data){
+ return kpair.getSignature(data);
+ }
+
+ public Signature getVerifier(){
+ return kpair.getVerifier();
+ }
+
+ public byte[] forSSHAgent() throws JSchException {
+ return kpair.forSSHAgent();
+ }
+
+ public boolean decrypt(byte[] _passphrase){
+ if(!isEncrypted()){
+ return true;
+ }
+ if(_passphrase==null){
+ return !isEncrypted();
+ }
+
+ /*
+ SEQUENCE
+ SEQUENCE
+ OBJECT :PBES2
+ SEQUENCE
+ SEQUENCE
+ OBJECT :PBKDF2
+ SEQUENCE
+ OCTET STRING [HEX DUMP]:E4E24ADC9C00BD4D
+ INTEGER :0800
+ SEQUENCE
+ OBJECT :aes-128-cbc
+ OCTET STRING [HEX DUMP]:5B66E6B3BF03944C92317BC370CC3AD0
+ OCTET STRING [HEX DUMP]:
+
+or
+
+ SEQUENCE
+ SEQUENCE
+ OBJECT :pbeWithMD5AndDES-CBC
+ SEQUENCE
+ OCTET STRING [HEX DUMP]:DBF75ECB69E3C0FC
+ INTEGER :0800
+ OCTET STRING [HEX DUMP]
+ */
+
+ try{
+
+ ASN1[] contents = null;
+ ASN1 asn1 = new ASN1(data);
+
+ contents = asn1.getContents();
+
+ byte[] _data = contents[1].getContent();
+
+ ASN1 pbes = contents[0];
+ contents = pbes.getContents();
+ byte[] pbesid = contents[0].getContent();
+ ASN1 pbesparam = contents[1];
+
+ byte[] salt = null;
+ int iterations = 0;
+ byte[] iv = null;
+ byte[] encryptfuncid = null;
+
+ if(Util.array_equals(pbesid, pbes2)){
+ contents = pbesparam.getContents();
+ ASN1 pbkdf = contents[0];
+ ASN1 encryptfunc = contents[1];
+ contents = pbkdf.getContents();
+ byte[] pbkdfid = contents[0].getContent();
+ ASN1 pbkdffunc = contents[1];
+ contents = pbkdffunc.getContents();
+ salt = contents[0].getContent();
+ iterations =
+ Integer.parseInt((new BigInteger(contents[1].getContent())).toString());
+
+ contents = encryptfunc.getContents();
+ encryptfuncid = contents[0].getContent();
+ iv = contents[1].getContent();
+ }
+ else if(Util.array_equals(pbesid, pbeWithMD5AndDESCBC)){
+ // not supported
+ return false;
+ }
+ else {
+ return false;
+ }
+
+ Cipher cipher=getCipher(encryptfuncid);
+ if(cipher==null) return false;
+
+ byte[] key=null;
+ try{
+ Class c=Class.forName((String)jsch.getConfig("pbkdf"));
+ PBKDF tmp=(PBKDF)(c.newInstance());
+ key = tmp.getKey(_passphrase, salt, iterations, cipher.getBlockSize());
+ }
+ catch(Exception ee){
+ }
+
+ if(key==null){
+ return false;
+ }
+
+ cipher.init(Cipher.DECRYPT_MODE, key, iv);
+ Util.bzero(key);
+ byte[] plain=new byte[_data.length];
+ cipher.update(_data, 0, _data.length, plain, 0);
+ if(parse(plain)){
+ encrypted=false;
+ return true;
+ }
+ }
+ catch(ASN1Exception e){
+ // System.err.println(e);
+ }
+ catch(Exception e){
+ // System.err.println(e);
+ }
+
+ return false;
+ }
+
+ Cipher getCipher(byte[] id){
+ Cipher cipher=null;
+ String name = null;
+ try{
+ if(Util.array_equals(id, aes128cbc)){
+ name="aes128-cbc";
+ }
+ else if(Util.array_equals(id, aes192cbc)){
+ name="aes192-cbc";
+ }
+ else if(Util.array_equals(id, aes256cbc)){
+ name="aes256-cbc";
+ }
+ Class c=Class.forName((String)jsch.getConfig(name));
+ cipher=(Cipher)(c.newInstance());
+ }
+ catch(Exception e){
+ if(JSch.getLogger().isEnabled(Logger.FATAL)){
+ String message="";
+ if(name==null){
+ message="unknown oid: "+Util.toHex(id);
+ }
+ else {
+ message="function "+name+" is not supported";
+ }
+ JSch.getLogger().log(Logger.FATAL, "PKCS8: "+message);
+ }
+ }
+ return cipher;
+ }
+}
diff --git a/java/com/jcraft/jsch/KeyPairRSA.java b/java/com/jcraft/jsch/KeyPairRSA.java
index dfc202f9..4221b75e 100644
--- a/java/com/jcraft/jsch/KeyPairRSA.java
+++ b/java/com/jcraft/jsch/KeyPairRSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,22 +29,36 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;
+import java.math.BigInteger;
+
public class KeyPairRSA extends KeyPair{
- private byte[] prv_array;
- private byte[] pub_array;
- private byte[] n_array;
+ private byte[] n_array; // modulus p multiply q
+ private byte[] pub_array; // e
+ private byte[] prv_array; // d e^-1 mod (p-1)(q-1)
private byte[] p_array; // prime p
private byte[] q_array; // prime q
- private byte[] ep_array; // prime exponent p
- private byte[] eq_array; // prime exponent q
- private byte[] c_array; // coefficient
+ private byte[] ep_array; // prime exponent p dmp1 == prv mod (p-1)
+ private byte[] eq_array; // prime exponent q dmq1 == prv mod (q-1)
+ private byte[] c_array; // coefficient iqmp == modinv(q, p) == q^-1 mod p
- //private int key_size=0;
private int key_size=1024;
public KeyPairRSA(JSch jsch){
+ this(jsch, null, null, null);
+ }
+
+ public KeyPairRSA(JSch jsch,
+ byte[] n_array,
+ byte[] pub_array,
+ byte[] prv_array){
super(jsch);
+ this.n_array = n_array;
+ this.pub_array = pub_array;
+ this.prv_array = prv_array;
+ if(n_array!=null){
+ key_size = (new java.math.BigInteger(n_array)).bitLength();
+ }
}
void generate(int key_size) throws JSchException{
@@ -110,17 +124,32 @@ public class KeyPairRSA extends KeyPair{
}
boolean parse(byte [] plain){
- /*
- byte[] p_array;
- byte[] q_array;
- byte[] dmp1_array;
- byte[] dmq1_array;
- byte[] iqmp_array;
- */
+
try{
int index=0;
int length=0;
+ if(vendor==VENDOR_PUTTY){
+ Buffer buf = new Buffer(plain);
+ buf.skip(plain.length);
+
+ try {
+ byte[][] tmp = buf.getBytes(4, "");
+ prv_array = tmp[0];
+ p_array = tmp[1];
+ q_array = tmp[2];
+ c_array = tmp[3];
+ }
+ catch(JSchException e){
+ return false;
+ }
+
+ getEPArray();
+ getEQArray();
+
+ return true;
+ }
+
if(vendor==VENDOR_FSECURE){
if(plain[index]!=0x30){ // FSecure
Buffer buf=new Buffer(plain);
@@ -130,11 +159,35 @@ public class KeyPairRSA extends KeyPair{
byte[] u_array=buf.getMPIntBits();
p_array=buf.getMPIntBits();
q_array=buf.getMPIntBits();
+ if(n_array!=null){
+ key_size = (new java.math.BigInteger(n_array)).bitLength();
+ }
+
+ getEPArray();
+ getEQArray();
+ getCArray();
+
return true;
}
return false;
}
+ /*
+ Key must be in the following ASN.1 DER encoding,
+ RSAPrivateKey ::= SEQUENCE {
+ version Version,
+ modulus INTEGER, -- n
+ publicExponent INTEGER, -- e
+ privateExponent INTEGER, -- d
+ prime1 INTEGER, -- p
+ prime2 INTEGER, -- q
+ exponent1 INTEGER, -- d mod (p-1)
+ exponent2 INTEGER, -- d mod (q-1)
+ coefficient INTEGER, -- (inverse of q) mod p
+ otherPrimeInfos OtherPrimeInfos OPTIONAL
+ }
+ */
+
index++; // SEQUENCE
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -151,10 +204,6 @@ public class KeyPairRSA extends KeyPair{
}
index+=length;
-//System.err.println("int: len="+length);
-//System.err.print(Integer.toHexString(plain[index-1]&0xff)+":");
-//System.err.println("");
-
index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -164,13 +213,7 @@ public class KeyPairRSA extends KeyPair{
n_array=new byte[length];
System.arraycopy(plain, index, n_array, 0, length);
index+=length;
-/*
-System.err.println("int: N len="+length);
-for(int i=0; i<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);
diff --git a/java/com/jcraft/jsch/KnownHosts.java b/java/com/jcraft/jsch/KnownHosts.java
index 342d7743..b86fa25c 100644
--- a/java/com/jcraft/jsch/KnownHosts.java
+++ b/java/com/jcraft/jsch/KnownHosts.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,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());
diff --git a/java/com/jcraft/jsch/LICENSE.txt b/java/com/jcraft/jsch/LICENSE.txt
index 81c8eacf..303096bf 100644
--- a/java/com/jcraft/jsch/LICENSE.txt
+++ b/java/com/jcraft/jsch/LICENSE.txt
@@ -2,7 +2,7 @@ JSch 0.0.* was released under the GNU LGPL license. Later, we have switched
over to a BSD-style license.
------------------------------------------------------------------------------
-Copyright (c) 2002-2012 Atsuhiko Yamanaka, JCraft,Inc.
+Copyright (c) 2002-2015 Atsuhiko Yamanaka, JCraft,Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/java/com/jcraft/jsch/LocalIdentityRepository.java b/java/com/jcraft/jsch/LocalIdentityRepository.java
index 7dde42e7..bc463498 100644
--- a/java/com/jcraft/jsch/LocalIdentityRepository.java
+++ b/java/com/jcraft/jsch/LocalIdentityRepository.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2012-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,8 +31,8 @@ package com.jcraft.jsch;
import java.util.Vector;
-@SuppressWarnings({"rawtypes","unchecked"})
class LocalIdentityRepository implements IdentityRepository {
+ private static final String name = "Local Identity Repository";
private Vector identities = new Vector();
private JSch jsch;
@@ -41,7 +41,16 @@ class LocalIdentityRepository implements IdentityRepository {
this.jsch = jsch;
}
+ public String getName(){
+ return name;
+ }
+
+ public int getStatus(){
+ return RUNNING;
+ }
+
public synchronized Vector getIdentities() {
+ removeDupulicates();
Vector v = new Vector();
for(int i=0; i<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));
+ }
+ }
}
diff --git a/java/com/jcraft/jsch/Logger.java b/java/com/jcraft/jsch/Logger.java
index 1263722b..b9704f89 100644
--- a/java/com/jcraft/jsch/Logger.java
+++ b/java/com/jcraft/jsch/Logger.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/MAC.java b/java/com/jcraft/jsch/MAC.java
index 0475ce2c..199c8888 100644
--- a/java/com/jcraft/jsch/MAC.java
+++ b/java/com/jcraft/jsch/MAC.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/OpenSSHConfig.java b/java/com/jcraft/jsch/OpenSSHConfig.java
new file mode 100644
index 00000000..9b1bff8b
--- /dev/null
+++ b/java/com/jcraft/jsch/OpenSSHConfig.java
@@ -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
index 00000000..44031fce
--- /dev/null
+++ b/java/com/jcraft/jsch/PBKDF.java
@@ -0,0 +1,34 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2013-2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public interface PBKDF {
+ byte[] getKey(byte[] pass, byte[] salt, int iteration, int size);
+}
diff --git a/java/com/jcraft/jsch/Packet.java b/java/com/jcraft/jsch/Packet.java
index 9c441577..c163b786 100644
--- a/java/com/jcraft/jsch/Packet.java
+++ b/java/com/jcraft/jsch/Packet.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/PortWatcher.java b/java/com/jcraft/jsch/PortWatcher.java
index b5fc37bb..2fdcd961 100644
--- a/java/com/jcraft/jsch/PortWatcher.java
+++ b/java/com/jcraft/jsch/PortWatcher.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -32,7 +32,6 @@ package com.jcraft.jsch;
import java.net.*;
import java.io.*;
-@SuppressWarnings({"rawtypes","unchecked"})
class PortWatcher implements Runnable{
private static java.util.Vector pool=new java.util.Vector();
private static InetAddress anyLocalAddress=null;
@@ -55,6 +54,7 @@ class PortWatcher implements Runnable{
InetAddress boundaddress;
Runnable thread;
ServerSocket ss;
+ int connectTimeout=0;
static String[] getPortForwarding(Session session){
java.util.Vector foo=new java.util.Vector();
@@ -93,7 +93,17 @@ class PortWatcher implements Runnable{
return null;
}
}
+ private static String normalize(String address){
+ if(address!=null){
+ if(address.length()==0 || address.equals("*"))
+ address="0.0.0.0";
+ else if(address.equals("localhost"))
+ address="127.0.0.1";
+ }
+ return address;
+ }
static PortWatcher addPort(Session session, String address, int lport, String host, int rport, ServerSocketFactory ssf) throws JSchException{
+ address = normalize(address);
if(getPort(session, address, lport)!=null){
throw new JSchException("PortForwardingL: local port "+ address+":"+lport+" is already registered.");
}
@@ -102,6 +112,7 @@ class PortWatcher implements Runnable{
return pw;
}
static void delPort(Session session, String address, int lport) throws JSchException{
+ address = normalize(address);
PortWatcher pw=getPort(session, address, lport);
if(pw==null){
throw new JSchException("PortForwardingL: local port "+address+":"+lport+" is not registered.");
@@ -171,7 +182,7 @@ class PortWatcher implements Runnable{
((ChannelDirectTCPIP)channel).setPort(rport);
((ChannelDirectTCPIP)channel).setOrgIPAddress(socket.getInetAddress().getHostAddress());
((ChannelDirectTCPIP)channel).setOrgPort(socket.getPort());
- channel.connect();
+ channel.connect(connectTimeout);
if(channel.exitstatus!=-1){
}
}
@@ -179,7 +190,6 @@ class PortWatcher implements Runnable{
catch(Exception e){
//System.err.println("! "+e);
}
-
delete();
}
@@ -192,4 +202,8 @@ class PortWatcher implements Runnable{
catch(Exception e){
}
}
+
+ void setConnectTimeout(int connectTimeout){
+ this.connectTimeout=connectTimeout;
+ }
}
diff --git a/java/com/jcraft/jsch/Proxy.java b/java/com/jcraft/jsch/Proxy.java
index 7d05caa8..be196b60 100644
--- a/java/com/jcraft/jsch/Proxy.java
+++ b/java/com/jcraft/jsch/Proxy.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/ProxyHTTP.java b/java/com/jcraft/jsch/ProxyHTTP.java
index df23114a..09a1623d 100644
--- a/java/com/jcraft/jsch/ProxyHTTP.java
+++ b/java/com/jcraft/jsch/ProxyHTTP.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/ProxySOCKS4.java b/java/com/jcraft/jsch/ProxySOCKS4.java
index cb506165..5cd97ed5 100644
--- a/java/com/jcraft/jsch/ProxySOCKS4.java
+++ b/java/com/jcraft/jsch/ProxySOCKS4.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/ProxySOCKS5.java b/java/com/jcraft/jsch/ProxySOCKS5.java
index 7960135a..33311bab 100644
--- a/java/com/jcraft/jsch/ProxySOCKS5.java
+++ b/java/com/jcraft/jsch/ProxySOCKS5.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/README b/java/com/jcraft/jsch/README
index a52886e5..d00a2192 100644
--- a/java/com/jcraft/jsch/README
+++ b/java/com/jcraft/jsch/README
@@ -6,7 +6,7 @@
http://www.jcraft.com/jsch/
-Last modified: Wed Nov 1 14:43:31 UTC 2006
+Last modified: Thu Mar 18 13:58:16 UTC 2015
Description
@@ -50,14 +50,21 @@ Features
o J2SE 1.2.2 and later and Bouncycastle's JCE implementation that
can be obtained at http://www.bouncycastle.org/
* SSH2 protocol support.
-* Key exchange: diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1
+* Key exchange: diffie-hellman-group-exchange-sha1,
+ diffie-hellman-group1-sha1,
+ diffie-hellman-group14-sha1,
+ diffie-hellman-group-exchange-sha256,
+ ecdh-sha2-nistp256,
+ ecdh-sha2-nistp384,
+ ecdh-sha2-nistp521
* Cipher: blowfish-cbc,3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc
3des-ctr,aes128-ctr,aes192-ctr,aes256-ctc,
arcfour,arcfour128,arcfour256
* MAC: hmac-md5,hmac-md5-96,hmac-sha1,hmac-sha1-96
-* Host key type: ssh-dss, ssh-rsa
+* Host key type: ssh-dss,ssh-rsa,
+ ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
* Userauth: password
-* Userauth: publickey(DSA,RSA)
+* Userauth: publickey(DSA,RSA,ECDSA)
* Userauth: keyboard-interactive
* Userauth: gssapi-with-mic
* X11 forwarding.
@@ -72,6 +79,7 @@ Features
* envrironment variable passing.
* remote exec.
* generating DSA and RSA key pairs.
+* supporting private keys in OpenSSL(traditional SSLeay) and PKCS#8 format.
* SSH File Transfer Protocol(version 0, 1, 2, 3)
* partial authentication
* packet compression: zlib, zlib@openssh.com
diff --git a/java/com/jcraft/jsch/Random.java b/java/com/jcraft/jsch/Random.java
index 879b7770..5718ba39 100644
--- a/java/com/jcraft/jsch/Random.java
+++ b/java/com/jcraft/jsch/Random.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/Request.java b/java/com/jcraft/jsch/Request.java
index 94f9b013..8bedb6ac 100644
--- a/java/com/jcraft/jsch/Request.java
+++ b/java/com/jcraft/jsch/Request.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestAgentForwarding.java b/java/com/jcraft/jsch/RequestAgentForwarding.java
index 66d328cd..252a0844 100644
--- a/java/com/jcraft/jsch/RequestAgentForwarding.java
+++ b/java/com/jcraft/jsch/RequestAgentForwarding.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestEnv.java b/java/com/jcraft/jsch/RequestEnv.java
index cccda4df..fcbcd3d7 100644
--- a/java/com/jcraft/jsch/RequestEnv.java
+++ b/java/com/jcraft/jsch/RequestEnv.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestExec.java b/java/com/jcraft/jsch/RequestExec.java
index 318d99ad..badc90f1 100644
--- a/java/com/jcraft/jsch/RequestExec.java
+++ b/java/com/jcraft/jsch/RequestExec.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestPtyReq.java b/java/com/jcraft/jsch/RequestPtyReq.java
index 86bf4f13..d0dfef16 100644
--- a/java/com/jcraft/jsch/RequestPtyReq.java
+++ b/java/com/jcraft/jsch/RequestPtyReq.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestSftp.java b/java/com/jcraft/jsch/RequestSftp.java
index 483c296b..b1a1ea51 100644
--- a/java/com/jcraft/jsch/RequestSftp.java
+++ b/java/com/jcraft/jsch/RequestSftp.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestShell.java b/java/com/jcraft/jsch/RequestShell.java
index e037ba9e..1266ad7d 100644
--- a/java/com/jcraft/jsch/RequestShell.java
+++ b/java/com/jcraft/jsch/RequestShell.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestSignal.java b/java/com/jcraft/jsch/RequestSignal.java
index a6926177..3a88d068 100644
--- a/java/com/jcraft/jsch/RequestSignal.java
+++ b/java/com/jcraft/jsch/RequestSignal.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestSubsystem.java b/java/com/jcraft/jsch/RequestSubsystem.java
index b6fee4f4..4de2b1c4 100644
--- a/java/com/jcraft/jsch/RequestSubsystem.java
+++ b/java/com/jcraft/jsch/RequestSubsystem.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2005-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestWindowChange.java b/java/com/jcraft/jsch/RequestWindowChange.java
index 43600ac4..53a31e63 100644
--- a/java/com/jcraft/jsch/RequestWindowChange.java
+++ b/java/com/jcraft/jsch/RequestWindowChange.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/RequestX11.java b/java/com/jcraft/jsch/RequestX11.java
index 3bdaca9f..870a352d 100644
--- a/java/com/jcraft/jsch/RequestX11.java
+++ b/java/com/jcraft/jsch/RequestX11.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/ServerSocketFactory.java b/java/com/jcraft/jsch/ServerSocketFactory.java
index 682b4c4f..c405577c 100644
--- a/java/com/jcraft/jsch/ServerSocketFactory.java
+++ b/java/com/jcraft/jsch/ServerSocketFactory.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/Session.java b/java/com/jcraft/jsch/Session.java
index 900d96d6..39e9029a 100644
--- a/java/com/jcraft/jsch/Session.java
+++ b/java/com/jcraft/jsch/Session.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,8 +31,8 @@ package com.jcraft.jsch;
import java.io.*;
import java.net.*;
+import java.util.Vector;
-@SuppressWarnings({"rawtypes","static","unchecked"})
public class Session implements Runnable{
// http://ietf.org/internet-drafts/draft-ietf-secsh-assignednumbers-01.txt
@@ -135,6 +135,9 @@ public class Session implements Runnable{
private int serverAliveInterval=0;
private int serverAliveCountMax=1;
+ private IdentityRepository identityRepository = null;
+ private HostKeyRepository hostkeyRepository = null;
+
protected boolean daemon_thread=false;
private long kex_start_time=0L;
@@ -143,6 +146,7 @@ public class Session implements Runnable{
int auth_failures = 0;
String host="127.0.0.1";
+ String org_host="127.0.0.1";
int port=22;
String username=null;
@@ -150,11 +154,29 @@ public class Session implements Runnable{
JSch jsch;
- Session(JSch jsch) throws JSchException{
+ Session(JSch jsch, String username, String host, int port) throws JSchException{
super();
this.jsch=jsch;
buf=new Buffer();
packet=new Packet(buf);
+ this.username = username;
+ this.org_host = this.host = host;
+ this.port = port;
+
+ applyConfig();
+
+ if(this.username==null) {
+ try {
+ this.username=(String)(System.getProperties().get("user.name"));
+ }
+ catch(SecurityException e){
+ // ignore e
+ }
+ }
+
+ if(this.username==null) {
+ throw new JSchException("username is not given.");
+ }
}
public void connect() throws JSchException{
@@ -462,8 +484,15 @@ public class Session implements Runnable{
catch(RuntimeException ee){
throw ee;
}
+ catch(JSchException ee){
+ throw ee;
+ }
catch(Exception ee){
//System.err.println("ee: "+ee); // SSH_MSG_DISCONNECT: 2 Too many authentication failures
+ if(JSch.getLogger().isEnabled(Logger.WARN)){
+ JSch.getLogger().log(Logger.WARN,
+ "an exception during authentication\n"+ee.toString());
+ }
break loop;
}
}
@@ -483,7 +512,7 @@ public class Session implements Runnable{
throw new JSchException("Auth fail");
}
- if(connectTimeout>0 || timeout>0){
+ if(socket!=null && (connectTimeout>0 || timeout>0)){
socket.setSoTimeout(timeout);
}
@@ -497,6 +526,8 @@ public class Session implements Runnable{
connectThread.setDaemon(daemon_thread);
}
connectThread.start();
+
+ requestPortForwarding();
}
else{
// The session has been already down and
@@ -506,19 +537,20 @@ public class Session implements Runnable{
}
catch(Exception e) {
in_kex=false;
- if(isConnected){
- try{
- packet.reset();
- buf.putByte((byte)SSH_MSG_DISCONNECT);
- buf.putInt(3);
- buf.putString(Util.str2byte(e.toString()));
- buf.putString(Util.str2byte("en"));
- write(packet);
- disconnect();
- }
- catch(Exception ee){
- }
+ try{
+ if(isConnected){
+ String message = e.toString();
+ packet.reset();
+ buf.checkFreeSize(1+4*3+message.length()+2+buffer_margin);
+ buf.putByte((byte)SSH_MSG_DISCONNECT);
+ buf.putInt(3);
+ buf.putString(Util.str2byte(message));
+ buf.putString(Util.str2byte("en"));
+ write(packet);
+ }
}
+ catch(Exception ee){}
+ try{ disconnect(); } catch(Exception ee){ }
isConnected=false;
//e.printStackTrace();
if(e instanceof RuntimeException) throw (RuntimeException)e;
@@ -570,7 +602,7 @@ public class Session implements Runnable{
return kex;
}
- private boolean in_kex=false;
+ private volatile boolean in_kex=false;
public void rekey() throws Exception {
send_kexinit();
}
@@ -599,6 +631,16 @@ public class Session implements Runnable{
}
}
+ String server_host_key = getConfig("server_host_key");
+ String[] not_available_shks =
+ checkSignatures(getConfig("CheckSignatures"));
+ if(not_available_shks!=null && not_available_shks.length>0){
+ server_host_key=Util.diffString(server_host_key, not_available_shks);
+ if(server_host_key==null){
+ throw new JSchException("There are not any available sig algorithm.");
+ }
+ }
+
in_kex=true;
kex_start_time=System.currentTimeMillis();
@@ -622,7 +664,7 @@ public class Session implements Runnable{
random.fill(buf.buffer, buf.index, 16); buf.skip(16);
}
buf.putString(Util.str2byte(kex));
- buf.putString(Util.str2byte(getConfig("server_host_key")));
+ buf.putString(Util.str2byte(server_host_key));
buf.putString(Util.str2byte(cipherc2s));
buf.putString(Util.str2byte(ciphers2c));
buf.putString(Util.str2byte(getConfig("mac.c2s")));
@@ -675,16 +717,22 @@ public class Session implements Runnable{
chost=("["+chost+"]:"+port);
}
-// hostkey=new HostKey(chost, K_S);
+ HostKeyRepository hkr=getHostKeyRepository();
+
+ String hkh=getConfig("HashKnownHosts");
+ if(hkh.equals("yes") && (hkr instanceof KnownHosts)){
+ hostkey=((KnownHosts)hkr).createHashedHostKey(chost, K_S);
+ }
+ else{
+ hostkey=new HostKey(chost, K_S);
+ }
- HostKeyRepository hkr=jsch.getHostKeyRepository();
int i=0;
synchronized(hkr){
i=hkr.check(chost, K_S);
}
boolean insert=false;
-
if((shkc.equals("ask") || shkc.equals("yes")) &&
i==HostKeyRepository.CHANGED){
String file=null;
@@ -701,7 +749,7 @@ public class Session implements Runnable{
"IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n"+
"Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n"+
"It is also possible that the "+key_type+" host key has just been changed.\n"+
-"The fingerprint for the "+key_type+" key sent by the remote host is\n"+
+"The fingerprint for the "+key_type+" key sent by the remote host "+chost+" is\n"+
key_fprint+".\n"+
"Please contact your system administrator.\n"+
"Add correct host key in "+file+" to get rid of this message.";
@@ -721,7 +769,7 @@ key_fprint+".\n"+
synchronized(hkr){
hkr.remove(chost,
- (key_type.equals("DSA") ? "ssh-dss" : "ssh-rsa"),
+ kex.getKeyAlgorithName(),
null);
insert=true;
}
@@ -757,10 +805,32 @@ key_type+" key fingerprint is "+key_fprint+".\n"+
insert=true;
}
+ if(i==HostKeyRepository.OK){
+ HostKey[] keys =
+ hkr.getHostKey(chost, kex.getKeyAlgorithName());
+ String _key= Util.byte2str(Util.toBase64(K_S, 0, K_S.length));
+ for(int j=0; j< keys.length; j++){
+ if(keys[i].getKey().equals(_key) &&
+ keys[j].getMarker().equals("@revoked")){
+ if(userinfo!=null){
+ userinfo.showMessage(
+"The "+ key_type +" host key for "+ host +" is marked as revoked.\n"+
+"This could mean that a stolen key is being used to "+
+"impersonate this host.");
+ }
+ if(JSch.getLogger().isEnabled(Logger.INFO)){
+ JSch.getLogger().log(Logger.INFO,
+ "Host '"+host+"' has provided revoked key.");
+ }
+ throw new JSchException("revoked HostKey: "+host);
+ }
+ }
+ }
+
if(i==HostKeyRepository.OK &&
JSch.getLogger().isEnabled(Logger.INFO)){
JSch.getLogger().log(Logger.INFO,
- "Host '"+host+"' is known and mathces the "+key_type+" host key");
+ "Host '"+host+"' is known and matches the "+key_type+" host key");
}
if(insert &&
@@ -769,21 +839,11 @@ key_type+" key fingerprint is "+key_fprint+".\n"+
"Permanently added '"+host+"' ("+key_type+") to the list of known hosts.");
}
- String hkh=getConfig("HashKnownHosts");
- if(hkh.equals("yes") && (hkr instanceof KnownHosts)){
- hostkey=((KnownHosts)hkr).createHashedHostKey(chost, K_S);
- }
- else{
- hostkey=new HostKey(chost, K_S);
- }
-
if(insert){
synchronized(hkr){
hkr.add(hostkey, userinfo);
}
-
}
-
}
//public void start(){ (new Thread(this)).start(); }
@@ -796,6 +856,9 @@ key_type+" key fingerprint is "+key_fprint+".\n"+
Channel channel=Channel.getChannel(type);
addChannel(channel);
channel.init();
+ if(channel instanceof ChannelSession){
+ applyConfigChannel((ChannelSession)channel);
+ }
return channel;
}
catch(Exception e){
@@ -966,7 +1029,7 @@ key_type+" key fingerprint is "+key_fprint+".\n"+
if(c==null){
}
else{
- c.addRemoteWindowSize(buf.getInt());
+ c.addRemoteWindowSize(buf.getUInt());
}
}
else if(type==UserAuth.SSH_MSG_USERAUTH_SUCCESS){
@@ -1032,8 +1095,6 @@ key_type+" key fingerprint is "+key_fprint+".\n"+
byte[] H=kex.getH();
HASH hash=kex.getHash();
-// String[] guess=kex.guess;
-
if(session_id==null){
session_id=new byte[H.length];
System.arraycopy(H, 0, session_id, 0, H.length);
@@ -1103,6 +1164,7 @@ key_type+" key fingerprint is "+key_fprint+".\n"+
method=guess[KeyExchange.PROPOSAL_MAC_ALGS_STOC];
c=Class.forName(getConfig(method));
s2cmac=(MAC)(c.newInstance());
+ MACs2c = expandKey(buf, K, H, MACs2c, hash, s2cmac.getBlockSize());
s2cmac.init(MACs2c);
//mac_buf=new byte[s2cmac.getBlockSize()];
s2cmac_result1=new byte[s2cmac.getBlockSize()];
@@ -1129,6 +1191,7 @@ key_type+" key fingerprint is "+key_fprint+".\n"+
method=guess[KeyExchange.PROPOSAL_MAC_ALGS_CTOS];
c=Class.forName(getConfig(method));
c2smac=(MAC)(c.newInstance());
+ MACc2s = expandKey(buf, K, H, MACc2s, hash, c2smac.getBlockSize());
c2smac.init(MACc2s);
method=guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS];
@@ -1145,6 +1208,40 @@ key_type+" key fingerprint is "+key_fprint+".\n"+
}
}
+
+ /*
+ * RFC 4253 7.2. Output from Key Exchange
+ * If the key length needed is longer than the output of the HASH, the
+ * key is extended by computing HASH of the concatenation of K and H and
+ * the entire key so far, and appending the resulting bytes (as many as
+ * HASH generates) to the key. This process is repeated until enough
+ * key material is available; the key is taken from the beginning of
+ * this value. In other words:
+ * K1 = HASH(K || H || X || session_id) (X is e.g., "A")
+ * K2 = HASH(K || H || K1)
+ * K3 = HASH(K || H || K1 || K2)
+ * ...
+ * key = K1 || K2 || K3 || ...
+ */
+ private byte[] expandKey(Buffer buf, byte[] K, byte[] H, byte[] key,
+ HASH hash, int required_length) throws Exception {
+ byte[] result = key;
+ int size = hash.getBlockSize();
+ while(result.length < required_length){
+ buf.reset();
+ buf.putMPInt(K);
+ buf.putByte(H);
+ buf.putByte(result);
+ hash.update(buf.buffer, 0, buf.index);
+ byte[] tmp = new byte[result.length+size];
+ System.arraycopy(result, 0, tmp, 0, result.length);
+ System.arraycopy(hash.digest(), 0, tmp, result.length, size);
+ Util.bzero(result);
+ result = tmp;
+ }
+ return result;
+ }
+
/*public*/ /*synchronized*/ void write(Packet packet, Channel c, int length) throws Exception{
long t = getTimeout();
while(true){
@@ -1170,6 +1267,10 @@ key_type+" key fingerprint is "+key_fprint+".\n"+
}
}
+ if(in_kex){
+ continue;
+ }
+
if(c.rwsize>=length){
c.rwsize-=length;
break;
@@ -1407,7 +1508,7 @@ break;
if(channel==null){
break;
}
- channel.addRemoteWindowSize(buf.getInt());
+ channel.addRemoteWindowSize(buf.getUInt());
break;
case SSH_MSG_CHANNEL_EOF:
@@ -1447,33 +1548,30 @@ break;
buf.getShort();
i=buf.getInt();
channel=Channel.getChannel(i, this);
- if(channel==null){
- //break;
- }
int r=buf.getInt();
long rws=buf.getUInt();
int rps=buf.getInt();
-
- channel.setRemoteWindowSize(rws);
- channel.setRemotePacketSize(rps);
- channel.open_confirmation=true;
- channel.setRecipient(r);
+ if(channel!=null){
+ channel.setRemoteWindowSize(rws);
+ channel.setRemotePacketSize(rps);
+ channel.open_confirmation=true;
+ channel.setRecipient(r);
+ }
break;
case SSH_MSG_CHANNEL_OPEN_FAILURE:
buf.getInt();
buf.getShort();
i=buf.getInt();
channel=Channel.getChannel(i, this);
- if(channel==null){
- //break;
- }
- int reason_code=buf.getInt();
- //foo=buf.getString(); // additional textual information
- //foo=buf.getString(); // language tag
- channel.setExitStatus(reason_code);
- channel.close=true;
- channel.eof_remote=true;
- channel.setRecipient(0);
+ if(channel!=null){
+ int reason_code=buf.getInt();
+ //foo=buf.getString(); // additional textual information
+ //foo=buf.getString(); // language tag
+ channel.setExitStatus(reason_code);
+ channel.close=true;
+ channel.eof_remote=true;
+ channel.setRecipient(0);
+ }
break;
case SSH_MSG_CHANNEL_REQUEST:
buf.getInt();
@@ -1529,8 +1627,8 @@ break;
tmp.setDaemon(daemon_thread);
}
tmp.start();
- break;
}
+ break;
case SSH_MSG_CHANNEL_SUCCESS:
buf.getInt();
buf.getShort();
@@ -1567,6 +1665,11 @@ break;
Thread t=grr.getThread();
if(t!=null){
grr.setReply(msgType==SSH_MSG_REQUEST_SUCCESS? 1 : 0);
+ if(msgType==SSH_MSG_REQUEST_SUCCESS && grr.getPort()==0){
+ buf.getInt();
+ buf.getShort();
+ grr.setPort(buf.getInt());
+ }
t.interrupt();
}
break;
@@ -1665,14 +1768,73 @@ break;
//System.gc();
}
+ /**
+ * Registers the local port forwarding for loop-back interface.
+ * If <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);
+ }
}
diff --git a/java/com/jcraft/jsch/SftpATTRS.java b/java/com/jcraft/jsch/SftpATTRS.java
index e89b2435..3195def9 100644
--- a/java/com/jcraft/jsch/SftpATTRS.java
+++ b/java/com/jcraft/jsch/SftpATTRS.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -108,12 +108,12 @@ public class SftpATTRS {
}
public String getAtimeString(){
- SimpleDateFormat locale=new SimpleDateFormat();
- return (locale.format(new Date(atime)));
+ Date date= new Date(((long)atime)*1000L);
+ return (date.toString());
}
public String getMtimeString(){
- Date date= new Date(((long)mtime)*1000);
+ Date date= new Date(((long)mtime)*1000L);
return (date.toString());
}
@@ -123,8 +123,14 @@ public class SftpATTRS {
public static final int SSH_FILEXFER_ATTR_ACMODTIME= 0x00000008;
public static final int SSH_FILEXFER_ATTR_EXTENDED= 0x80000000;
+ static final int S_IFMT=0xf000;
+ static final int S_IFIFO=0x1000;
+ static final int S_IFCHR=0x2000;
static final int S_IFDIR=0x4000;
+ static final int S_IFBLK=0x6000;
+ static final int S_IFREG=0x8000;
static final int S_IFLNK=0xa000;
+ static final int S_IFSOCK=0xc000;
int flags=0;
long size;
@@ -231,14 +237,39 @@ public class SftpATTRS {
this.permissions=permissions;
}
+ private boolean isType(int mask) {
+ return (flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 &&
+ (permissions&S_IFMT)==mask;
+ }
+
+ public boolean isReg(){
+ return isType(S_IFREG);
+ }
+
public boolean isDir(){
- return ((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 &&
- ((permissions&S_IFDIR)==S_IFDIR));
+ return isType(S_IFDIR);
}
- public boolean isLink(){
- return ((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 &&
- ((permissions&S_IFLNK)==S_IFLNK));
+
+ public boolean isChr(){
+ return isType(S_IFCHR);
+ }
+
+ public boolean isBlk(){
+ return isType(S_IFBLK);
}
+
+ public boolean isFifo(){
+ return isType(S_IFIFO);
+ }
+
+ public boolean isLink(){
+ return isType(S_IFLNK);
+ }
+
+ public boolean isSock(){
+ return isType(S_IFSOCK);
+ }
+
public int getFlags() { return flags; }
public long getSize() { return size; }
public int getUId() { return uid; }
diff --git a/java/com/jcraft/jsch/SftpException.java b/java/com/jcraft/jsch/SftpException.java
index 6a6c1ff8..7fb630e4 100644
--- a/java/com/jcraft/jsch/SftpException.java
+++ b/java/com/jcraft/jsch/SftpException.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/SftpProgressMonitor.java b/java/com/jcraft/jsch/SftpProgressMonitor.java
index bd91688d..cfc69e6b 100644
--- a/java/com/jcraft/jsch/SftpProgressMonitor.java
+++ b/java/com/jcraft/jsch/SftpProgressMonitor.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/SftpStatVFS.java b/java/com/jcraft/jsch/SftpStatVFS.java
new file mode 100644
index 00000000..872eddb9
--- /dev/null
+++ b/java/com/jcraft/jsch/SftpStatVFS.java
@@ -0,0 +1,122 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class SftpStatVFS {
+
+ /*
+ It seems data is serializsed according to sys/statvfs.h; for example,
+ http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/statvfs.h.html
+ */
+
+ private long bsize;
+ private long frsize;
+ private long blocks;
+ private long bfree;
+ private long bavail;
+ private long files;
+ private long ffree;
+ private long favail;
+ private long fsid;
+ private long flag;
+ private long namemax;
+
+ int flags=0;
+ long size;
+ int uid;
+ int gid;
+ int permissions;
+ int atime;
+ int mtime;
+ String[] extended=null;
+
+ private SftpStatVFS(){
+ }
+
+ static SftpStatVFS getStatVFS(Buffer buf){
+ SftpStatVFS statvfs=new SftpStatVFS();
+
+ statvfs.bsize = buf.getLong();
+ statvfs.frsize = buf.getLong();
+ statvfs.blocks = buf.getLong();
+ statvfs.bfree = buf.getLong();
+ statvfs.bavail = buf.getLong();
+ statvfs.files = buf.getLong();
+ statvfs.ffree = buf.getLong();
+ statvfs.favail = buf.getLong();
+ statvfs.fsid = buf.getLong();
+ int flag = (int)buf.getLong();
+ statvfs.namemax = buf.getLong();
+
+ statvfs.flag =
+ (flag & 1/*SSH2_FXE_STATVFS_ST_RDONLY*/) != 0 ? 1/*ST_RDONLY*/ : 0;
+ statvfs.flag |=
+ (flag & 2/*SSH2_FXE_STATVFS_ST_NOSUID*/) != 0 ? 2/*ST_NOSUID*/ : 0;
+
+ return statvfs;
+ }
+
+ public long getBlockSize() { return bsize; }
+ public long getFragmentSize() { return frsize; }
+ public long getBlocks() { return blocks; }
+ public long getFreeBlocks() { return bfree; }
+ public long getAvailBlocks() { return bavail; }
+ public long getINodes() { return files; }
+ public long getFreeINodes() { return ffree; }
+ public long getAvailINodes() { return favail; }
+ public long getFileSystemID() { return fsid; }
+ public long getMountFlag() { return flag; }
+ public long getMaximumFilenameLength() { return namemax; }
+
+ public long getSize(){
+ return getFragmentSize()*getBlocks()/1024;
+ }
+
+ public long getUsed(){
+ return getFragmentSize()*(getBlocks()-getFreeBlocks())/1024;
+ }
+
+ public long getAvailForNonRoot(){
+ return getFragmentSize()*getAvailBlocks()/1024;
+ }
+
+ public long getAvail(){
+ return getFragmentSize()*getFreeBlocks()/1024;
+ }
+
+ public int getCapacity(){
+ return (int)(100*(getBlocks()-getFreeBlocks())/getBlocks());
+ }
+
+// public String toString() { return ""; }
+}
diff --git a/java/com/jcraft/jsch/Signature.java b/java/com/jcraft/jsch/Signature.java
new file mode 100644
index 00000000..a517cfd3
--- /dev/null
+++ b/java/com/jcraft/jsch/Signature.java
@@ -0,0 +1,37 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2012-2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public interface Signature{
+ void init() throws Exception;
+ void update(byte[] H) throws Exception;
+ boolean verify(byte[] sig) throws Exception;
+ byte[] sign() throws Exception;
+}
diff --git a/java/com/jcraft/jsch/SignatureDSA.java b/java/com/jcraft/jsch/SignatureDSA.java
index 6f44b7ff..9cc0651e 100644
--- a/java/com/jcraft/jsch/SignatureDSA.java
+++ b/java/com/jcraft/jsch/SignatureDSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,11 +29,7 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;
-public interface SignatureDSA{
- void init() throws Exception;
+public interface SignatureDSA extends Signature {
void setPubKey(byte[] y, byte[] p, byte[] q, byte[] g) throws Exception;
void setPrvKey(byte[] x, byte[] p, byte[] q, byte[] g) throws Exception;
- void update(byte[] H) throws Exception;
- boolean verify(byte[] sig) throws Exception;
- byte[] sign() throws Exception;
}
diff --git a/java/com/jcraft/jsch/SignatureECDSA.java b/java/com/jcraft/jsch/SignatureECDSA.java
new file mode 100644
index 00000000..516a4906
--- /dev/null
+++ b/java/com/jcraft/jsch/SignatureECDSA.java
@@ -0,0 +1,35 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch;
+
+public interface SignatureECDSA extends Signature {
+ void setPubKey(byte[] r, byte[] s) throws Exception;
+ void setPrvKey(byte[] s) throws Exception;
+}
diff --git a/java/com/jcraft/jsch/SignatureRSA.java b/java/com/jcraft/jsch/SignatureRSA.java
index e8e61059..b31a8dcf 100644
--- a/java/com/jcraft/jsch/SignatureRSA.java
+++ b/java/com/jcraft/jsch/SignatureRSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,11 +29,7 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;
-public interface SignatureRSA{
- void init() throws Exception;
+public interface SignatureRSA extends Signature {
void setPubKey(byte[] e, byte[] n) throws Exception;
void setPrvKey(byte[] d, byte[] n) throws Exception;
- void update(byte[] H) throws Exception;
- boolean verify(byte[] sig) throws Exception;
- byte[] sign() throws Exception;
}
diff --git a/java/com/jcraft/jsch/SocketFactory.java b/java/com/jcraft/jsch/SocketFactory.java
index aaac0dce..532b7d4d 100644
--- a/java/com/jcraft/jsch/SocketFactory.java
+++ b/java/com/jcraft/jsch/SocketFactory.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/UIKeyboardInteractive.java b/java/com/jcraft/jsch/UIKeyboardInteractive.java
index 23af9c31..afc5217e 100644
--- a/java/com/jcraft/jsch/UIKeyboardInteractive.java
+++ b/java/com/jcraft/jsch/UIKeyboardInteractive.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/UserAuth.java b/java/com/jcraft/jsch/UserAuth.java
index 085a9508..8a74dc62 100644
--- a/java/com/jcraft/jsch/UserAuth.java
+++ b/java/com/jcraft/jsch/UserAuth.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java b/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java
index 15856cbc..2b0bdc7d 100644
--- a/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java
+++ b/java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java b/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java
index 29947965..389733e6 100644
--- a/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java
+++ b/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -128,7 +128,7 @@ class UserAuthKeyboardInteractive extends UserAuth{
if(password!=null &&
prompt.length==1 &&
!echo[0] &&
- prompt[0].toLowerCase().startsWith("password:")){
+ prompt[0].toLowerCase().indexOf("password:") >= 0){
response=new byte[1][];
response[0]=password;
password=null;
diff --git a/java/com/jcraft/jsch/UserAuthNone.java b/java/com/jcraft/jsch/UserAuthNone.java
index b3b0b077..4b04a1fa 100644
--- a/java/com/jcraft/jsch/UserAuthNone.java
+++ b/java/com/jcraft/jsch/UserAuthNone.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/UserAuthPassword.java b/java/com/jcraft/jsch/UserAuthPassword.java
index 9b5837f5..b10f4622 100644
--- a/java/com/jcraft/jsch/UserAuthPassword.java
+++ b/java/com/jcraft/jsch/UserAuthPassword.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/UserAuthPublicKey.java b/java/com/jcraft/jsch/UserAuthPublicKey.java
index 234ad0ac..129c124d 100644
--- a/java/com/jcraft/jsch/UserAuthPublicKey.java
+++ b/java/com/jcraft/jsch/UserAuthPublicKey.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,13 +31,12 @@ package com.jcraft.jsch;
import java.util.Vector;
-@SuppressWarnings({"rawtypes"})
class UserAuthPublicKey extends UserAuth{
public boolean start(Session session) throws Exception{
super.start(session);
- Vector identities=session.jsch.getIdentityRepository().getIdentities();
+ Vector identities=session.getIdentityRepository().getIdentities();
byte[] passphrase=null;
byte[] _username=null;
@@ -60,8 +59,6 @@ class UserAuthPublicKey extends UserAuth{
Identity identity=(Identity)(identities.elementAt(i));
byte[] pubkeyblob=identity.getPublicKeyBlob();
-//System.err.println("UserAuthPublicKey: "+identity+" "+pubkeyblob);
-
if(pubkeyblob!=null){
// send
// byte SSH_MSG_USERAUTH_REQUEST(50)
@@ -69,7 +66,8 @@ class UserAuthPublicKey extends UserAuth{
// string service name ("ssh-connection")
// string "publickey"
// boolen FALSE
- // string plaintext password (ISO-10646 UTF-8)
+ // string public key algorithm name
+ // string public key blob
packet.reset();
buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
buf.putString(_username);
@@ -132,8 +130,13 @@ class UserAuthPublicKey extends UserAuth{
}
if(!identity.isEncrypted() || passphrase!=null){
- if(identity.setPassphrase(passphrase))
+ if(identity.setPassphrase(passphrase)){
+ if(passphrase!=null &&
+ (session.getIdentityRepository() instanceof IdentityRepository.Wrapper)){
+ ((IdentityRepository.Wrapper)session.getIdentityRepository()).check();
+ }
break;
+ }
}
Util.bzero(passphrase);
passphrase=null;
@@ -152,13 +155,15 @@ class UserAuthPublicKey extends UserAuth{
if(pubkeyblob==null) continue;
- // send
- // byte SSH_MSG_USERAUTH_REQUEST(50)
- // string user name
- // string service name ("ssh-connection")
- // string "publickey"
- // boolen TRUE
- // string plaintext password (ISO-10646 UTF-8)
+ // send
+ // byte SSH_MSG_USERAUTH_REQUEST(50)
+ // string user name
+ // string service name ("ssh-connection")
+ // string "publickey"
+ // boolen TRUE
+ // string public key algorithm name
+ // string public key blob
+ // string signature
packet.reset();
buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
buf.putString(_username);
diff --git a/java/com/jcraft/jsch/UserInfo.java b/java/com/jcraft/jsch/UserInfo.java
index 22552ede..c7f9f478 100644
--- a/java/com/jcraft/jsch/UserInfo.java
+++ b/java/com/jcraft/jsch/UserInfo.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/Util.java b/java/com/jcraft/jsch/Util.java
index 8d51fc61..5974b0cb 100644
--- a/java/com/jcraft/jsch/Util.java
+++ b/java/com/jcraft/jsch/Util.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,8 +29,10 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;
import java.net.Socket;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
-@SuppressWarnings({"rawtypes","unchecked"})
class Util{
private static final byte[] b64 =Util.str2byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=");
@@ -41,20 +43,25 @@ class Util{
}
return 0;
}
- static byte[] fromBase64(byte[] buf, int start, int length){
- byte[] foo=new byte[length];
- int j=0;
- for (int i=start;i<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();
+ }
+ }
}
diff --git a/java/com/jcraft/jsch/jce/AES128CBC.java b/java/com/jcraft/jsch/jce/AES128CBC.java
index 8c2b43b5..1042776d 100644
--- a/java/com/jcraft/jsch/jce/AES128CBC.java
+++ b/java/com/jcraft/jsch/jce/AES128CBC.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2005-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -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;
diff --git a/java/com/jcraft/jsch/jce/AES128CTR.java b/java/com/jcraft/jsch/jce/AES128CTR.java
index 470a896b..6a1839e1 100644
--- a/java/com/jcraft/jsch/jce/AES128CTR.java
+++ b/java/com/jcraft/jsch/jce/AES128CTR.java
@@ -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;
diff --git a/java/com/jcraft/jsch/jce/AES192CBC.java b/java/com/jcraft/jsch/jce/AES192CBC.java
index 615d4943..f08dd7e6 100644
--- a/java/com/jcraft/jsch/jce/AES192CBC.java
+++ b/java/com/jcraft/jsch/jce/AES192CBC.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2005-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -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;
diff --git a/java/com/jcraft/jsch/jce/AES192CTR.java b/java/com/jcraft/jsch/jce/AES192CTR.java
index 74090bf9..93da4780 100644
--- a/java/com/jcraft/jsch/jce/AES192CTR.java
+++ b/java/com/jcraft/jsch/jce/AES192CTR.java
@@ -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;
diff --git a/java/com/jcraft/jsch/jce/AES256CBC.java b/java/com/jcraft/jsch/jce/AES256CBC.java
index 9018a204..3dbce644 100644
--- a/java/com/jcraft/jsch/jce/AES256CBC.java
+++ b/java/com/jcraft/jsch/jce/AES256CBC.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2005-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -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;
diff --git a/java/com/jcraft/jsch/jce/AES256CTR.java b/java/com/jcraft/jsch/jce/AES256CTR.java
index b7472e96..30e17e69 100644
--- a/java/com/jcraft/jsch/jce/AES256CTR.java
+++ b/java/com/jcraft/jsch/jce/AES256CTR.java
@@ -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;
diff --git a/java/com/jcraft/jsch/jce/ARCFOUR.java b/java/com/jcraft/jsch/jce/ARCFOUR.java
index 9f6537c3..5fd3e7a8 100644
--- a/java/com/jcraft/jsch/jce/ARCFOUR.java
+++ b/java/com/jcraft/jsch/jce/ARCFOUR.java
@@ -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;
diff --git a/java/com/jcraft/jsch/jce/ARCFOUR128.java b/java/com/jcraft/jsch/jce/ARCFOUR128.java
index d8b46137..51f568f9 100644
--- a/java/com/jcraft/jsch/jce/ARCFOUR128.java
+++ b/java/com/jcraft/jsch/jce/ARCFOUR128.java
@@ -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);
diff --git a/java/com/jcraft/jsch/jce/ARCFOUR256.java b/java/com/jcraft/jsch/jce/ARCFOUR256.java
index a4a9f690..226545fc 100644
--- a/java/com/jcraft/jsch/jce/ARCFOUR256.java
+++ b/java/com/jcraft/jsch/jce/ARCFOUR256.java
@@ -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);
diff --git a/java/com/jcraft/jsch/jce/BlowfishCBC.java b/java/com/jcraft/jsch/jce/BlowfishCBC.java
index 3853ab72..df63fe94 100644
--- a/java/com/jcraft/jsch/jce/BlowfishCBC.java
+++ b/java/com/jcraft/jsch/jce/BlowfishCBC.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -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;
diff --git a/java/com/jcraft/jsch/jce/DH.java b/java/com/jcraft/jsch/jce/DH.java
index da03c1de..d0503ad7 100644
--- a/java/com/jcraft/jsch/jce/DH.java
+++ b/java/com/jcraft/jsch/jce/DH.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -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
index 00000000..5efa20dc
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/ECDH256.java
@@ -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
index 00000000..26decd20
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/ECDH384.java
@@ -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
index 00000000..6a1ba81a
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/ECDH521.java
@@ -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
index 00000000..20119ce1
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/ECDHN.java
@@ -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
index 00000000..7a301dc2
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/HMAC.java
@@ -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;
+ }
+}
diff --git a/java/com/jcraft/jsch/jce/HMACMD5.java b/java/com/jcraft/jsch/jce/HMACMD5.java
index def3747b..6249c0b6 100644
--- a/java/com/jcraft/jsch/jce/HMACMD5.java
+++ b/java/com/jcraft/jsch/jce/HMACMD5.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -33,43 +33,10 @@ import com.jcraft.jsch.MAC;
import javax.crypto.*;
import javax.crypto.spec.*;
-public class HMACMD5 implements MAC{
- private static final String name="hmac-md5";
- private static final int BSIZE=16;
- private Mac mac;
- public int getBlockSize(){return BSIZE;};
- public void init(byte[] key) throws Exception{
- if(key.length>BSIZE){
- byte[] tmp=new byte[BSIZE];
- System.arraycopy(key, 0, tmp, 0, BSIZE);
- key=tmp;
- }
-
- SecretKeySpec skey=new SecretKeySpec(key, "HmacMD5");
- mac=Mac.getInstance("HmacMD5");
- mac.init(skey);
- }
-
- private final byte[] tmp=new byte[4];
- public void update(int i){
- tmp[0]=(byte)(i>>>24);
- tmp[1]=(byte)(i>>>16);
- tmp[2]=(byte)(i>>>8);
- tmp[3]=(byte)i;
- update(tmp, 0, 4);
- }
- public void update(byte foo[], int s, int l){
- mac.update(foo, s, l);
- }
- public void doFinal(byte[] buf, int offset){
- try{
- mac.doFinal(buf, offset);
- }
- catch(ShortBufferException e){
- }
- }
-
- public String getName(){
- return name;
+public class HMACMD5 extends HMAC {
+ public HMACMD5(){
+ name = "hmac-md5";
+ bsize = 16;
+ algorithm = "HmacMD5";
}
}
diff --git a/java/com/jcraft/jsch/jce/HMACMD596.java b/java/com/jcraft/jsch/jce/HMACMD596.java
index a296a5df..b9809316 100644
--- a/java/com/jcraft/jsch/jce/HMACMD596.java
+++ b/java/com/jcraft/jsch/jce/HMACMD596.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,49 +29,18 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch.jce;
-import com.jcraft.jsch.MAC;
-import javax.crypto.*;
-import javax.crypto.spec.*;
-
-public class HMACMD596 implements MAC{
- private static final String name="hmac-md5-96";
- private static final int bsize=12;
- private Mac mac;
- public int getBlockSize(){return bsize;};
- public void init(byte[] key) throws Exception{
- if(key.length>16){
- byte[] tmp=new byte[16];
- System.arraycopy(key, 0, tmp, 0, 16);
- key=tmp;
- }
- SecretKeySpec skey=new SecretKeySpec(key, "HmacMD5");
- mac=Mac.getInstance("HmacMD5");
- mac.init(skey);
- }
- private final byte[] tmp=new byte[4];
- public void update(int i){
- tmp[0]=(byte)(i>>>24);
- tmp[1]=(byte)(i>>>16);
- tmp[2]=(byte)(i>>>8);
- tmp[3]=(byte)i;
- update(tmp, 0, 4);
+public class HMACMD596 extends HMACMD5 {
+ public HMACMD596(){
+ name="hmac-md5-96";
}
- public void update(byte foo[], int s, int l){
- mac.update(foo, s, l);
- }
+ public int getBlockSize(){
+ return 12;
+ };
- private final byte[] _buf16=new byte[16];
+ private final byte[] _buf16 = new byte[16];
public void doFinal(byte[] buf, int offset){
- try{
- mac.doFinal(_buf16, 0);
- }
- catch(ShortBufferException e){
- }
+ super.doFinal(_buf16, 0);
System.arraycopy(_buf16, 0, buf, offset, 12);
}
-
- public String getName(){
- return name;
- }
}
diff --git a/java/com/jcraft/jsch/jce/HMACSHA1.java b/java/com/jcraft/jsch/jce/HMACSHA1.java
index 13feaabf..12f3de5f 100644
--- a/java/com/jcraft/jsch/jce/HMACSHA1.java
+++ b/java/com/jcraft/jsch/jce/HMACSHA1.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,47 +29,10 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch.jce;
-import com.jcraft.jsch.MAC;
-import javax.crypto.*;
-import javax.crypto.spec.*;
-
-public class HMACSHA1 implements MAC{
- private static final String name="hmac-sha1";
- private static final int bsize=20;
- private Mac mac;
- public int getBlockSize(){return bsize;};
- public void init(byte[] key) throws Exception{
- if(key.length>bsize){
- byte[] tmp=new byte[bsize];
- System.arraycopy(key, 0, tmp, 0, bsize);
- key=tmp;
- }
- SecretKeySpec skey=new SecretKeySpec(key, "HmacSHA1");
- mac=Mac.getInstance("HmacSHA1");
- mac.init(skey);
- }
- private final byte[] tmp=new byte[4];
- public void update(int i){
- tmp[0]=(byte)(i>>>24);
- tmp[1]=(byte)(i>>>16);
- tmp[2]=(byte)(i>>>8);
- tmp[3]=(byte)i;
- update(tmp, 0, 4);
- }
-
- public void update(byte foo[], int s, int l){
- mac.update(foo, s, l);
- }
-
- public void doFinal(byte[] buf, int offset){
- try{
- mac.doFinal(buf, offset);
- }
- catch(ShortBufferException e){
- }
- }
-
- public String getName(){
- return name;
+public class HMACSHA1 extends HMAC {
+ public HMACSHA1(){
+ name = "hmac-sha1";
+ bsize = 20;
+ algorithm = "HmacSHA1";
}
}
diff --git a/java/com/jcraft/jsch/jce/HMACSHA196.java b/java/com/jcraft/jsch/jce/HMACSHA196.java
index e8791762..ab3b07b9 100644
--- a/java/com/jcraft/jsch/jce/HMACSHA196.java
+++ b/java/com/jcraft/jsch/jce/HMACSHA196.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,48 +29,19 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch.jce;
-import com.jcraft.jsch.MAC;
-import javax.crypto.*;
-import javax.crypto.spec.*;
+public class HMACSHA196 extends HMACSHA1 {
-public class HMACSHA196 implements MAC{
- private static final String name="hmac-sha1-96";
- private static final int bsize=12;
- private Mac mac;
- public int getBlockSize(){return bsize;};
- public void init(byte[] key) throws Exception{
- if(key.length>20){
- byte[] tmp=new byte[20];
- System.arraycopy(key, 0, tmp, 0, 20);
- key=tmp;
- }
- SecretKeySpec skey=new SecretKeySpec(key, "HmacSHA1");
- mac=Mac.getInstance("HmacSHA1");
- mac.init(skey);
- }
- private final byte[] tmp=new byte[4];
- public void update(int i){
- tmp[0]=(byte)(i>>>24);
- tmp[1]=(byte)(i>>>16);
- tmp[2]=(byte)(i>>>8);
- tmp[3]=(byte)i;
- update(tmp, 0, 4);
- }
- public void update(byte foo[], int s, int l){
- mac.update(foo, s, l);
+ public HMACSHA196(){
+ name = "hmac-sha1-96";
}
- private final byte[] _buf20=new byte[20];
+ public int getBlockSize(){
+ return 12;
+ };
+
+ private final byte[] _buf20 = new byte[20];
public void doFinal(byte[] buf, int offset){
- try{
- mac.doFinal(_buf20, 0);
- }
- catch(ShortBufferException e){
- }
+ super.doFinal(_buf20, 0);
System.arraycopy(_buf20, 0, buf, offset, 12);
}
-
- public String getName(){
- return name;
- }
}
diff --git a/java/com/jcraft/jsch/jce/HMACSHA256.java b/java/com/jcraft/jsch/jce/HMACSHA256.java
new file mode 100644
index 00000000..d3cebf49
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/HMACSHA256.java
@@ -0,0 +1,38 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2012-2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch.jce;
+
+public class HMACSHA256 extends HMAC {
+ public HMACSHA256(){
+ name = "hmac-sha2-256";
+ bsize = 32;
+ algorithm = "HmacSHA256";
+ }
+}
diff --git a/java/com/jcraft/jsch/jce/HMACSHA512.java b/java/com/jcraft/jsch/jce/HMACSHA512.java
new file mode 100644
index 00000000..41433435
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/HMACSHA512.java
@@ -0,0 +1,38 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2012-2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch.jce;
+
+public class HMACSHA512 extends HMAC {
+ public HMACSHA512(){
+ name = "hmac-sha2-512";
+ bsize = 64;
+ algorithm = "HmacSHA512";
+ }
+}
diff --git a/java/com/jcraft/jsch/jce/KeyPairGenDSA.java b/java/com/jcraft/jsch/jce/KeyPairGenDSA.java
index 67ad54eb..722e7043 100644
--- a/java/com/jcraft/jsch/jce/KeyPairGenDSA.java
+++ b/java/com/jcraft/jsch/jce/KeyPairGenDSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java b/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java
new file mode 100644
index 00000000..54b1e8e9
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/KeyPairGenECDSA.java
@@ -0,0 +1,96 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2015 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.jcraft.jsch.jce;
+
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
+import com.jcraft.jsch.JSchException;
+
+public class KeyPairGenECDSA implements com.jcraft.jsch.KeyPairGenECDSA {
+ byte[] d;
+ byte[] r;
+ byte[] s;
+ ECPublicKey pubKey;
+ ECPrivateKey prvKey;
+ ECParameterSpec params;
+ public void init(int key_size) throws Exception {
+ String name=null;
+ if(key_size==256) name="secp256r1";
+ else if(key_size==384) name="secp384r1";
+ else if(key_size==521) name="secp521r1";
+ else throw new JSchException("unsupported key size: "+key_size);
+
+ for(int i = 0; i<1000; i++) {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
+ ECGenParameterSpec ecsp = new ECGenParameterSpec(name);
+ kpg.initialize(ecsp);
+ KeyPair kp = kpg.genKeyPair();
+ prvKey = (ECPrivateKey)kp.getPrivate();
+ pubKey = (ECPublicKey)kp.getPublic();
+ params=pubKey.getParams();
+ d=((ECPrivateKey)prvKey).getS().toByteArray();
+ ECPoint w = pubKey.getW();
+ r = w.getAffineX().toByteArray();
+ s = w.getAffineY().toByteArray();
+
+ if(r.length!=s.length) continue;
+ if(key_size==256 && r.length==32) break;
+ if(key_size==384 && r.length==48) break;
+ if(key_size==521 && r.length==66) break;
+ }
+ if(d.length<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;
+ }
+}
diff --git a/java/com/jcraft/jsch/jce/KeyPairGenRSA.java b/java/com/jcraft/jsch/jce/KeyPairGenRSA.java
index 543f0f79..8d4b86ef 100644
--- a/java/com/jcraft/jsch/jce/KeyPairGenRSA.java
+++ b/java/com/jcraft/jsch/jce/KeyPairGenRSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jce/MD5.java b/java/com/jcraft/jsch/jce/MD5.java
index 538ae340..96db7ae7 100644
--- a/java/com/jcraft/jsch/jce/MD5.java
+++ b/java/com/jcraft/jsch/jce/MD5.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jce/PBKDF.java b/java/com/jcraft/jsch/jce/PBKDF.java
new file mode 100644
index 00000000..7b03bf62
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/PBKDF.java
@@ -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;
+ }
+}
diff --git a/java/com/jcraft/jsch/jce/Random.java b/java/com/jcraft/jsch/jce/Random.java
index 8668a01a..aebdaa52 100644
--- a/java/com/jcraft/jsch/jce/Random.java
+++ b/java/com/jcraft/jsch/jce/Random.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jce/SHA1.java b/java/com/jcraft/jsch/jce/SHA1.java
index 08fce4b0..2bc6c97f 100644
--- a/java/com/jcraft/jsch/jce/SHA1.java
+++ b/java/com/jcraft/jsch/jce/SHA1.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jce/SHA256.java b/java/com/jcraft/jsch/jce/SHA256.java
new file mode 100644
index 00000000..70a88b07
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/SHA256.java
@@ -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
index 00000000..eeb5b1e4
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/SHA384.java
@@ -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
index 00000000..d56eafd7
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/SHA512.java
@@ -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();
+ }
+}
diff --git a/java/com/jcraft/jsch/jce/SignatureDSA.java b/java/com/jcraft/jsch/jce/SignatureDSA.java
index 262dfc5e..0f7ec4a5 100644
--- a/java/com/jcraft/jsch/jce/SignatureDSA.java
+++ b/java/com/jcraft/jsch/jce/SignatureDSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jce/SignatureECDSA.java b/java/com/jcraft/jsch/jce/SignatureECDSA.java
new file mode 100644
index 00000000..1f3e0aa0
--- /dev/null
+++ b/java/com/jcraft/jsch/jce/SignatureECDSA.java
@@ -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;
+ }
+}
diff --git a/java/com/jcraft/jsch/jce/SignatureRSA.java b/java/com/jcraft/jsch/jce/SignatureRSA.java
index 50d8b5a8..07dff18c 100644
--- a/java/com/jcraft/jsch/jce/SignatureRSA.java
+++ b/java/com/jcraft/jsch/jce/SignatureRSA.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jce/TripleDESCBC.java b/java/com/jcraft/jsch/jce/TripleDESCBC.java
index 2cbf9b75..ec084959 100644
--- a/java/com/jcraft/jsch/jce/TripleDESCBC.java
+++ b/java/com/jcraft/jsch/jce/TripleDESCBC.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -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;
diff --git a/java/com/jcraft/jsch/jce/TripleDESCTR.java b/java/com/jcraft/jsch/jce/TripleDESCTR.java
index 899f03bd..3793e9dd 100644
--- a/java/com/jcraft/jsch/jce/TripleDESCTR.java
+++ b/java/com/jcraft/jsch/jce/TripleDESCTR.java
@@ -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;
diff --git a/java/com/jcraft/jsch/jcraft/Compression.java b/java/com/jcraft/jsch/jcraft/Compression.java
index cb1f3170..05963feb 100644
--- a/java/com/jcraft/jsch/jcraft/Compression.java
+++ b/java/com/jcraft/jsch/jcraft/Compression.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -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
diff --git a/java/com/jcraft/jsch/jcraft/HMAC.java b/java/com/jcraft/jsch/jcraft/HMAC.java
index 9aedc27f..34f3cdd4 100644
--- a/java/com/jcraft/jsch/jcraft/HMAC.java
+++ b/java/com/jcraft/jsch/jcraft/HMAC.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -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);
diff --git a/java/com/jcraft/jsch/jcraft/HMACMD5.java b/java/com/jcraft/jsch/jcraft/HMACMD5.java
index 90960113..850e81db 100644
--- a/java/com/jcraft/jsch/jcraft/HMACMD5.java
+++ b/java/com/jcraft/jsch/jcraft/HMACMD5.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jcraft/HMACMD596.java b/java/com/jcraft/jsch/jcraft/HMACMD596.java
index 95c6f60d..56593939 100644
--- a/java/com/jcraft/jsch/jcraft/HMACMD596.java
+++ b/java/com/jcraft/jsch/jcraft/HMACMD596.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jcraft/HMACSHA1.java b/java/com/jcraft/jsch/jcraft/HMACSHA1.java
index ea9eccf1..6dbb9de0 100644
--- a/java/com/jcraft/jsch/jcraft/HMACSHA1.java
+++ b/java/com/jcraft/jsch/jcraft/HMACSHA1.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jcraft/HMACSHA196.java b/java/com/jcraft/jsch/jcraft/HMACSHA196.java
index 86a81b5b..0a49f548 100644
--- a/java/com/jcraft/jsch/jcraft/HMACSHA196.java
+++ b/java/com/jcraft/jsch/jcraft/HMACSHA196.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jsch/jgss/GSSContextKrb5.java b/java/com/jcraft/jsch/jgss/GSSContextKrb5.java
index 9ee1560e..8f72f35d 100644
--- a/java/com/jcraft/jsch/jgss/GSSContextKrb5.java
+++ b/java/com/jcraft/jsch/jgss/GSSContextKrb5.java
@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
-Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
+Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/java/com/jcraft/jzlib/Deflate.java b/java/com/jcraft/jzlib/Deflate.java
index baaac9be..cfda0f0b 100644
--- a/java/com/jcraft/jzlib/Deflate.java
+++ b/java/com/jcraft/jzlib/Deflate.java
@@ -263,6 +263,8 @@ final class Deflate implements Cloneable {
// number of codes at each bit length for an optimal tree
short[] bl_count=new short[MAX_BITS+1];
+ // working area to be used in Tree#gen_codes()
+ short[] next_code=new short[MAX_BITS+1];
// heap used to build the Huffman trees
int[] heap=new int[2*L_CODES+1];
@@ -275,7 +277,7 @@ final class Deflate implements Cloneable {
// Depth of each subtree used as tie breaker for trees of equal frequency
byte[] depth=new byte[2*L_CODES+1];
- int l_buf; // index for literals or lengths */
+ byte[] l_buf; // index for literals or lengths */
// Size of match buffer for literals/lengths. There are 4 reasons for
// limiting lit_bufsize to 64K:
@@ -630,7 +632,7 @@ final class Deflate implements Cloneable {
pending_buf[d_buf+last_lit*2] = (byte)(dist>>>8);
pending_buf[d_buf+last_lit*2+1] = (byte)dist;
- pending_buf[l_buf+last_lit] = (byte)lc; last_lit++;
+ l_buf[last_lit] = (byte)lc; last_lit++;
if (dist == 0) {
// lc is the unmatched char
@@ -675,7 +677,7 @@ final class Deflate implements Cloneable {
do{
dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)|
(pending_buf[d_buf+lx*2+1]&0xff);
- lc=(pending_buf[l_buf+lx])&0xff; lx++;
+ lc=(l_buf[lx])&0xff; lx++;
if(dist == 0){
send_code(lc, ltree); // send a literal byte
@@ -1379,11 +1381,11 @@ final class Deflate implements Cloneable {
// We overlay pending_buf and d_buf+l_buf. This works since the average
// output size for (length,distance) codes is <= 24 bits.
- pending_buf = new byte[lit_bufsize*4];
- pending_buf_size = lit_bufsize*4;
+ pending_buf = new byte[lit_bufsize*3];
+ pending_buf_size = lit_bufsize*3;
- d_buf = lit_bufsize/2;
- l_buf = (1+2)*lit_bufsize;
+ d_buf = lit_bufsize;
+ l_buf = new byte[lit_bufsize];
this.level = level;
@@ -1420,6 +1422,7 @@ final class Deflate implements Cloneable {
}
// Deallocate in reverse order of allocations:
pending_buf=null;
+ l_buf=null;
head=null;
prev=null;
window=null;
@@ -1697,6 +1700,8 @@ final class Deflate implements Cloneable {
Deflate dest = (Deflate)super.clone();
dest.pending_buf = dup(dest.pending_buf);
+ dest.d_buf = dest.d_buf;
+ dest.l_buf = dup(dest.l_buf);
dest.window = dup(dest.window);
dest.prev = dup(dest.prev);
@@ -1706,6 +1711,7 @@ final class Deflate implements Cloneable {
dest.bl_tree = dup(dest.bl_tree);
dest.bl_count = dup(dest.bl_count);
+ dest.next_code = dup(dest.next_code);
dest.heap = dup(dest.heap);
dest.depth = dup(dest.depth);
diff --git a/java/com/jcraft/jzlib/Deflater.java b/java/com/jcraft/jzlib/Deflater.java
new file mode 100644
index 00000000..ce0580dd
--- /dev/null
+++ b/java/com/jcraft/jzlib/Deflater.java
@@ -0,0 +1,171 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final public class Deflater extends ZStream{
+
+ static final private int MAX_WBITS=15; // 32K LZ77 window
+ static final private int DEF_WBITS=MAX_WBITS;
+
+ static final private int Z_NO_FLUSH=0;
+ static final private int Z_PARTIAL_FLUSH=1;
+ static final private int Z_SYNC_FLUSH=2;
+ static final private int Z_FULL_FLUSH=3;
+ static final private int Z_FINISH=4;
+
+ static final private int MAX_MEM_LEVEL=9;
+
+ static final private int Z_OK=0;
+ static final private int Z_STREAM_END=1;
+ static final private int Z_NEED_DICT=2;
+ static final private int Z_ERRNO=-1;
+ static final private int Z_STREAM_ERROR=-2;
+ static final private int Z_DATA_ERROR=-3;
+ static final private int Z_MEM_ERROR=-4;
+ static final private int Z_BUF_ERROR=-5;
+ static final private int Z_VERSION_ERROR=-6;
+
+ private boolean finished = false;
+
+ public Deflater(){
+ super();
+ }
+
+ public Deflater(int level) throws GZIPException {
+ this(level, MAX_WBITS);
+ }
+
+ public Deflater(int level, boolean nowrap) throws GZIPException {
+ this(level, MAX_WBITS, nowrap);
+ }
+
+ public Deflater(int level, int bits) throws GZIPException {
+ this(level, bits, false);
+ }
+
+ public Deflater(int level, int bits, boolean nowrap) throws GZIPException {
+ super();
+ int ret = init(level, bits, nowrap);
+ if(ret!=Z_OK)
+ throw new GZIPException(ret+": "+msg);
+ }
+
+ public Deflater(int level, int bits, int memlevel, JZlib.WrapperType wrapperType) throws GZIPException {
+ super();
+ int ret = init(level, bits, memlevel, wrapperType);
+ if(ret!=Z_OK)
+ throw new GZIPException(ret+": "+msg);
+ }
+
+ public Deflater(int level, int bits, int memlevel) throws GZIPException {
+ super();
+ int ret = init(level, bits, memlevel);
+ if(ret!=Z_OK)
+ throw new GZIPException(ret+": "+msg);
+ }
+
+ public int init(int level){
+ return init(level, MAX_WBITS);
+ }
+ public int init(int level, boolean nowrap){
+ return init(level, MAX_WBITS, nowrap);
+ }
+ public int init(int level, int bits){
+ return init(level, bits, false);
+ }
+ public int init(int level, int bits, int memlevel, JZlib.WrapperType wrapperType){
+ if(bits < 9 || bits > 15){
+ return Z_STREAM_ERROR;
+ }
+ if(wrapperType == JZlib.W_NONE) {
+ bits *= -1;
+ }
+ else if(wrapperType == JZlib.W_GZIP) {
+ bits += 16;
+ }
+ else if(wrapperType == JZlib.W_ANY) {
+ return Z_STREAM_ERROR;
+ }
+ else if(wrapperType == JZlib.W_ZLIB) {
+ }
+ return init(level, bits, memlevel);
+ }
+ public int init(int level, int bits, int memlevel){
+ finished = false;
+ dstate=new Deflate(this);
+ return dstate.deflateInit(level, bits, memlevel);
+ }
+ public int init(int level, int bits, boolean nowrap){
+ finished = false;
+ dstate=new Deflate(this);
+ return dstate.deflateInit(level, nowrap?-bits:bits);
+ }
+
+ public int deflate(int flush){
+ if(dstate==null){
+ return Z_STREAM_ERROR;
+ }
+ int ret = dstate.deflate(flush);
+ if(ret == Z_STREAM_END)
+ finished = true;
+ return ret;
+ }
+ public int end(){
+ finished = true;
+ if(dstate==null) return Z_STREAM_ERROR;
+ int ret=dstate.deflateEnd();
+ dstate=null;
+ free();
+ return ret;
+ }
+ public int params(int level, int strategy){
+ if(dstate==null) return Z_STREAM_ERROR;
+ return dstate.deflateParams(level, strategy);
+ }
+ public int setDictionary (byte[] dictionary, int dictLength){
+ if(dstate == null)
+ return Z_STREAM_ERROR;
+ return dstate.deflateSetDictionary(dictionary, dictLength);
+ }
+
+ public boolean finished(){
+ return finished;
+ }
+
+ public int copy(Deflater src){
+ this.finished = src.finished;
+ return Deflate.deflateCopy(this, src);
+ }
+}
diff --git a/java/com/jcraft/jzlib/DeflaterOutputStream.java b/java/com/jcraft/jzlib/DeflaterOutputStream.java
new file mode 100644
index 00000000..4c9f0d25
--- /dev/null
+++ b/java/com/jcraft/jzlib/DeflaterOutputStream.java
@@ -0,0 +1,181 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jcraft.jzlib;
+import java.io.*;
+
+public class DeflaterOutputStream extends FilterOutputStream {
+
+ protected final Deflater deflater;
+
+ protected byte[] buffer;
+
+ private boolean closed = false;
+
+ private boolean syncFlush = false;
+
+ private final byte[] buf1 = new byte[1];
+
+ protected boolean mydeflater = false;
+
+ private boolean close_out = true;
+
+ protected static final int DEFAULT_BUFSIZE = 512;
+
+ public DeflaterOutputStream(OutputStream out) throws IOException {
+ this(out,
+ new Deflater(JZlib.Z_DEFAULT_COMPRESSION),
+ DEFAULT_BUFSIZE, true);
+ mydeflater = true;
+ }
+
+ public DeflaterOutputStream(OutputStream out, Deflater def) throws IOException {
+ this(out, def, DEFAULT_BUFSIZE, true);
+ }
+
+ public DeflaterOutputStream(OutputStream out,
+ Deflater deflater,
+ int size) throws IOException {
+ this(out, deflater, size, true);
+ }
+ public DeflaterOutputStream(OutputStream out,
+ Deflater deflater,
+ int size,
+ boolean close_out) throws IOException {
+ super(out);
+ if (out == null || deflater == null) {
+ throw new NullPointerException();
+ }
+ else if (size <= 0) {
+ throw new IllegalArgumentException("buffer size must be greater than 0");
+ }
+ this.deflater = deflater;
+ buffer = new byte[size];
+ this.close_out = close_out;
+ }
+
+ public void write(int b) throws IOException {
+ buf1[0] = (byte)(b & 0xff);
+ write(buf1, 0, 1);
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (deflater.finished()) {
+ throw new IOException("finished");
+ }
+ else if (off<0 | len<0 | off+len>b.length) {
+ throw new IndexOutOfBoundsException();
+ }
+ else if (len == 0) {
+ return;
+ }
+ else {
+ int flush = syncFlush ? JZlib.Z_SYNC_FLUSH : JZlib.Z_NO_FLUSH;
+ deflater.setInput(b, off, len, true);
+ while (deflater.avail_in>0) {
+ int err = deflate(flush);
+ if (err == JZlib.Z_STREAM_END)
+ break;
+ }
+ }
+ }
+
+ public void finish() throws IOException {
+ while (!deflater.finished()) {
+ deflate(JZlib.Z_FINISH);
+ }
+ }
+
+ public void close() throws IOException {
+ if (!closed) {
+ finish();
+ if (mydeflater){
+ deflater.end();
+ }
+ if(close_out)
+ out.close();
+ closed = true;
+ }
+ }
+
+ protected int deflate(int flush) throws IOException {
+ deflater.setOutput(buffer, 0, buffer.length);
+ int err = deflater.deflate(flush);
+ switch(err) {
+ case JZlib.Z_OK:
+ case JZlib.Z_STREAM_END:
+ break;
+ case JZlib.Z_BUF_ERROR:
+ if(deflater.avail_in<=0 && flush!=JZlib.Z_FINISH){
+ // flush() without any data
+ break;
+ }
+ default:
+ throw new IOException("failed to deflate");
+ }
+ int len = deflater.next_out_index;
+ if (len > 0) {
+ out.write(buffer, 0, len);
+ }
+ return err;
+ }
+
+ public void flush() throws IOException {
+ if (syncFlush && !deflater.finished()) {
+ while (true) {
+ int err = deflate(JZlib.Z_SYNC_FLUSH);
+ if (deflater.next_out_index < buffer.length)
+ break;
+ if (err == JZlib.Z_STREAM_END)
+ break;
+ }
+ }
+ out.flush();
+ }
+
+ public long getTotalIn() {
+ return deflater.getTotalIn();
+ }
+
+ public long getTotalOut() {
+ return deflater.getTotalOut();
+ }
+
+ public void setSyncFlush(boolean syncFlush){
+ this.syncFlush = syncFlush;
+ }
+
+ public boolean getSyncFlush(){
+ return this.syncFlush;
+ }
+
+ public Deflater getDeflater(){
+ return deflater;
+ }
+}
diff --git a/java/com/jcraft/jzlib/GZIPException.java b/java/com/jcraft/jzlib/GZIPException.java
new file mode 100644
index 00000000..0beef40d
--- /dev/null
+++ b/java/com/jcraft/jzlib/GZIPException.java
@@ -0,0 +1,44 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+public class GZIPException extends java.io.IOException {
+ public GZIPException() {
+ super();
+ }
+ public GZIPException(String s) {
+ super(s);
+ }
+}
diff --git a/java/com/jcraft/jzlib/GZIPInputStream.java b/java/com/jcraft/jzlib/GZIPInputStream.java
new file mode 100644
index 00000000..5d29dca7
--- /dev/null
+++ b/java/com/jcraft/jzlib/GZIPInputStream.java
@@ -0,0 +1,145 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jcraft.jzlib;
+import java.io.*;
+
+public class GZIPInputStream extends InflaterInputStream {
+
+ public GZIPInputStream(InputStream in) throws IOException {
+ this(in, DEFAULT_BUFSIZE, true);
+ }
+
+ public GZIPInputStream(InputStream in,
+ int size,
+ boolean close_in) throws IOException {
+ this(in, new Inflater(15+16), size, close_in);
+ myinflater = true;
+ }
+
+ public GZIPInputStream(InputStream in,
+ Inflater inflater,
+ int size,
+ boolean close_in) throws IOException {
+ super(in, inflater, size, close_in);
+ }
+
+ public long getModifiedtime() {
+ return inflater.istate.getGZIPHeader().getModifiedTime();
+ }
+
+ public int getOS() {
+ return inflater.istate.getGZIPHeader().getOS();
+ }
+
+ public String getName() {
+ return inflater.istate.getGZIPHeader().getName();
+ }
+
+ public String getComment() {
+ return inflater.istate.getGZIPHeader().getComment();
+ }
+
+ public long getCRC() throws GZIPException {
+ if(inflater.istate.mode != 12 /*DONE*/)
+ throw new GZIPException("checksum is not calculated yet.");
+ return inflater.istate.getGZIPHeader().getCRC();
+ }
+
+ public void readHeader() throws IOException {
+
+ byte[] empty = "".getBytes();
+ inflater.setOutput(empty, 0, 0);
+ inflater.setInput(empty, 0, 0, false);
+
+ byte[] b = new byte[10];
+
+ int n = fill(b);
+ if(n!=10){
+ if(n>0){
+ inflater.setInput(b, 0, n, false);
+ //inflater.next_in_index = n;
+ inflater.next_in_index = 0;
+ inflater.avail_in = n;
+ }
+ throw new IOException("no input");
+ }
+
+ inflater.setInput(b, 0, n, false);
+
+ byte[] b1 = new byte[1];
+ do{
+ if(inflater.avail_in<=0){
+ int i = in.read(b1);
+ if(i<=0)
+ throw new IOException("no input");
+ inflater.setInput(b1, 0, 1, true);
+ }
+
+ int err = inflater.inflate(JZlib.Z_NO_FLUSH);
+
+ if(err!=0/*Z_OK*/){
+ int len = 2048-inflater.next_in.length;
+ if(len>0){
+ byte[] tmp = new byte[len];
+ n = fill(tmp);
+ if(n>0){
+ inflater.avail_in += inflater.next_in_index;
+ inflater.next_in_index = 0;
+ inflater.setInput(tmp, 0, n, true);
+ }
+ }
+ //inflater.next_in_index = inflater.next_in.length;
+ inflater.avail_in += inflater.next_in_index;
+ inflater.next_in_index = 0;
+ throw new IOException(inflater.msg);
+ }
+ }
+ while(inflater.istate.inParsingHeader());
+ }
+
+ private int fill(byte[] buf) {
+ int len = buf.length;
+ int n = 0;
+ do{
+ int i = -1;
+ try {
+ i = in.read(buf, n, buf.length - n);
+ }
+ catch(IOException e){
+ }
+ if(i == -1){
+ break;
+ }
+ n+=i;
+ }
+ while(n<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
index 00000000..54dcf8ec
--- /dev/null
+++ b/java/com/jcraft/jzlib/GZIPOutputStream.java
@@ -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();
+ }
+}
diff --git a/java/com/jcraft/jzlib/Inflate.java b/java/com/jcraft/jzlib/Inflate.java
index 6aa6240c..a9693325 100644
--- a/java/com/jcraft/jzlib/Inflate.java
+++ b/java/com/jcraft/jzlib/Inflate.java
@@ -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
index 00000000..0fb0b098
--- /dev/null
+++ b/java/com/jcraft/jzlib/Inflater.java
@@ -0,0 +1,168 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final public class Inflater extends ZStream{
+
+ static final private int MAX_WBITS=15; // 32K LZ77 window
+ static final private int DEF_WBITS=MAX_WBITS;
+
+ static final private int Z_NO_FLUSH=0;
+ static final private int Z_PARTIAL_FLUSH=1;
+ static final private int Z_SYNC_FLUSH=2;
+ static final private int Z_FULL_FLUSH=3;
+ static final private int Z_FINISH=4;
+
+ static final private int MAX_MEM_LEVEL=9;
+
+ static final private int Z_OK=0;
+ static final private int Z_STREAM_END=1;
+ static final private int Z_NEED_DICT=2;
+ static final private int Z_ERRNO=-1;
+ static final private int Z_STREAM_ERROR=-2;
+ static final private int Z_DATA_ERROR=-3;
+ static final private int Z_MEM_ERROR=-4;
+ static final private int Z_BUF_ERROR=-5;
+ static final private int Z_VERSION_ERROR=-6;
+
+ public Inflater() {
+ super();
+ init();
+ }
+
+ public Inflater(JZlib.WrapperType wrapperType) throws GZIPException {
+ this(DEF_WBITS, wrapperType);
+ }
+
+ public Inflater(int w, JZlib.WrapperType wrapperType) throws GZIPException {
+ super();
+ int ret = init(w, wrapperType);
+ if(ret!=Z_OK)
+ throw new GZIPException(ret+": "+msg);
+ }
+
+ public Inflater(int w) throws GZIPException {
+ this(w, false);
+ }
+
+ public Inflater(boolean nowrap) throws GZIPException {
+ this(DEF_WBITS, nowrap);
+ }
+
+ public Inflater(int w, boolean nowrap) throws GZIPException {
+ super();
+ int ret = init(w, nowrap);
+ if(ret!=Z_OK)
+ throw new GZIPException(ret+": "+msg);
+ }
+
+ private boolean finished = false;
+
+ public int init(){
+ return init(DEF_WBITS);
+ }
+
+ public int init(JZlib.WrapperType wrapperType){
+ return init(DEF_WBITS, wrapperType);
+ }
+
+ public int init(int w, JZlib.WrapperType wrapperType) {
+ boolean nowrap = false;
+ if(wrapperType == JZlib.W_NONE){
+ nowrap = true;
+ }
+ else if(wrapperType == JZlib.W_GZIP) {
+ w += 16;
+ }
+ else if(wrapperType == JZlib.W_ANY) {
+ w |= Inflate.INFLATE_ANY;
+ }
+ else if(wrapperType == JZlib.W_ZLIB) {
+ }
+ return init(w, nowrap);
+ }
+
+ public int init(boolean nowrap){
+ return init(DEF_WBITS, nowrap);
+ }
+
+ public int init(int w){
+ return init(w, false);
+ }
+
+ public int init(int w, boolean nowrap){
+ finished = false;
+ istate=new Inflate(this);
+ return istate.inflateInit(nowrap?-w:w);
+ }
+
+ public int inflate(int f){
+ if(istate==null) return Z_STREAM_ERROR;
+ int ret = istate.inflate(f);
+ if(ret == Z_STREAM_END)
+ finished = true;
+ return ret;
+ }
+
+ public int end(){
+ finished = true;
+ if(istate==null) return Z_STREAM_ERROR;
+ int ret=istate.inflateEnd();
+// istate = null;
+ return ret;
+ }
+
+ public int sync(){
+ if(istate == null)
+ return Z_STREAM_ERROR;
+ return istate.inflateSync();
+ }
+
+ public int syncPoint(){
+ if(istate == null)
+ return Z_STREAM_ERROR;
+ return istate.inflateSyncPoint();
+ }
+
+ public int setDictionary(byte[] dictionary, int dictLength){
+ if(istate == null)
+ return Z_STREAM_ERROR;
+ return istate.inflateSetDictionary(dictionary, dictLength);
+ }
+
+ public boolean finished(){
+ return istate.mode==12 /*DONE*/;
+ }
+}
diff --git a/java/com/jcraft/jzlib/InflaterInputStream.java b/java/com/jcraft/jzlib/InflaterInputStream.java
new file mode 100644
index 00000000..0420582a
--- /dev/null
+++ b/java/com/jcraft/jzlib/InflaterInputStream.java
@@ -0,0 +1,247 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jcraft.jzlib;
+import java.io.*;
+
+public class InflaterInputStream extends FilterInputStream {
+ protected final Inflater inflater;
+ protected byte[] buf;
+
+ private boolean closed = false;
+
+ private boolean eof = false;
+
+ private boolean close_in = true;
+
+ protected static final int DEFAULT_BUFSIZE = 512;
+
+ public InflaterInputStream(InputStream in) throws IOException {
+ this(in, false);
+ }
+
+ public InflaterInputStream(InputStream in, boolean nowrap) throws IOException {
+ this(in, new Inflater(nowrap));
+ myinflater = true;
+ }
+
+ public InflaterInputStream(InputStream in, Inflater inflater) throws IOException {
+ this(in, inflater, DEFAULT_BUFSIZE);
+ }
+
+ public InflaterInputStream(InputStream in,
+ Inflater inflater, int size) throws IOException {
+ this(in, inflater, size, true);
+ }
+
+ public InflaterInputStream(InputStream in,
+ Inflater inflater,
+ int size, boolean close_in) throws IOException {
+ super(in);
+ if (in == null || inflater == null) {
+ throw new NullPointerException();
+ }
+ else if (size <= 0) {
+ throw new IllegalArgumentException("buffer size must be greater than 0");
+ }
+ this.inflater = inflater;
+ buf = new byte[size];
+ this.close_in = close_in;
+ }
+
+ protected boolean myinflater = false;
+
+ private byte[] byte1 = new byte[1];
+
+ public int read() throws IOException {
+ if (closed) { throw new IOException("Stream closed"); }
+ return read(byte1, 0, 1) == -1 ? -1 : byte1[0] & 0xff;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (closed) { throw new IOException("Stream closed"); }
+ if (b == null) {
+ throw new NullPointerException();
+ }
+ else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ }
+ else if (len == 0) {
+ return 0;
+ }
+ else if (eof) {
+ return -1;
+ }
+
+ int n = 0;
+ inflater.setOutput(b, off, len);
+ while(!eof) {
+ if(inflater.avail_in==0)
+ fill();
+ int err = inflater.inflate(JZlib.Z_NO_FLUSH);
+ n += inflater.next_out_index - off;
+ off = inflater.next_out_index;
+ switch(err) {
+ case JZlib.Z_DATA_ERROR:
+ throw new IOException(inflater.msg);
+ case JZlib.Z_STREAM_END:
+ case JZlib.Z_NEED_DICT:
+ eof = true;
+ if(err == JZlib.Z_NEED_DICT)
+ return -1;
+ break;
+ default:
+ }
+ if(inflater.avail_out==0)
+ break;
+ }
+ return n;
+ }
+
+ public int available() throws IOException {
+ if (closed) { throw new IOException("Stream closed"); }
+ if (eof) {
+ return 0;
+ }
+ else {
+ return 1;
+ }
+ }
+
+ private byte[] b = new byte[512];
+
+ public long skip(long n) throws IOException {
+ if (n < 0) {
+ throw new IllegalArgumentException("negative skip length");
+ }
+
+ if (closed) { throw new IOException("Stream closed"); }
+
+ int max = (int)Math.min(n, Integer.MAX_VALUE);
+ int total = 0;
+ while (total < max) {
+ int len = max - total;
+ if (len > b.length) {
+ len = b.length;
+ }
+ len = read(b, 0, len);
+ if (len == -1) {
+ eof = true;
+ break;
+ }
+ total += len;
+ }
+ return total;
+ }
+
+ public void close() throws IOException {
+ if (!closed) {
+ if (myinflater)
+ inflater.end();
+ if(close_in)
+ in.close();
+ closed = true;
+ }
+ }
+
+ protected void fill() throws IOException {
+ if (closed) { throw new IOException("Stream closed"); }
+ int len = in.read(buf, 0, buf.length);
+ if (len == -1) {
+ if(inflater.istate.wrap == 0 &&
+ !inflater.finished()){
+ buf[0]=0;
+ len=1;
+ }
+ else if(inflater.istate.was != -1){ // in reading trailer
+ throw new IOException("footer is not found");
+ }
+ else{
+ throw new EOFException("Unexpected end of ZLIB input stream");
+ }
+ }
+ inflater.setInput(buf, 0, len, true);
+ }
+
+ public boolean markSupported() {
+ return false;
+ }
+
+ public synchronized void mark(int readlimit) {
+ }
+
+ public synchronized void reset() throws IOException {
+ throw new IOException("mark/reset not supported");
+ }
+
+ public long getTotalIn() {
+ return inflater.getTotalIn();
+ }
+
+ public long getTotalOut() {
+ return inflater.getTotalOut();
+ }
+
+ public byte[] getAvailIn() {
+ if(inflater.avail_in<=0)
+ return null;
+ byte[] tmp = new byte[inflater.avail_in];
+ System.arraycopy(inflater.next_in, inflater.next_in_index,
+ tmp, 0, inflater.avail_in);
+ return tmp;
+ }
+
+ public void readHeader() throws IOException {
+
+ byte[] empty = "".getBytes();
+ inflater.setInput(empty, 0, 0, false);
+ inflater.setOutput(empty, 0, 0);
+
+ int err = inflater.inflate(JZlib.Z_NO_FLUSH);
+ if(!inflater.istate.inParsingHeader()){
+ return;
+ }
+
+ byte[] b1 = new byte[1];
+ do{
+ int i = in.read(b1);
+ if(i<=0)
+ throw new IOException("no input");
+ inflater.setInput(b1);
+ err = inflater.inflate(JZlib.Z_NO_FLUSH);
+ if(err!=0/*Z_OK*/)
+ throw new IOException(inflater.msg);
+ }
+ while(inflater.istate.inParsingHeader());
+ }
+
+ public Inflater getInflater(){
+ return inflater;
+ }
+} \ No newline at end of file
diff --git a/java/com/jcraft/jzlib/JZlib.java b/java/com/jcraft/jzlib/JZlib.java
index 8fd98ea7..a4bb3410 100644
--- a/java/com/jcraft/jzlib/JZlib.java
+++ b/java/com/jcraft/jzlib/JZlib.java
@@ -41,6 +41,15 @@ final public class JZlib{
static final public int MAX_WBITS=15; // 32K LZ77 window
static final public int DEF_WBITS=MAX_WBITS;
+ public enum WrapperType {
+ NONE, ZLIB, GZIP, ANY
+ }
+
+ public static final WrapperType W_NONE = WrapperType.NONE;
+ public static final WrapperType W_ZLIB = WrapperType.ZLIB;
+ public static final WrapperType W_GZIP = WrapperType.GZIP;
+ public static final WrapperType W_ANY = WrapperType.ANY;
+
// compression levels
static final public int Z_NO_COMPRESSION=0;
static final public int Z_BEST_SPEED=1;
diff --git a/java/com/jcraft/jzlib/Tree.java b/java/com/jcraft/jzlib/Tree.java
index 40b6ba87..38cb40f2 100644
--- a/java/com/jcraft/jzlib/Tree.java
+++ b/java/com/jcraft/jzlib/Tree.java
@@ -308,7 +308,7 @@ final class Tree{
gen_bitlen(s);
// The field len is now set, we can generate the bit codes
- gen_codes(tree, max_code, s.bl_count);
+ gen_codes(tree, max_code, s.bl_count, s.next_code);
}
// Generate the codes for a given tree and bit counts (which need not be
@@ -317,11 +317,11 @@ final class Tree{
// the given tree and the field len is set for all tree elements.
// OUT assertion: the field code is set for all tree elements of non
// zero code length.
- static short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length
- synchronized static void gen_codes(short[] tree, // the tree to decorate
- int max_code, // largest code with non zero frequency
- short[] bl_count // number of codes at each bit length
- ){
+ private final static void gen_codes(
+ short[] tree, // the tree to decorate
+ int max_code, // largest code with non zero frequency
+ short[] bl_count, // number of codes at each bit length
+ short[] next_code){
short code = 0; // running code value
int bits; // bit index
int n; // code index
@@ -350,7 +350,8 @@ final class Tree{
// Reverse the first len bits of a code, using straightforward code (a faster
// method would use a table)
// IN assertion: 1 <= len <= 15
- static int bi_reverse(int code, // the value to invert
+ private final static int bi_reverse(
+ int code, // the value to invert
int len // its bit length
){
int res = 0;
diff --git a/java/com/jcraft/jzlib/ZInputStream.java b/java/com/jcraft/jzlib/ZInputStream.java
index 0054645e..cbd38e15 100644
--- a/java/com/jcraft/jzlib/ZInputStream.java
+++ b/java/com/jcraft/jzlib/ZInputStream.java
@@ -50,7 +50,7 @@ public class ZInputStream extends FilterInputStream {
}
public ZInputStream(InputStream in, boolean nowrap) throws IOException {
super(in);
- iis = new InflaterInputStream(in);
+ iis = new InflaterInputStream(in, nowrap);
compress=false;
}
diff --git a/java/com/jcraft/jzlib/ZStream.java b/java/com/jcraft/jzlib/ZStream.java
index dd0a5256..0afa4fd0 100644
--- a/java/com/jcraft/jzlib/ZStream.java
+++ b/java/com/jcraft/jzlib/ZStream.java
@@ -99,7 +99,24 @@ public class ZStream{
public int inflateInit(int w){
return inflateInit(w, false);
}
-
+ public int inflateInit(JZlib.WrapperType wrapperType) {
+ return inflateInit(DEF_WBITS, wrapperType);
+ }
+ public int inflateInit(int w, JZlib.WrapperType wrapperType) {
+ boolean nowrap = false;
+ if(wrapperType == JZlib.W_NONE){
+ nowrap = true;
+ }
+ else if(wrapperType == JZlib.W_GZIP) {
+ w += 16;
+ }
+ else if(wrapperType == JZlib.W_ANY) {
+ w |= Inflate.INFLATE_ANY;
+ }
+ else if(wrapperType == JZlib.W_ZLIB) {
+ }
+ return inflateInit(w, nowrap);
+ }
public int inflateInit(int w, boolean nowrap){
istate=new Inflate(this);
return istate.inflateInit(nowrap?-w:w);
@@ -143,6 +160,23 @@ public class ZStream{
public int deflateInit(int level, int bits){
return deflateInit(level, bits, false);
}
+ public int deflateInit(int level, int bits, int memlevel, JZlib.WrapperType wrapperType){
+ if(bits < 9 || bits > 15){
+ return Z_STREAM_ERROR;
+ }
+ if(wrapperType == JZlib.W_NONE) {
+ bits *= -1;
+ }
+ else if(wrapperType == JZlib.W_GZIP) {
+ bits += 16;
+ }
+ else if(wrapperType == JZlib.W_ANY) {
+ return Z_STREAM_ERROR;
+ }
+ else if(wrapperType == JZlib.W_ZLIB) {
+ }
+ return this.deflateInit(level, bits, memlevel);
+ }
public int deflateInit(int level, int bits, int memlevel){
dstate=new Deflate(this);
return dstate.deflateInit(level, bits, memlevel);
diff --git a/java/com/jcraft/jzlib/ZStreamException.java b/java/com/jcraft/jzlib/ZStreamException.java
index 308bb8a1..424b74b7 100644
--- a/java/com/jcraft/jzlib/ZStreamException.java
+++ b/java/com/jcraft/jzlib/ZStreamException.java
@@ -1,44 +1,44 @@
-/* -*-mode:java; c-basic-offset:2; -*- */
-/*
-Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the distribution.
-
- 3. The names of the authors may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
-INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
-OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*
- * This program is based on zlib-1.1.3, so all credit should go authors
- * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
- * and contributors of zlib.
- */
-
-package com.jcraft.jzlib;
-
-public class ZStreamException extends java.io.IOException {
- public ZStreamException() {
- super();
- }
- public ZStreamException(String s) {
- super(s);
- }
-}
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+public class ZStreamException extends java.io.IOException {
+ public ZStreamException() {
+ super();
+ }
+ public ZStreamException(String s) {
+ super(s);
+ }
+}