Browse Source

Upgrade in-tree jsch and jzlib to latest upstream versions

tags/v1.6.90
Brian P. Hinz 8 years ago
parent
commit
ce48cc8962
100 changed files with 5847 additions and 2075 deletions
  1. 33
    14
      java/CMakeLists.txt
  2. 46
    3
      java/com/jcraft/jsch/Buffer.java
  3. 431
    198
      java/com/jcraft/jsch/ChangeLog
  4. 116
    21
      java/com/jcraft/jsch/Channel.java
  5. 2
    3
      java/com/jcraft/jsch/ChannelAgentForwarding.java
  6. 18
    3
      java/com/jcraft/jsch/ChannelDirectTCPIP.java
  7. 1
    1
      java/com/jcraft/jsch/ChannelExec.java
  8. 88
    73
      java/com/jcraft/jsch/ChannelForwardedTCPIP.java
  9. 9
    10
      java/com/jcraft/jsch/ChannelSession.java
  10. 408
    32
      java/com/jcraft/jsch/ChannelSftp.java
  11. 1
    1
      java/com/jcraft/jsch/ChannelShell.java
  12. 1
    1
      java/com/jcraft/jsch/ChannelSubsystem.java
  13. 1
    2
      java/com/jcraft/jsch/ChannelX11.java
  14. 1
    1
      java/com/jcraft/jsch/Cipher.java
  15. 1
    1
      java/com/jcraft/jsch/CipherNone.java
  16. 1
    1
      java/com/jcraft/jsch/Compression.java
  17. 55
    0
      java/com/jcraft/jsch/ConfigRepository.java
  18. 5
    1
      java/com/jcraft/jsch/DH.java
  19. 37
    0
      java/com/jcraft/jsch/DHEC256.java
  20. 37
    0
      java/com/jcraft/jsch/DHEC384.java
  21. 37
    0
      java/com/jcraft/jsch/DHEC521.java
  22. 187
    0
      java/com/jcraft/jsch/DHECN.java
  23. 7
    122
      java/com/jcraft/jsch/DHG1.java
  24. 7
    103
      java/com/jcraft/jsch/DHG14.java
  25. 31
    127
      java/com/jcraft/jsch/DHGEX.java
  26. 36
    0
      java/com/jcraft/jsch/DHGEX256.java
  27. 37
    0
      java/com/jcraft/jsch/ECDH.java
  28. 1
    1
      java/com/jcraft/jsch/ForwardedTCPIPDaemon.java
  29. 1
    1
      java/com/jcraft/jsch/GSSContext.java
  30. 1
    1
      java/com/jcraft/jsch/HASH.java
  31. 43
    7
      java/com/jcraft/jsch/HostKey.java
  32. 51
    1
      java/com/jcraft/jsch/HostKeyRepository.java
  33. 1
    1
      java/com/jcraft/jsch/IO.java
  34. 43
    1
      java/com/jcraft/jsch/Identity.java
  35. 62
    888
      java/com/jcraft/jsch/IdentityFile.java
  36. 77
    2
      java/com/jcraft/jsch/IdentityRepository.java
  37. 307
    33
      java/com/jcraft/jsch/JSch.java
  38. 1
    1
      java/com/jcraft/jsch/JSchAuthCancelException.java
  39. 1
    1
      java/com/jcraft/jsch/JSchException.java
  40. 1
    1
      java/com/jcraft/jsch/JSchPartialAuthException.java
  41. 182
    17
      java/com/jcraft/jsch/KeyExchange.java
  42. 593
    67
      java/com/jcraft/jsch/KeyPair.java
  43. 123
    12
      java/com/jcraft/jsch/KeyPairDSA.java
  44. 391
    0
      java/com/jcraft/jsch/KeyPairECDSA.java
  45. 1
    1
      java/com/jcraft/jsch/KeyPairGenDSA.java
  46. 37
    0
      java/com/jcraft/jsch/KeyPairGenECDSA.java
  47. 1
    1
      java/com/jcraft/jsch/KeyPairGenRSA.java
  48. 363
    0
      java/com/jcraft/jsch/KeyPairPKCS8.java
  49. 183
    85
      java/com/jcraft/jsch/KeyPairRSA.java
  50. 127
    46
      java/com/jcraft/jsch/KnownHosts.java
  51. 1
    1
      java/com/jcraft/jsch/LICENSE.txt
  52. 63
    3
      java/com/jcraft/jsch/LocalIdentityRepository.java
  53. 1
    1
      java/com/jcraft/jsch/Logger.java
  54. 1
    1
      java/com/jcraft/jsch/MAC.java
  55. 264
    0
      java/com/jcraft/jsch/OpenSSHConfig.java
  56. 34
    0
      java/com/jcraft/jsch/PBKDF.java
  57. 1
    1
      java/com/jcraft/jsch/Packet.java
  58. 18
    4
      java/com/jcraft/jsch/PortWatcher.java
  59. 1
    1
      java/com/jcraft/jsch/Proxy.java
  60. 1
    1
      java/com/jcraft/jsch/ProxyHTTP.java
  61. 1
    1
      java/com/jcraft/jsch/ProxySOCKS4.java
  62. 1
    1
      java/com/jcraft/jsch/ProxySOCKS5.java
  63. 12
    4
      java/com/jcraft/jsch/README
  64. 1
    1
      java/com/jcraft/jsch/Random.java
  65. 1
    1
      java/com/jcraft/jsch/Request.java
  66. 1
    1
      java/com/jcraft/jsch/RequestAgentForwarding.java
  67. 1
    1
      java/com/jcraft/jsch/RequestEnv.java
  68. 1
    1
      java/com/jcraft/jsch/RequestExec.java
  69. 1
    1
      java/com/jcraft/jsch/RequestPtyReq.java
  70. 1
    1
      java/com/jcraft/jsch/RequestSftp.java
  71. 1
    1
      java/com/jcraft/jsch/RequestShell.java
  72. 1
    1
      java/com/jcraft/jsch/RequestSignal.java
  73. 1
    1
      java/com/jcraft/jsch/RequestSubsystem.java
  74. 1
    1
      java/com/jcraft/jsch/RequestWindowChange.java
  75. 1
    1
      java/com/jcraft/jsch/RequestX11.java
  76. 1
    1
      java/com/jcraft/jsch/ServerSocketFactory.java
  77. 847
    75
      java/com/jcraft/jsch/Session.java
  78. 40
    9
      java/com/jcraft/jsch/SftpATTRS.java
  79. 1
    1
      java/com/jcraft/jsch/SftpException.java
  80. 1
    1
      java/com/jcraft/jsch/SftpProgressMonitor.java
  81. 122
    0
      java/com/jcraft/jsch/SftpStatVFS.java
  82. 37
    0
      java/com/jcraft/jsch/Signature.java
  83. 2
    6
      java/com/jcraft/jsch/SignatureDSA.java
  84. 35
    0
      java/com/jcraft/jsch/SignatureECDSA.java
  85. 2
    6
      java/com/jcraft/jsch/SignatureRSA.java
  86. 1
    1
      java/com/jcraft/jsch/SocketFactory.java
  87. 1
    1
      java/com/jcraft/jsch/UIKeyboardInteractive.java
  88. 1
    1
      java/com/jcraft/jsch/UserAuth.java
  89. 1
    1
      java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java
  90. 2
    2
      java/com/jcraft/jsch/UserAuthKeyboardInteractive.java
  91. 1
    1
      java/com/jcraft/jsch/UserAuthNone.java
  92. 1
    1
      java/com/jcraft/jsch/UserAuthPassword.java
  93. 19
    14
      java/com/jcraft/jsch/UserAuthPublicKey.java
  94. 1
    1
      java/com/jcraft/jsch/UserInfo.java
  95. 67
    16
      java/com/jcraft/jsch/Util.java
  96. 7
    5
      java/com/jcraft/jsch/jce/AES128CBC.java
  97. 7
    5
      java/com/jcraft/jsch/jce/AES128CTR.java
  98. 7
    5
      java/com/jcraft/jsch/jce/AES192CBC.java
  99. 7
    5
      java/com/jcraft/jsch/jce/AES192CTR.java
  100. 0
    0
      java/com/jcraft/jsch/jce/AES256CBC.java

+ 33
- 14
java/CMakeLists.txt View File

@@ -36,9 +36,15 @@ set(JAVA_CLASSES "")

set(JSCH_CLASSNAMES
DH
DHEC256
DHEC384
DHEC521
DHECN
DHGEX256
DHG1
DHG14
DHGEX
ECDH
JSch
Session
UserAuth
@@ -47,28 +53,41 @@ set(JSCH_CLASSNAMES
UserAuthPublicKey
UserAuthNone
jce/AES128CBC
jce/AES192CTR
jce/ARCFOUR128
jce/BlowfishCBC
jce/HMACMD5
jce/KeyPairGenDSA
jce/Random
jce/SignatureRSA
jce/AES128CTR
jce/AES256CBC
jce/ARCFOUR256
jce/DH
jce/HMACSHA196
jce/KeyPairGenRSA
jce/SHA1
jce/TripleDESCBC
jce/AES192CBC
jce/AES192CTR
jce/AES256CBC
jce/AES256CTR
jce/ARCFOUR
jce/ARCFOUR128
jce/ARCFOUR256
jce/BlowfishCBC
jce/DH
jce/ECDH256
jce/ECDH384
jce/ECDH521
jce/ECDHN
jce/HMAC
jce/HMACMD5
jce/HMACMD596
jce/HMACSHA1
jce/HMACSHA196
jce/HMACSHA256
jce/HMACSHA512
jce/KeyPairGenDSA
jce/KeyPairGenECDSA
jce/KeyPairGenRSA
jce/MD5
jce/PBKDF
jce/Random
jce/SHA1
jce/SHA256
jce/SHA384
jce/SHA512
jce/SignatureDSA
jce/SignatureECDSA
jce/SignatureRSA
jce/TripleDESCBC
jce/TripleDESCTR
jcraft/Compression
jcraft/HMAC

+ 46
- 3
java/com/jcraft/jsch/Buffer.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -213,13 +213,56 @@ public class Buffer{
}

void checkFreeSize(int n){
if(buffer.length<index+n){
byte[] tmp = new byte[buffer.length*2];
int size = index+n+Session.buffer_margin;
if(buffer.length<size){
int i = buffer.length*2;
if(i<size) i = size;
byte[] tmp = new byte[i];
System.arraycopy(buffer, 0, tmp, 0, index);
buffer = tmp;
}
}

byte[][] getBytes(int n, String msg) throws JSchException {
byte[][] tmp = new byte[n][];
for(int i = 0; i < n; i++){
int j = getInt();
if(getLength() < j){
throw new JSchException(msg);
}
tmp[i] = new byte[j];
getByte(tmp[i]);
}
return tmp;
}

/*
static Buffer fromBytes(byte[]... args){
int length = args.length*4;
for(int i = 0; i < args.length; i++){
length += args[i].length;
}
Buffer buf = new Buffer(length);
for(int i = 0; i < args.length; i++){
buf.putString(args[i]);
}
return buf;
}
*/

static Buffer fromBytes(byte[][] args){
int length = args.length*4;
for(int i = 0; i < args.length; i++){
length += args[i].length;
}
Buffer buf = new Buffer(length);
for(int i = 0; i < args.length; i++){
buf.putString(args[i]);
}
return buf;
}


/*
static String[] chars={
"0","1","2","3","4","5","6","7","8","9", "a","b","c","d","e","f"

+ 431
- 198
java/com/jcraft/jsch/ChangeLog
File diff suppressed because it is too large
View File


+ 116
- 21
java/com/jcraft/jsch/Channel.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -35,7 +35,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

@SuppressWarnings({"rawtypes","unchecked"})
public abstract class Channel implements Runnable{

static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION= 91;
@@ -192,29 +192,38 @@ public abstract class Channel implements Runnable{
io.setExtOutputStream(out, dontclose);
}
public InputStream getInputStream() throws IOException {
PipedInputStream in=
int max_input_buffer_size = 32*1024;
try {
max_input_buffer_size =
Integer.parseInt(getSession().getConfig("max_input_buffer_size"));
}
catch(Exception e){}
PipedInputStream in =
new MyPipedInputStream(
32*1024 // this value should be customizable.
32*1024, // this value should be customizable.
max_input_buffer_size
);
io.setOutputStream(new PassiveOutputStream(in), false);
boolean resizable = 32*1024<max_input_buffer_size;
io.setOutputStream(new PassiveOutputStream(in, resizable), false);
return in;
}
public InputStream getExtInputStream() throws IOException {
PipedInputStream in=
int max_input_buffer_size = 32*1024;
try {
max_input_buffer_size =
Integer.parseInt(getSession().getConfig("max_input_buffer_size"));
}
catch(Exception e){}
PipedInputStream in =
new MyPipedInputStream(
32*1024 // this value should be customizable.
32*1024, // this value should be customizable.
max_input_buffer_size
);
io.setExtOutputStream(new PassiveOutputStream(in), false);
boolean resizable = 32*1024<max_input_buffer_size;
io.setExtOutputStream(new PassiveOutputStream(in, resizable), false);
return in;
}
public OutputStream getOutputStream() throws IOException {
/*
PipedOutputStream out=new PipedOutputStream();
io.setInputStream(new PassiveInputStream(out
, 32*1024
), false);
return out;
*/

final Channel channel=this;
OutputStream out=new OutputStream(){
@@ -317,15 +326,24 @@ public abstract class Channel implements Runnable{
}

class MyPipedInputStream extends PipedInputStream{
private int BUFFER_SIZE = 1024;
private int max_buffer_size = BUFFER_SIZE;
MyPipedInputStream() throws IOException{ super(); }
MyPipedInputStream(int size) throws IOException{
super();
buffer=new byte[size];
BUFFER_SIZE = size;
max_buffer_size = size;
}
MyPipedInputStream(int size, int max_buffer_size) throws IOException{
this(size);
this.max_buffer_size = max_buffer_size;
}
MyPipedInputStream(PipedOutputStream out) throws IOException{ super(out); }
MyPipedInputStream(PipedOutputStream out, int size) throws IOException{
super(out);
buffer=new byte[size];
BUFFER_SIZE=size;
}

/*
@@ -343,12 +361,66 @@ public abstract class Channel implements Runnable{
buffer[in++] = 0;
read();
}

private int freeSpace(){
int size = 0;
if(out < in) {
size = buffer.length-in;
}
else if(in < out){
if(in == -1) size = buffer.length;
else size = out - in;
}
return size;
}
synchronized void checkSpace(int len) throws IOException {
int size = freeSpace();
if(size<len){
int datasize=buffer.length-size;
int foo = buffer.length;
while((foo - datasize) < len){
foo*=2;
}

if(foo > max_buffer_size){
foo = max_buffer_size;
}
if((foo - datasize) < len) return;

byte[] tmp = new byte[foo];
if(out < in) {
System.arraycopy(buffer, 0, tmp, 0, buffer.length);
}
else if(in < out){
if(in == -1) {
}
else {
System.arraycopy(buffer, 0, tmp, 0, in);
System.arraycopy(buffer, out,
tmp, tmp.length-(buffer.length-out),
(buffer.length-out));
out = tmp.length-(buffer.length-out);
}
}
else if(in == out){
System.arraycopy(buffer, 0, tmp, 0, buffer.length);
in=buffer.length;
}
buffer=tmp;
}
else if(buffer.length == size && size > BUFFER_SIZE) {
int i = size/2;
if(i<BUFFER_SIZE) i = BUFFER_SIZE;
byte[] tmp = new byte[i];
buffer=tmp;
}
}
}
void setLocalWindowSizeMax(int foo){ this.lwsize_max=foo; }
void setLocalWindowSize(int foo){ this.lwsize=foo; }
void setLocalPacketSize(int foo){ this.lmpsize=foo; }
synchronized void setRemoteWindowSize(long foo){ this.rwsize=foo; }
synchronized void addRemoteWindowSize(int foo){
synchronized void addRemoteWindowSize(long foo){
this.rwsize+=foo;
if(notifyme>0)
notifyAll();
@@ -384,12 +456,15 @@ public abstract class Channel implements Runnable{
if(eof_local)return;
eof_local=true;

int i = getRecipient();
if(i == -1) return;

try{
Buffer buf=new Buffer(100);
Packet packet=new Packet(buf);
packet.reset();
buf.putByte((byte)Session.SSH_MSG_CHANNEL_EOF);
buf.putInt(getRecipient());
buf.putInt(i);
synchronized(this){
if(!close)
getSession().write(packet);
@@ -445,12 +520,15 @@ public abstract class Channel implements Runnable{
close=true;
eof_local=eof_remote=true;

int i = getRecipient();
if(i == -1) return;

try{
Buffer buf=new Buffer(100);
Packet packet=new Packet(buf);
packet.reset();
buf.putByte((byte)Session.SSH_MSG_CHANNEL_CLOSE);
buf.putInt(getRecipient());
buf.putInt(i);
synchronized(this){
getSession().write(packet);
}
@@ -561,8 +639,25 @@ public abstract class Channel implements Runnable{
}
}
class PassiveOutputStream extends PipedOutputStream{
PassiveOutputStream(PipedInputStream in) throws IOException{
private MyPipedInputStream _sink=null;
PassiveOutputStream(PipedInputStream in,
boolean resizable_buffer) throws IOException{
super(in);
if(resizable_buffer && (in instanceof MyPipedInputStream)) {
this._sink=(MyPipedInputStream)in;
}
}
public void write(int b) throws IOException {
if(_sink != null) {
_sink.checkSpace(1);
}
super.write(b);
}
public void write(byte[] b, int off, int len) throws IOException {
if(_sink != null) {
_sink.checkSpace(len);
}
super.write(b, off, len);
}
}

@@ -636,7 +731,7 @@ public abstract class Channel implements Runnable{
Packet packet = genChannelOpenPacket();
_session.write(packet);

int retry=10;
int retry=2000;
long start=System.currentTimeMillis();
long timeout=connectTimeout;
if(timeout!=0L) retry = 1;
@@ -651,7 +746,7 @@ public abstract class Channel implements Runnable{
}
}
try{
long t = timeout==0L ? 5000L : timeout;
long t = timeout==0L ? 10L : timeout;
this.notifyme=1;
wait(t);
}

+ 2
- 3
java/com/jcraft/jsch/ChannelAgentForwarding.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -32,7 +32,6 @@ package com.jcraft.jsch;
import java.net.*;
import java.util.Vector;

@SuppressWarnings({"rawtypes"})
class ChannelAgentForwarding extends Channel{

static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
@@ -122,7 +121,7 @@ class ChannelAgentForwarding extends Channel{
throw new java.io.IOException(e.toString());
}

IdentityRepository irepo = _session.jsch.getIdentityRepository();
IdentityRepository irepo = _session.getIdentityRepository();
UserInfo userinfo=_session.getUserInfo();

mbuf.reset();

+ 18
- 3
java/com/jcraft/jsch/ChannelDirectTCPIP.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -54,7 +54,8 @@ public class ChannelDirectTCPIP extends Channel{
io=new IO();
}

public void connect() throws JSchException{
public void connect(int connectTimeout) throws JSchException{
this.connectTimeout=connectTimeout;
try{
Session _session=getSession();
if(!_session.isConnected()){
@@ -69,6 +70,9 @@ public class ChannelDirectTCPIP extends Channel{
}
thread.start();
}
else {
sendChannelOpen();
}
}
catch(Exception e){
io.close();
@@ -116,7 +120,16 @@ public class ChannelDirectTCPIP extends Channel{
}
}
catch(Exception e){
// Whenever an exception is thrown by sendChannelOpen(),
// 'connected' is false.
if(!connected){
connected=true;
}
disconnect();
return;
}

eof();
disconnect();
}

@@ -133,7 +146,9 @@ public class ChannelDirectTCPIP extends Channel{
public void setOrgPort(int foo){this.originator_port=foo;}

protected Packet genChannelOpenPacket(){
Buffer buf = new Buffer(150);
Buffer buf = new Buffer(50 + // 6 + 4*8 + 12
host.length() + originator_IP_address.length() +
Session.buffer_margin);
Packet packet = new Packet(buf);
// byte SSH_MSG_CHANNEL_OPEN(90)
// string channel type //

+ 1
- 1
java/com/jcraft/jsch/ChannelExec.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 88
- 73
java/com/jcraft/jsch/ChannelForwardedTCPIP.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,11 +31,11 @@ package com.jcraft.jsch;

import java.net.*;
import java.io.*;
import java.util.Vector;

@SuppressWarnings({"rawtypes","unchecked"})
public class ChannelForwardedTCPIP extends Channel{

static java.util.Vector pool=new java.util.Vector();
private static Vector pool = new Vector();

static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
//static private final int LOCAL_WINDOW_SIZE_MAX=0x100000;
@@ -43,12 +43,9 @@ public class ChannelForwardedTCPIP extends Channel{

static private final int TIMEOUT=10*1000;

SocketFactory factory=null;
private Socket socket=null;
private ForwardedTCPIPDaemon daemon=null;
String target;
int lport;
int rport;
private Config config = null;

ChannelForwardedTCPIP(){
super();
@@ -61,8 +58,9 @@ public class ChannelForwardedTCPIP extends Channel{

public void run(){
try{
if(lport==-1){
Class c=Class.forName(target);
if(config instanceof ConfigDaemon){
ConfigDaemon _config = (ConfigDaemon)config;
Class c=Class.forName(_config.target);
daemon=(ForwardedTCPIPDaemon)c.newInstance();

PipedOutputStream out=new PipedOutputStream();
@@ -71,15 +69,14 @@ public class ChannelForwardedTCPIP extends Channel{
), false);

daemon.setChannel(this, getInputStream(), out);
Object[] foo=getPort(getSession(), rport);
daemon.setArg((Object[])foo[3]);

daemon.setArg(_config.arg);
new Thread(daemon).start();
}
else{
socket=(factory==null) ?
Util.createSocket(target, lport, TIMEOUT) :
factory.createSocket(target, lport);
ConfigLHost _config = (ConfigLHost)config;
socket=(_config.factory==null) ?
Util.createSocket(_config.target, _config.lport, TIMEOUT) :
_config.factory.createSocket(_config.target, _config.lport);
socket.setTcpNoDelay(true);
io.setInputStream(socket.getInputStream());
io.setOutputStream(socket.getOutputStream());
@@ -155,32 +152,29 @@ public class ChannelForwardedTCPIP extends Channel{
// session has been already down.
}

synchronized(pool){
for(int i=0; i<pool.size(); i++){
Object[] foo=(Object[])(pool.elementAt(i));
if(foo[0]!=_session) continue;
if(((Integer)foo[1]).intValue()!=port) continue;
this.rport=port;
this.target=(String)foo[2];
if(foo[3]==null || (foo[3] instanceof Object[])){ this.lport=-1; }
else{ this.lport=((Integer)foo[3]).intValue(); }
if(foo.length>=6){
this.factory=((SocketFactory)foo[5]);
}
break;
}
if(target==null){
//System.err.println("??");
this.config = getPort(_session, Util.byte2str(addr), port);
if(this.config == null)
this.config = getPort(_session, null, port);

if(this.config == null){
if(JSch.getLogger().isEnabled(Logger.ERROR)){
JSch.getLogger().log(Logger.ERROR,
"ChannelForwardedTCPIP: "+Util.byte2str(addr)+":"+port+" is not registered.");
}
}
}

static Object[] getPort(Session session, int rport){
private static Config getPort(Session session, String address_to_bind, int rport){
synchronized(pool){
for(int i=0; i<pool.size(); i++){
Object[] bar=(Object[])(pool.elementAt(i));
if(bar[0]!=session) continue;
if(((Integer)bar[1]).intValue()!=rport) continue;
Config bar = (Config)(pool.elementAt(i));
if(bar.session != session) continue;
if(bar.rport != rport) {
if(bar.rport != 0 || bar.allocated_rport != rport)
continue;
}
if(address_to_bind != null &&
!bar.address_to_bind.equals(address_to_bind)) continue;
return bar;
}
return null;
@@ -188,13 +182,14 @@ public class ChannelForwardedTCPIP extends Channel{
}

static String[] getPortForwarding(Session session){
java.util.Vector foo=new java.util.Vector();
Vector foo = new Vector();
synchronized(pool){
for(int i=0; i<pool.size(); i++){
Object[] bar=(Object[])(pool.elementAt(i));
if(bar[0]!=session) continue;
if(bar[3]==null){ foo.addElement(bar[1]+":"+bar[2]+":"); }
else{ foo.addElement(bar[1]+":"+bar[2]+":"+bar[3]); }
Config config = (Config)(pool.elementAt(i));
if(config instanceof ConfigDaemon)
foo.addElement(config.allocated_rport+":"+config.target+":");
else
foo.addElement(config.allocated_rport+":"+config.target+":"+((ConfigLHost)config).lport);
}
}
String[] bar=new String[foo.size()];
@@ -210,31 +205,39 @@ public class ChannelForwardedTCPIP extends Channel{
else{ return address; }
}

static void addPort(Session session, String _address_to_bind, int port, String target, int lport, SocketFactory factory) throws JSchException{
static void addPort(Session session, String _address_to_bind,
int port, int allocated_port, String target, int lport, SocketFactory factory) throws JSchException{
String address_to_bind=normalize(_address_to_bind);
synchronized(pool){
if(getPort(session, port)!=null){
if(getPort(session, address_to_bind, port)!=null){
throw new JSchException("PortForwardingR: remote port "+port+" is already registered.");
}
Object[] foo=new Object[6];
foo[0]=session; foo[1]=new Integer(port);
foo[2]=target; foo[3]=new Integer(lport);
foo[4]=address_to_bind;
foo[5]=factory;
pool.addElement(foo);
ConfigLHost config = new ConfigLHost();
config.session = session;
config.rport = port;
config.allocated_rport = allocated_port;
config.target = target;
config.lport =lport;
config.address_to_bind = address_to_bind;
config.factory = factory;
pool.addElement(config);
}
}
static void addPort(Session session, String _address_to_bind, int port, String daemon, Object[] arg) throws JSchException{
static void addPort(Session session, String _address_to_bind,
int port, int allocated_port, String daemon, Object[] arg) throws JSchException{
String address_to_bind=normalize(_address_to_bind);
synchronized(pool){
if(getPort(session, port)!=null){
if(getPort(session, address_to_bind, port)!=null){
throw new JSchException("PortForwardingR: remote port "+port+" is already registered.");
}
Object[] foo=new Object[5];
foo[0]=session; foo[1]=new Integer(port);
foo[2]=daemon; foo[3]=arg;
foo[4]=address_to_bind;
pool.addElement(foo);
ConfigDaemon config = new ConfigDaemon();
config.session = session;
config.rport = port;
config.allocated_rport = port;
config.target = daemon;
config.arg = arg;
config.address_to_bind = address_to_bind;
pool.addElement(config);
}
}
static void delPort(ChannelForwardedTCPIP c){
@@ -245,26 +248,21 @@ public class ChannelForwardedTCPIP extends Channel{
catch(JSchException e){
// session has been already down.
}
if(_session!=null)
delPort(_session, c.rport);
if(_session!=null && c.config!=null)
delPort(_session, c.config.rport);
}
static void delPort(Session session, int rport){
delPort(session, null, rport);
}
static void delPort(Session session, String address_to_bind, int rport){
synchronized(pool){
Object[] foo=null;
for(int i=0; i<pool.size(); i++){
Object[] bar=(Object[])(pool.elementAt(i));
if(bar[0]!=session) continue;
if(((Integer)bar[1]).intValue()!=rport) continue;
foo=bar;
break;
}
if(foo==null)return;
Config foo = getPort(session, normalize(address_to_bind), rport);
if(foo == null)
foo = getPort(session, null, rport);
if(foo==null) return;
pool.removeElement(foo);
if(address_to_bind==null){
address_to_bind=(String)foo[4];
address_to_bind=foo.address_to_bind;
}
if(address_to_bind==null){
address_to_bind="0.0.0.0";
@@ -298,9 +296,9 @@ public class ChannelForwardedTCPIP extends Channel{
synchronized(pool){
rport=new int[pool.size()];
for(int i=0; i<pool.size(); i++){
Object[] bar=(Object[])(pool.elementAt(i));
if(bar[0]==session) {
rport[count++]=((Integer)bar[1]).intValue();
Config config = (Config)(pool.elementAt(i));
if(config.session == session) {
rport[count++]=config.rport; // ((Integer)bar[1]).intValue();
}
}
}
@@ -309,8 +307,25 @@ public class ChannelForwardedTCPIP extends Channel{
}
}

public int getRemotePort(){return rport;}
void setSocketFactory(SocketFactory factory){
this.factory=factory;
public int getRemotePort(){return (config!=null ? config.rport: 0);}
private void setSocketFactory(SocketFactory factory){
if(config!=null && (config instanceof ConfigLHost) )
((ConfigLHost)config).factory = factory;
}
static abstract class Config {
Session session;
int rport;
int allocated_rport;
String address_to_bind;
String target;
}

static class ConfigDaemon extends Config {
Object[] arg;
}

static class ConfigLHost extends Config {
int lport;
SocketFactory factory;
}
}

+ 9
- 10
java/com/jcraft/jsch/ChannelSession.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,7 +31,6 @@ package com.jcraft.jsch;

import java.util.*;

@SuppressWarnings({"rawtypes","unchecked"})
class ChannelSession extends Channel{
private static byte[] _session=Util.str2byte("session");

@@ -65,9 +64,9 @@ class ChannelSession extends Channel{

/**
* Enable the X11 forwarding.
* Refer to RFC4254 6.3.1. Requesting X11 Forwarding.
*
* @param enable
* @see RFC4254 6.3.1. Requesting X11 Forwarding
*/
public void setXForwarding(boolean enable){
xforwading=enable;
@@ -87,12 +86,12 @@ class ChannelSession extends Channel{
/**
* Set the environment variable.
* If <code>name</code> and <code>value</code> are needed to be passed
* to the remote in your faivorite encoding,use
* {@link #setEnv(byte[], byte[])}.
* to the remote in your favorite encoding,
* use {@link #setEnv(byte[], byte[])}.
* Refer to RFC4254 6.4 Environment Variable Passing.
*
* @param name A name for environment variable.
* @param value A value for environment variable.
* @see RFC4254 6.4 Environment Variable Passing
*/
public void setEnv(String name, String value){
setEnv(Util.str2byte(name), Util.str2byte(value));
@@ -100,11 +99,11 @@ class ChannelSession extends Channel{

/**
* Set the environment variable.
* Refer to RFC4254 6.4 Environment Variable Passing.
*
* @param name A name of environment variable.
* @param value A value of environment variable.
* @see #setEnv(String, String)
* @see RFC4254 6.4 Environment Variable Passing
*/
public void setEnv(byte[] name, byte[] value){
synchronized(this){
@@ -120,9 +119,9 @@ class ChannelSession extends Channel{

/**
* Allocate a Pseudo-Terminal.
* Refer to RFC4254 6.2. Requesting a Pseudo-Terminal.
*
* @param enable
* @see RFC4254 6.2. Requesting a Pseudo-Terminal
*/
public void setPty(boolean enable){
pty=enable;
@@ -139,12 +138,12 @@ class ChannelSession extends Channel{

/**
* Change the window dimension interactively.
*
* Refer to RFC4254 6.7. Window Dimension Change Message.
*
* @param col terminal width, columns
* @param row terminal height, rows
* @param wp terminal width, pixels
* @param hp terminal height, pixels
* @see RFC4254 6.7. Window Dimension Change Message
*/
public void setPtySize(int col, int row, int wp, int hp){
setPtyType(this.ttype, col, row, wp, hp);

+ 408
- 32
java/com/jcraft/jsch/ChannelSftp.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -33,7 +33,6 @@ import java.io.*;

import java.util.Vector;

@SuppressWarnings({"rawtypes","unchecked"})
public class ChannelSftp extends ChannelSession{

static private final int LOCAL_MAXIMUM_PACKET_SIZE=32*1024;
@@ -150,6 +149,11 @@ public class ChannelSftp extends ChannelSession{
private java.util.Hashtable extensions=null;
private InputStream io_in=null;

private boolean extension_posix_rename = false;
private boolean extension_statvfs = false;
// private boolean extension_fstatvfs = false;
private boolean extension_hardlink = false;

/*
10. Changes from previous protocol versions
The SSH File Transfer Protocol has changed over time, before it's
@@ -178,7 +182,15 @@ public class ChannelSftp extends ChannelSession{
private String fEncoding=UTF8;
private boolean fEncoding_is_utf8=true;

private RequestQueue rq = new RequestQueue(10);
private RequestQueue rq = new RequestQueue(16);

/**
* Specify how many requests may be sent at any one time.
* Increasing this value may slightly improve file transfer speed but will
* increase memory usage. The default is 16 requests.
*
* @param bulk_requests how many requests may be outstanding at any one time.
*/
public void setBulkRequests(int bulk_requests) throws JSchException {
if(bulk_requests>0)
rq = new RequestQueue(bulk_requests);
@@ -186,11 +198,18 @@ public class ChannelSftp extends ChannelSession{
throw new JSchException("setBulkRequests: "+
bulk_requests+" must be greater than 0.");
}

/**
* This method will return the value how many requests may be
* sent at any one time.
*
* @return how many requests may be sent at any one time.
*/
public int getBulkRequests(){
return rq.size();
}

ChannelSftp(){
public ChannelSftp(){
super();
setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX);
setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX);
@@ -249,8 +268,8 @@ public class ChannelSftp extends ChannelSession{
type=header.type; // 2 -> SSH_FXP_VERSION
server_version=header.rid;
//System.err.println("SFTP protocol server-version="+server_version);
extensions=new java.util.Hashtable();
if(length>0){
extensions=new java.util.Hashtable();
// extension data
fill(buf, length);
byte[] extension_name=null;
@@ -265,6 +284,28 @@ public class ChannelSftp extends ChannelSession{
}
}

if(extensions.get("posix-rename@openssh.com")!=null &&
extensions.get("posix-rename@openssh.com").equals("1")){
extension_posix_rename = true;
}

if(extensions.get("statvfs@openssh.com")!=null &&
extensions.get("statvfs@openssh.com").equals("2")){
extension_statvfs = true;
}

/*
if(extensions.get("fstatvfs@openssh.com")!=null &&
extensions.get("fstatvfs@openssh.com").equals("2")){
extension_fstatvfs = true;
}
*/

if(extensions.get("hardlink@openssh.com")!=null &&
extensions.get("hardlink@openssh.com").equals("1")){
extension_hardlink = true;
}

lcwd=new File(".").getCanonicalPath();
}
catch(Exception e){
@@ -330,6 +371,17 @@ public class ChannelSftp extends ChannelSession{
SftpProgressMonitor monitor) throws SftpException{
put(src, dst, monitor, OVERWRITE);
}

/**
* Sends data from <code>src</code> file to <code>dst</code> file.
* The <code>mode</code> should be <code>OVERWRITE</code>,
* <code>RESUME</code> or <code>APPEND</code>.
*
* @param src source file
* @param dst destination file
* @param monitor progress monitor
* @param mode how data should be added to dst
*/
public void put(String src, String dst,
SftpProgressMonitor monitor, int mode) throws SftpException{

@@ -446,6 +498,17 @@ public class ChannelSftp extends ChannelSession{
SftpProgressMonitor monitor) throws SftpException{
put(src, dst, monitor, OVERWRITE);
}

/**
* Sends data from the input stream <code>src</code> to <code>dst</code> file.
* The <code>mode</code> should be <code>OVERWRITE</code>,
* <code>RESUME</code> or <code>APPEND</code>.
*
* @param src input stream
* @param dst destination file
* @param monitor progress monitor
* @param mode how data should be added to dst
*/
public void put(InputStream src, String dst,
SftpProgressMonitor monitor, int mode) throws SftpException{
try{
@@ -468,10 +531,6 @@ public class ChannelSftp extends ChannelSession{
dst=(String)(v.elementAt(0));
}

if(isRemoteDir(dst)){
throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
}

if(monitor!=null){
monitor.init(SftpProgressMonitor.PUT,
"-", dst,
@@ -481,7 +540,13 @@ public class ChannelSftp extends ChannelSession{
_put(src, dst, monitor, mode);
}
catch(Exception e){
if(e instanceof SftpException) throw (SftpException)e;
if(e instanceof SftpException) {
if(((SftpException)e).id == SSH_FX_FAILURE &&
isRemoteDir(dst)) {
throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
}
throw (SftpException)e;
}
if(e instanceof Throwable)
throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e);
throw new SftpException(SSH_FX_FAILURE, e.toString());
@@ -583,7 +648,6 @@ public class ChannelSftp extends ChannelSession{
if((seq-1)==startid ||
((seq-startid)-ackcount)>=bulk_requests){
while(((seq-startid)-ackcount)>=bulk_requests){
if(this.rwsize>=foo) break;
if(checkStatus(ackid, header)){
int _ackid = ackid[0];
if(startid>_ackid || _ackid>seq-1){
@@ -635,6 +699,18 @@ public class ChannelSftp extends ChannelSession{
public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode) throws SftpException{
return put(dst, monitor, mode, 0);
}

/**
* Sends data from the output stream to <code>dst</code> file.
* The <code>mode</code> should be <code>OVERWRITE</code>,
* <code>RESUME</code> or <code>APPEND</code>.
*
* @param dst destination file
* @param monitor progress monitor
* @param mode how data should be added to dst
* @param offset data will be added at offset
* @return output stream, which accepts data to be transferred.
*/
public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset) throws SftpException{
try{
((MyPipedInputStream)io_in).updateReadSide();
@@ -987,7 +1063,16 @@ public class ChannelSftp extends ChannelSession{
length=header.length;
type=header.type;

RequestQueue.Request rr = rq.get(header.rid);
RequestQueue.Request rr = null;
try{
rr = rq.get(header.rid);
}
catch(RequestQueue.OutOfOrderException e){
request_offset = e.offset;
skip(header.length);
rq.cancel(header, buf);
continue;
}

if(type==SSH_FXP_STATUS){
fill(buf, length);
@@ -1079,6 +1164,12 @@ public class ChannelSftp extends ChannelSession{


private class RequestQueue {
class OutOfOrderException extends Exception {
long offset;
OutOfOrderException(long offset){
this.offset=offset;
}
}
class Request {
int id;
long offset;
@@ -1109,15 +1200,27 @@ public class ChannelSftp extends ChannelSession{
count++;
}

Request get(int id){
Request get(int id) throws OutOfOrderException, SftpException {
count -= 1;
int i=head;
int i = head;
head++;
if(head==rrq.length) head=0;
if(rrq[i].id!=id){
System.err.println("The request is not in order.");
if(rrq[i].id != id){
long offset = getOffset();
boolean find = false;
for(int j = 0; j<rrq.length; j++){
if(rrq[j].id == id){
find = true;
rrq[j].id = 0;
break;
}
}
if(find)
throw new OutOfOrderException(offset);
throw new SftpException(SSH_FX_FAILURE,
"RequestQueue: unknown request id "+id);
}
rrq[i].id=0;
rrq[i].id = 0;
return rrq[i];
}

@@ -1134,10 +1237,29 @@ public class ChannelSftp extends ChannelSession{
for(int i=0; i<_count; i++){
header=header(buf, header);
int length=header.length;
get(header.rid);
for(int j=0; j<rrq.length; j++){
if(rrq[j].id == header.rid){
rrq[j].id=0;
break;
}
}
skip(length);
}
init();
}

long getOffset(){
long result = Long.MAX_VALUE;

for(int i=0; i<rrq.length; i++){
if(rrq[i].id == 0)
continue;
if(result>rrq[i].offset)
result=rrq[i].offset;
}

return result;
}
}

public InputStream get(String src) throws SftpException{
@@ -1193,6 +1315,8 @@ public class ChannelSftp extends ChannelSession{

final byte[] handle=buf.getString(); // handle

rq.init();

java.io.InputStream in=new java.io.InputStream(){
long offset=skip;
boolean closed=false;
@@ -1200,6 +1324,8 @@ public class ChannelSftp extends ChannelSession{
byte[] _data=new byte[1];
byte[] rest_byte=new byte[1024];
Header header=new Header();
int request_max=1;
long request_offset=offset;

public int read() throws java.io.IOException{
if(closed)return -1;
@@ -1248,14 +1374,38 @@ public class ChannelSftp extends ChannelSession{
len=1024;
}

try{sendREAD(handle, offset, len);}
catch(Exception e){ throw new IOException("error"); }
if(rq.count()==0) {
int request_len = buf.buffer.length-13;
if(server_version==0){ request_len=1024; }

while(rq.count() < request_max){
try{
sendREAD(handle, request_offset, request_len, rq);
}
catch(Exception e){ throw new IOException("error"); }
request_offset += request_len;
}
}

header=header(buf, header);
rest_length=header.length;
int type=header.type;
int id=header.rid;

RequestQueue.Request rr = null;
try{
rr = rq.get(header.rid);
}
catch(RequestQueue.OutOfOrderException e){
request_offset = e.offset;
skip(header.length);
rq.cancel(header, buf);
return 0;
}
catch(SftpException e){
throw new IOException("error: "+e.toString());
}

if(type!=SSH_FXP_STATUS && type!=SSH_FXP_DATA){
throw new IOException("error");
}
@@ -1270,6 +1420,7 @@ public class ChannelSftp extends ChannelSession{
//throwStatusError(buf, i);
throw new IOException("error");
}

buf.rewind();
fill(buf.buffer, 0, 4);
int length_of_data = buf.getInt(); rest_length-=4;
@@ -1319,6 +1470,21 @@ public class ChannelSftp extends ChannelSession{
io_in.skip(optional_data);
}

if(length_of_data<rr.length){ //
rq.cancel(header, buf);
try {
sendREAD(handle,
rr.offset+length_of_data,
(int)(rr.length-length_of_data), rq);
}
catch(Exception e){ throw new IOException("error"); }
request_offset=rr.offset+rr.length;
}

if(request_max < rq.size()){
request_max++;
}

if(monitor!=null){
if(!monitor.count(i)){
close();
@@ -1334,6 +1500,7 @@ public class ChannelSftp extends ChannelSession{
if(closed)return;
closed=true;
if(monitor!=null)monitor.end();
rq.cancel(header, buf);
try{_sendCLOSE(handle, header);}
catch(Exception e){throw new IOException("error");}
}
@@ -1349,6 +1516,28 @@ public class ChannelSftp extends ChannelSession{
}

public java.util.Vector ls(String path) throws SftpException{
final java.util.Vector v = new Vector();
LsEntrySelector selector = new LsEntrySelector(){
public int select(LsEntry entry){
v.addElement(entry);
return CONTINUE;
}
};
ls(path, selector);
return v;
}

/**
* List files specified by the remote <code>path</code>.
* Each files and directories will be passed to
* <code>LsEntrySelector#select(LsEntry)</code> method, and if that method
* returns <code>LsEntrySelector#BREAK</code>, the operation will be
* canceled immediately.
*
* @see ChannelSftp.LsEntrySelector
* @since 0.1.47
*/
public void ls(String path, LsEntrySelector selector) throws SftpException{
//System.out.println("ls: "+path);
try{
((MyPipedInputStream)io_in).updateReadSide();
@@ -1417,9 +1606,11 @@ public class ChannelSftp extends ChannelSession{
throwStatusError(buf, i);
}

int cancel = LsEntrySelector.CONTINUE;
byte[] handle=buf.getString(); // handle

while(true){
while(cancel==LsEntrySelector.CONTINUE){

sendREADDIR(handle);

header=header(buf, header);
@@ -1461,6 +1652,11 @@ public class ChannelSftp extends ChannelSession{
}
SftpATTRS attrs=SftpATTRS.getATTR(buf);

if(cancel==LsEntrySelector.BREAK){
count--;
continue;
}

boolean find=false;
String f=null;
if(pattern==null){
@@ -1491,7 +1687,8 @@ public class ChannelSftp extends ChannelSession{
else{
l=Util.byte2str(longname, fEncoding);
}
v.addElement(new LsEntry(f, l, attrs));

cancel = selector.select(new LsEntry(f, l, attrs));
}

count--;
@@ -1516,7 +1713,6 @@ public class ChannelSftp extends ChannelSession{
}
*/

return v;
}
catch(Exception e){
if(e instanceof SftpException) throw (SftpException)e;
@@ -1525,6 +1721,7 @@ public class ChannelSftp extends ChannelSession{
throw new SftpException(SSH_FX_FAILURE, "");
}
}

public String readlink(String path) throws SftpException{
try{
if(server_version<3){
@@ -1574,6 +1771,7 @@ public class ChannelSftp extends ChannelSession{
}
return null;
}

public void symlink(String oldpath, String newpath) throws SftpException{
if(server_version<3){
throw new SftpException(SSH_FX_OP_UNSUPPORTED,
@@ -1583,10 +1781,17 @@ public class ChannelSftp extends ChannelSession{
try{
((MyPipedInputStream)io_in).updateReadSide();

oldpath=remoteAbsolutePath(oldpath);
String _oldpath=remoteAbsolutePath(oldpath);
newpath=remoteAbsolutePath(newpath);

oldpath=isUnique(oldpath);
_oldpath=isUnique(_oldpath);
if(oldpath.charAt(0)!='/'){ // relative path
String cwd=getCwd();
oldpath=_oldpath.substring(cwd.length()+(cwd.endsWith("/")?0:1));
}
else {
oldpath=_oldpath;
}

if(isPattern(newpath)){
throw new SftpException(SSH_FX_FAILURE, newpath);
@@ -1619,6 +1824,58 @@ public class ChannelSftp extends ChannelSession{
}
}

public void hardlink(String oldpath, String newpath) throws SftpException{
if(!extension_hardlink){
throw new SftpException(SSH_FX_OP_UNSUPPORTED,
"hardlink@openssh.com is not supported");
}

try{
((MyPipedInputStream)io_in).updateReadSide();

String _oldpath=remoteAbsolutePath(oldpath);
newpath=remoteAbsolutePath(newpath);

_oldpath=isUnique(_oldpath);
if(oldpath.charAt(0)!='/'){ // relative path
String cwd=getCwd();
oldpath=_oldpath.substring(cwd.length()+(cwd.endsWith("/")?0:1));
}
else {
oldpath=_oldpath;
}

if(isPattern(newpath)){
throw new SftpException(SSH_FX_FAILURE, newpath);
}
newpath=Util.unquote(newpath);

sendHARDLINK(Util.str2byte(oldpath, fEncoding),
Util.str2byte(newpath, fEncoding));

Header header=new Header();
header=header(buf, header);
int length=header.length;
int type=header.type;

fill(buf, length);

if(type!=SSH_FXP_STATUS){
throw new SftpException(SSH_FX_FAILURE, "");
}

int i=buf.getInt();
if(i==SSH_FX_OK) return;
throwStatusError(buf, i);
}
catch(Exception e){
if(e instanceof SftpException) throw (SftpException)e;
if(e instanceof Throwable)
throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
throw new SftpException(SSH_FX_FAILURE, "");
}
}

public void rename(String oldpath, String newpath) throws SftpException{
if(server_version<2){
throw new SftpException(SSH_FX_OP_UNSUPPORTED,
@@ -1958,6 +2215,66 @@ public class ChannelSftp extends ChannelSession{
return _stat(Util.str2byte(path, fEncoding));
}

public SftpStatVFS statVFS(String path) throws SftpException{
try{
((MyPipedInputStream)io_in).updateReadSide();

path=remoteAbsolutePath(path);
path=isUnique(path);

return _statVFS(path);
}
catch(Exception e){
if(e instanceof SftpException) throw (SftpException)e;
if(e instanceof Throwable)
throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
throw new SftpException(SSH_FX_FAILURE, "");
}
//return null;
}

private SftpStatVFS _statVFS(byte[] path) throws SftpException{
if(!extension_statvfs){
throw new SftpException(SSH_FX_OP_UNSUPPORTED,
"statvfs@openssh.com is not supported");
}

try{

sendSTATVFS(path);

Header header=new Header();
header=header(buf, header);
int length=header.length;
int type=header.type;

fill(buf, length);

if(type != (SSH_FXP_EXTENDED_REPLY&0xff)){
if(type==SSH_FXP_STATUS){
int i=buf.getInt();
throwStatusError(buf, i);
}
throw new SftpException(SSH_FX_FAILURE, "");
}
else {
SftpStatVFS stat = SftpStatVFS.getStatVFS(buf);
return stat;
}
}
catch(Exception e){
if(e instanceof SftpException) throw (SftpException)e;
if(e instanceof Throwable)
throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
throw new SftpException(SSH_FX_FAILURE, "");
}
//return null;
}

private SftpStatVFS _statVFS(String path) throws SftpException{
return _statVFS(Util.str2byte(path, fEncoding));
}

public SftpATTRS lstat(String path) throws SftpException{
try{
((MyPipedInputStream)io_in).updateReadSide();
@@ -2161,6 +2478,14 @@ public class ChannelSftp extends ChannelSession{
private void sendSTAT(byte[] path) throws Exception{
sendPacketPath(SSH_FXP_STAT, path);
}
private void sendSTATVFS(byte[] path) throws Exception{
sendPacketPath((byte)0, path, "statvfs@openssh.com");
}
/*
private void sendFSTATVFS(byte[] handle) throws Exception{
sendPacketPath((byte)0, handle, "fstatvfs@openssh.com");
}
*/
private void sendLSTAT(byte[] path) throws Exception{
sendPacketPath(SSH_FXP_LSTAT, path);
}
@@ -2193,6 +2518,9 @@ public class ChannelSftp extends ChannelSession{
private void sendSYMLINK(byte[] p1, byte[] p2) throws Exception{
sendPacketPath(SSH_FXP_SYMLINK, p1, p2);
}
private void sendHARDLINK(byte[] p1, byte[] p2) throws Exception{
sendPacketPath((byte)0, p1, p2, "hardlink@openssh.com");
}
private void sendREADLINK(byte[] path) throws Exception{
sendPacketPath(SSH_FXP_READLINK, path);
}
@@ -2203,7 +2531,8 @@ public class ChannelSftp extends ChannelSession{
sendPacketPath(SSH_FXP_READDIR, path);
}
private void sendRENAME(byte[] p1, byte[] p2) throws Exception{
sendPacketPath(SSH_FXP_RENAME, p1, p2);
sendPacketPath(SSH_FXP_RENAME, p1, p2,
extension_posix_rename ? "posix-rename@openssh.com" : null);
}
private void sendCLOSE(byte[] path) throws Exception{
sendPacketPath(SSH_FXP_CLOSE, path);
@@ -2227,19 +2556,44 @@ public class ChannelSftp extends ChannelSession{
getSession().write(packet, this, 17+path.length+4);
}
private void sendPacketPath(byte fxp, byte[] path) throws Exception{
sendPacketPath(fxp, path, (String)null);
}
private void sendPacketPath(byte fxp, byte[] path, String extension) throws Exception{
packet.reset();
putHEAD(fxp, 9+path.length);
buf.putInt(seq++);
int len = 9+path.length;
if(extension == null) {
putHEAD(fxp, len);
buf.putInt(seq++);
}
else {
len+=(4+extension.length());
putHEAD(SSH_FXP_EXTENDED, len);
buf.putInt(seq++);
buf.putString(Util.str2byte(extension));
}
buf.putString(path); // path
getSession().write(packet, this, 9+path.length+4);
getSession().write(packet, this, len+4);
}

private void sendPacketPath(byte fxp, byte[] p1, byte[] p2) throws Exception{
sendPacketPath(fxp, p1, p2, null);
}
private void sendPacketPath(byte fxp, byte[] p1, byte[] p2, String extension) throws Exception{
packet.reset();
putHEAD(fxp, 13+p1.length+p2.length);
buf.putInt(seq++);
int len = 13+p1.length+p2.length;
if(extension==null){
putHEAD(fxp, len);
buf.putInt(seq++);
}
else {
len+=(4+extension.length());
putHEAD(SSH_FXP_EXTENDED, len);
buf.putInt(seq++);
buf.putString(Util.str2byte(extension));
}
buf.putString(p1);
buf.putString(p2);
getSession().write(packet, this, 13+p1.length+p2.length+4);
getSession().write(packet, this, len+4);
}

private int sendWRITE(byte[] handle, long offset,
@@ -2649,4 +3003,26 @@ public class ChannelSftp extends ChannelSession{
throw new ClassCastException("a decendent of LsEntry must be given.");
}
}

/**
* This interface will be passed as an argument for <code>ls</code> method.
*
* @see ChannelSftp.LsEntry
* @see #ls(String, ChannelSftp.LsEntrySelector)
* @since 0.1.47
*/
public interface LsEntrySelector {
public final int CONTINUE = 0;
public final int BREAK = 1;

/**
* <p> The <code>select</code> method will be invoked in <code>ls</code>
* method for each file entry. If this method returns BREAK,
* <code>ls</code> will be canceled.
*
* @param entry one of entry from ls
* @return if BREAK is returned, the 'ls' operation will be canceled.
*/
public int select(LsEntry entry);
}
}

+ 1
- 1
java/com/jcraft/jsch/ChannelShell.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/ChannelSubsystem.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2005-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 2
java/com/jcraft/jsch/ChannelX11.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,7 +31,6 @@ package com.jcraft.jsch;

import java.net.*;

@SuppressWarnings({"rawtypes","unchecked"})
class ChannelX11 extends Channel{

static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;

+ 1
- 1
java/com/jcraft/jsch/Cipher.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/CipherNone.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/Compression.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 55
- 0
java/com/jcraft/jsch/ConfigRepository.java View File

@@ -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; }
};
}

+ 5
- 1
java/com/jcraft/jsch/DH.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -36,4 +36,8 @@ public interface DH{
byte[] getE() throws Exception;
void setF(byte[] f);
byte[] getK() throws Exception;

// checkRange() will check if e and f are in [1,p-1]
// as defined at https://tools.ietf.org/html/rfc4253#section-8
void checkRange() throws Exception;
}

+ 37
- 0
java/com/jcraft/jsch/DHEC256.java View File

@@ -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;
}
}

+ 37
- 0
java/com/jcraft/jsch/DHEC384.java View File

@@ -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;
}
}

+ 37
- 0
java/com/jcraft/jsch/DHEC521.java View File

@@ -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;
}
}

+ 187
- 0
java/com/jcraft/jsch/DHECN.java View File

@@ -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; }
}

+ 7
- 122
java/com/jcraft/jsch/DHG1.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.jcraft.jsch;

@SuppressWarnings({"rawtypes"})
public class DHG1 extends KeyExchange{

static final byte[] g={ 2 };
@@ -56,25 +55,15 @@ public class DHG1 extends KeyExchange{
private static final int SSH_MSG_KEXDH_INIT= 30;
private static final int SSH_MSG_KEXDH_REPLY= 31;

static final int RSA=0;
static final int DSS=1;
private int type=0;

private int state;

DH dh;
// HASH sha;

// byte[] K;
// byte[] H;

byte[] V_S;
byte[] V_C;
byte[] I_S;
byte[] I_C;

// byte[] K_S;

byte[] e;

private Buffer buf;
@@ -88,8 +77,6 @@ public class DHG1 extends KeyExchange{
this.I_S=I_S;
this.I_C=I_C;

// sha=new SHA1();
// sha.init();
try{
Class c=Class.forName(session.getConfig("sha-1"));
sha=(HASH)(c.newInstance());
@@ -156,25 +143,15 @@ public class DHG1 extends KeyExchange{
}

K_S=_buf.getString();
// K_S is server_key_blob, which includes ....
// string ssh-dss
// impint p of dsa
// impint q of dsa
// impint g of dsa
// impint pub_key of dsa
//System.err.print("K_S: "); //dump(K_S, 0, K_S.length);

byte[] f=_buf.getMPInt();
byte[] sig_of_H=_buf.getString();
/*
for(int ii=0; ii<sig_of_H.length;ii++){
System.err.print(Integer.toHexString(sig_of_H[ii]&0xff));
System.err.print(": ");
}
System.err.println("");
*/

dh.setF(f);
K=dh.getK();

dh.checkRange();

K=normalize(dh.getK());

//The hash H is computed as the HASH hash of the concatenation of the
//following:
@@ -207,105 +184,13 @@ System.err.println("");
String alg=Util.byte2str(K_S, i, j);
i+=j;

boolean result=false;

if(alg.equals("ssh-rsa")){
byte[] tmp;
byte[] ee;
byte[] n;

type=RSA;

j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
ee=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
n=tmp;
// SignatureRSA sig=new SignatureRSA();
// sig.init();

SignatureRSA sig=null;
try{
Class c=Class.forName(session.getConfig("signature.rsa"));
sig=(SignatureRSA)(c.newInstance());
sig.init();
}
catch(Exception e){
System.err.println(e);
}

sig.setPubKey(ee, n);
sig.update(H);
result=sig.verify(sig_of_H);

if(JSch.getLogger().isEnabled(Logger.INFO)){
JSch.getLogger().log(Logger.INFO,
"ssh_rsa_verify: signature "+result);
}

}
else if(alg.equals("ssh-dss")){
byte[] q=null;
byte[] tmp;
byte[] p;
byte[] g;
type=DSS;

j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
p=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
q=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
g=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
f=tmp;
// SignatureDSA sig=new SignatureDSA();
// sig.init();
SignatureDSA sig=null;
try{
Class c=Class.forName(session.getConfig("signature.dss"));
sig=(SignatureDSA)(c.newInstance());
sig.init();
}
catch(Exception e){
System.err.println(e);
}
sig.setPubKey(f, p, q, g);
sig.update(H);
result=sig.verify(sig_of_H);

if(JSch.getLogger().isEnabled(Logger.INFO)){
JSch.getLogger().log(Logger.INFO,
"ssh_dss_verify: signature "+result);
}
boolean result = verify(alg, K_S, i, sig_of_H);

}
else{
System.err.println("unknown alg");
}
state=STATE_END;
return result;
}
return false;
}

public String getKeyType(){
if(type==DSS) return "DSA";
return "RSA";
}

public int getState(){return state; }
}

+ 7
- 103
java/com/jcraft/jsch/DHG14.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.jcraft.jsch;

@SuppressWarnings({"rawtypes"})
public class DHG14 extends KeyExchange{

static final byte[] g={ 2 };
@@ -72,10 +71,6 @@ public class DHG14 extends KeyExchange{
private static final int SSH_MSG_KEXDH_INIT= 30;
private static final int SSH_MSG_KEXDH_REPLY= 31;

static final int RSA=0;
static final int DSS=1;
private int type=0;

private int state;

DH dh;
@@ -167,18 +162,15 @@ public class DHG14 extends KeyExchange{
}

K_S=_buf.getString();
// K_S is server_key_blob, which includes ....
// string ssh-dss
// impint p of dsa
// impint q of dsa
// impint g of dsa
// impint pub_key of dsa
//System.err.print("K_S: "); //dump(K_S, 0, K_S.length);

byte[] f=_buf.getMPInt();
byte[] sig_of_H=_buf.getString();

dh.setF(f);
K=dh.getK();

dh.checkRange();

K=normalize(dh.getK());

//The hash H is computed as the HASH hash of the concatenation of the
//following:
@@ -211,101 +203,13 @@ public class DHG14 extends KeyExchange{
String alg=Util.byte2str(K_S, i, j);
i+=j;

boolean result=false;

if(alg.equals("ssh-rsa")){
byte[] tmp;
byte[] ee;
byte[] n;

type=RSA;

j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
ee=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
n=tmp;
SignatureRSA sig=null;
try{
Class c=Class.forName(session.getConfig("signature.rsa"));
sig=(SignatureRSA)(c.newInstance());
sig.init();
}
catch(Exception e){
System.err.println(e);
}

sig.setPubKey(ee, n);
sig.update(H);
result=sig.verify(sig_of_H);

if(JSch.getLogger().isEnabled(Logger.INFO)){
JSch.getLogger().log(Logger.INFO,
"ssh_rsa_verify: signature "+result);
}
boolean result = verify(alg, K_S, i, sig_of_H);

}
else if(alg.equals("ssh-dss")){
byte[] q=null;
byte[] tmp;
byte[] p;
byte[] g;
type=DSS;

j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
p=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
q=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
g=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
f=tmp;

SignatureDSA sig=null;
try{
Class c=Class.forName(session.getConfig("signature.dss"));
sig=(SignatureDSA)(c.newInstance());
sig.init();
}
catch(Exception e){
System.err.println(e);
}
sig.setPubKey(f, p, q, g);
sig.update(H);
result=sig.verify(sig_of_H);

if(JSch.getLogger().isEnabled(Logger.INFO)){
JSch.getLogger().log(Logger.INFO,
"ssh_dss_verify: signature "+result);
}

}
else{
System.err.println("unknown alg");
}
state=STATE_END;
return result;
}
return false;
}

public String getKeyType(){
if(type==DSS) return "DSA";
return "RSA";
}

public int getState(){return state; }
}

+ 31
- 127
java/com/jcraft/jsch/DHGEX.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.jcraft.jsch;

@SuppressWarnings({"rawtypes"})
public class DHGEX extends KeyExchange{

private static final int SSH_MSG_KEX_DH_GEX_GROUP= 31;
@@ -38,21 +37,11 @@ public class DHGEX extends KeyExchange{
private static final int SSH_MSG_KEX_DH_GEX_REQUEST= 34;

static int min=1024;

// static int min=512;
static int preferred=1024;
static int max=1024;

// static int preferred=1024;
// static int max=2000;

static final int RSA=0;
static final int DSS=1;
private int type=0;
int max=1024;

private int state;

// com.jcraft.jsch.DH dh;
DH dh;

byte[] V_S;
@@ -66,7 +55,8 @@ public class DHGEX extends KeyExchange{
private byte[] p;
private byte[] g;
private byte[] e;
//private byte[] f;

protected String hash="sha-1";

public void init(Session session,
byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{
@@ -77,7 +67,7 @@ public class DHGEX extends KeyExchange{
this.I_C=I_C;

try{
Class c=Class.forName(session.getConfig("sha-1"));
Class c=Class.forName(session.getConfig(hash));
sha=(HASH)(c.newInstance());
sha.init();
}
@@ -90,11 +80,13 @@ public class DHGEX extends KeyExchange{

try{
Class c=Class.forName(session.getConfig("dh"));
// Since JDK8, SunJCE has lifted the keysize restrictions
// from 1024 to 2048 for DH.
preferred = max = check2048(c, max);
dh=(com.jcraft.jsch.DH)(c.newInstance());
dh.init();
}
catch(Exception e){
// System.err.println(e);
throw e;
}

@@ -132,18 +124,9 @@ public class DHGEX extends KeyExchange{

p=_buf.getMPInt();
g=_buf.getMPInt();
/*
for(int iii=0; iii<p.length; iii++){
System.err.println("0x"+Integer.toHexString(p[iii]&0xff)+",");
}
System.err.println("");
for(int iii=0; iii<g.length; iii++){
System.err.println("0x"+Integer.toHexString(g[iii]&0xff)+",");
}
*/

dh.setP(p);
dh.setG(g);

// The client responds with:
// byte SSH_MSG_KEX_DH_GEX_INIT(32)
// mpint e <- g^x mod p
@@ -182,19 +165,15 @@ System.err.println("0x"+Integer.toHexString(g[iii]&0xff)+",");
}

K_S=_buf.getString();
// K_S is server_key_blob, which includes ....
// string ssh-dss
// impint p of dsa
// impint q of dsa
// impint g of dsa
// impint pub_key of dsa
//System.err.print("K_S: "); dump(K_S, 0, K_S.length);

byte[] f=_buf.getMPInt();
byte[] sig_of_H=_buf.getString();

dh.setF(f);
K=dh.getK();

dh.checkRange();

K=normalize(dh.getK());

//The hash H is computed as the HASH hash of the concatenation of the
//following:
@@ -237,105 +216,30 @@ System.err.println("0x"+Integer.toHexString(g[iii]&0xff)+",");
String alg=Util.byte2str(K_S, i, j);
i+=j;

boolean result=false;
if(alg.equals("ssh-rsa")){
byte[] tmp;
byte[] ee;
byte[] n;
type=RSA;

j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
ee=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
n=tmp;

// SignatureRSA sig=new SignatureRSA();
// sig.init();

SignatureRSA sig=null;
try{
Class c=Class.forName(session.getConfig("signature.rsa"));
sig=(SignatureRSA)(c.newInstance());
sig.init();
}
catch(Exception e){
System.err.println(e);
}

sig.setPubKey(ee, n);
sig.update(H);
result=sig.verify(sig_of_H);

if(JSch.getLogger().isEnabled(Logger.INFO)){
JSch.getLogger().log(Logger.INFO,
"ssh_rsa_verify: signature "+result);
}

}
else if(alg.equals("ssh-dss")){
byte[] q=null;
byte[] tmp;

type=DSS;

j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
p=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
q=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
g=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
f=tmp;
// SignatureDSA sig=new SignatureDSA();
// sig.init();

SignatureDSA sig=null;
try{
Class c=Class.forName(session.getConfig("signature.dss"));
sig=(SignatureDSA)(c.newInstance());
sig.init();
}
catch(Exception e){
System.err.println(e);
}

sig.setPubKey(f, p, q, g);
sig.update(H);
result=sig.verify(sig_of_H);

if(JSch.getLogger().isEnabled(Logger.INFO)){
JSch.getLogger().log(Logger.INFO,
"ssh_dss_verify: signature "+result);
}
boolean result = verify(alg, K_S, i, sig_of_H);

}
else{
System.err.println("unknown alg");
}
state=STATE_END;
return result;
}
return false;
}

public String getKeyType(){
if(type==DSS) return "DSA";
return "RSA";
}

public int getState(){return state; }

protected int check2048(Class c, int _max) throws Exception {
DH dh=(com.jcraft.jsch.DH)(c.newInstance());
dh.init();
byte[] foo = new byte[257];
foo[1]=(byte)0xdd;
foo[256]=0x73;
dh.setP(foo);
byte[] bar = {(byte)0x02};
dh.setG(bar);
try {
dh.getE();
_max=2048;
}
catch(Exception e){ }
return _max;
}
}

+ 36
- 0
java/com/jcraft/jsch/DHGEX256.java View File

@@ -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";
}
}

+ 37
- 0
java/com/jcraft/jsch/ECDH.java View File

@@ -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;
}

+ 1
- 1
java/com/jcraft/jsch/ForwardedTCPIPDaemon.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/GSSContext.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2004-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2004-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/HASH.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 43
- 7
java/com/jcraft/jsch/HostKey.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,43 +29,77 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.jcraft.jsch;

@SuppressWarnings({"rawtypes","static"})
public class HostKey{
private static final byte[] sshdss=Util.str2byte("ssh-dss");
private static final byte[] sshrsa=Util.str2byte("ssh-rsa");

private static final byte[][] names = {
Util.str2byte("ssh-dss"),
Util.str2byte("ssh-rsa"),
Util.str2byte("ecdsa-sha2-nistp256"),
Util.str2byte("ecdsa-sha2-nistp384"),
Util.str2byte("ecdsa-sha2-nistp521")
};

protected static final int GUESS=0;
public static final int SSHDSS=1;
public static final int SSHRSA=2;
static final int UNKNOWN=3;
public static final int ECDSA256=3;
public static final int ECDSA384=4;
public static final int ECDSA521=5;
static final int UNKNOWN=6;

protected String marker;
protected String host;
protected int type;
protected byte[] key;
protected String comment;

public HostKey(String host, byte[] key) throws JSchException {
this(host, GUESS, key);
}

public HostKey(String host, int type, byte[] key) throws JSchException {
this(host, type, key, null);
}
public HostKey(String host, int type, byte[] key, String comment) throws JSchException {
this("", host, type, key, comment);
}
public HostKey(String marker, String host, int type, byte[] key, String comment) throws JSchException {
this.marker=marker;
this.host=host;
if(type==GUESS){
if(key[8]=='d'){ this.type=SSHDSS; }
else if(key[8]=='r'){ this.type=SSHRSA; }
else if(key[8]=='a' && key[20]=='2'){ this.type=ECDSA256; }
else if(key[8]=='a' && key[20]=='3'){ this.type=ECDSA384; }
else if(key[8]=='a' && key[20]=='5'){ this.type=ECDSA521; }
else { throw new JSchException("invalid key type");}
}
else{
this.type=type;
}
this.key=key;
this.comment=comment;
}

public String getHost(){ return host; }
public String getType(){
if(type==SSHDSS){ return Util.byte2str(sshdss); }
if(type==SSHRSA){ return Util.byte2str(sshrsa);}
if(type==SSHDSS ||
type==SSHRSA ||
type==ECDSA256 ||
type==ECDSA384 ||
type==ECDSA521){
return Util.byte2str(names[type-1]);
}
return "UNKNOWN";
}
protected static int name2type(String name){
for(int i = 0; i < names.length; i++){
if(Util.byte2str(names[i]).equals(name)){
return i + 1;
}
}
return UNKNOWN;
}
public String getKey(){
return Util.byte2str(Util.toBase64(key, 0, key.length));
}
@@ -78,6 +112,8 @@ public class HostKey{
catch(Exception e){ System.err.println("getFingerPrint: "+e); }
return Util.getFingerPrint(hash, key);
}
public String getComment(){ return comment; }
public String getMarker(){ return marker; }

boolean isMatched(String _host){
return isIncluded(_host);

+ 51
- 1
java/com/jcraft/jsch/HostKeyRepository.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2004-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2004-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -34,11 +34,61 @@ public interface HostKeyRepository{
final int NOT_INCLUDED=1;
final int CHANGED=2;

/**
* Checks if <code>host</code> is included with the <code>key</code>.
*
* @return #NOT_INCLUDED, #OK or #CHANGED
* @see #NOT_INCLUDED
* @see #OK
* @see #CHANGED
*/
int check(String host, byte[] key);

/**
* Adds a host key <code>hostkey</code>
*
* @param hostkey a host key to be added
* @param ui a user interface for showing messages or promping inputs.
* @see UserInfo
*/
void add(HostKey hostkey, UserInfo ui);

/**
* Removes a host key if there exists mached key with
* <code>host</code>, <code>type</code>.
*
* @see #remove(String host, String type, byte[] key)
*/
void remove(String host, String type);

/**
* Removes a host key if there exists a matched key with
* <code>host</code>, <code>type</code> and <code>key</code>.
*/
void remove(String host, String type, byte[] key);

/**
* Returns id of this repository.
*
* @return identity in String
*/
String getKnownHostsRepositoryID();

/**
* Retuns a list for host keys managed in this repository.
*
* @see #getHostKey(String host, String type)
*/
HostKey[] getHostKey();

/**
* Retuns a list for host keys managed in this repository.
*
* @param host a hostname used in searching host keys.
* If <code>null</code> is given, every host key will be listed.
* @param type a key type used in searching host keys,
* and it should be "ssh-dss" or "ssh-rsa".
* If <code>null</code> is given, a key type type will not be ignored.
*/
HostKey[] getHostKey(String host, String type);
}

+ 1
- 1
java/com/jcraft/jsch/IO.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 43
- 1
java/com/jcraft/jsch/Identity.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -30,12 +30,54 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.jcraft.jsch;

public interface Identity{

/**
* Decrypts this identity with the specified pass-phrase.
* @param passphrase the pass-phrase for this identity.
* @return <tt>true</tt> if the decryption is succeeded
* or this identity is not cyphered.
*/
public boolean setPassphrase(byte[] passphrase) throws JSchException;

/**
* Returns the public-key blob.
* @return the public-key blob
*/
public byte[] getPublicKeyBlob();

/**
* Signs on data with this identity, and returns the result.
* @param data data to be signed
* @return the signature
*/
public byte[] getSignature(byte[] data);

/**
* @deprecated The decryption should be done automatically in #setPassphase(byte[] passphrase)
* @see #setPassphrase(byte[] passphrase)
*/
public boolean decrypt();

/**
* Returns the name of the key algorithm.
* @return "ssh-rsa" or "ssh-dss"
*/
public String getAlgName();

/**
* Returns the name of this identity.
* It will be useful to identify this object in the {@link IdentityRepository}.
*/
public String getName();

/**
* Returns <tt>true</tt> if this identity is cyphered.
* @return <tt>true</tt> if this identity is cyphered.
*/
public boolean isEncrypted();

/**
* Disposes internally allocated data, like byte array for the private key.
*/
public void clear();
}

+ 62
- 888
java/com/jcraft/jsch/IdentityFile.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,926 +31,100 @@ package com.jcraft.jsch;

import java.io.*;

@SuppressWarnings({"rawtypes","static"})
class IdentityFile implements Identity{
String identity;
byte[] key;
byte[] iv;
private JSch jsch;
private HASH hash;
private byte[] encoded_data;

private Cipher cipher;

// DSA
private byte[] P_array;
private byte[] Q_array;
private byte[] G_array;
private byte[] pub_array;
private byte[] prv_array;
// RSA
private byte[] n_array; // modulus
private byte[] e_array; // public exponent
private byte[] d_array; // private exponent
// private String algname="ssh-dss";
private String algname="ssh-rsa";

private static final int ERROR=0;
private static final int RSA=1;
private static final int DSS=2;
private static final int UNKNOWN=3;

private static final int OPENSSH=0;
private static final int FSECURE=1;
private static final int PUTTY=2;

private int type=ERROR;
private int keytype=OPENSSH;

private byte[] publickeyblob=null;

private boolean encrypted=true;
private KeyPair kpair;
private String identity;

static IdentityFile newInstance(String prvfile, String pubfile, JSch jsch) throws JSchException{
byte[] prvkey=null;
byte[] pubkey=null;

File file=null;
FileInputStream fis=null;
try{
file=new File(prvfile);
fis=new FileInputStream(prvfile);
prvkey=new byte[(int)(file.length())];
int len=0;
while(true){
int i=fis.read(prvkey, len, prvkey.length-len);
if(i<=0)
break;
len+=i;
}
fis.close();
}
catch(Exception e){
try{ if(fis!=null) fis.close();}
catch(Exception ee){}
if(e instanceof Throwable)
throw new JSchException(e.toString(), (Throwable)e);
throw new JSchException(e.toString());
}

String _pubfile=pubfile;
if(pubfile==null){
_pubfile=prvfile+".pub";
}

try{
file=new File(_pubfile);
fis = new FileInputStream(_pubfile);
pubkey=new byte[(int)(file.length())];
int len=0;
while(true){
int i=fis.read(pubkey, len, pubkey.length-len);
if(i<=0)
break;
len+=i;
}
fis.close();
}
catch(Exception e){
try{ if(fis!=null) fis.close();}
catch(Exception ee){}
if(pubfile!=null){
// The pubfile is explicitry given, but not accessible.
if(e instanceof Throwable)
throw new JSchException(e.toString(), (Throwable)e);
throw new JSchException(e.toString());
}
}
return newInstance(prvfile, prvkey, pubkey, jsch);
KeyPair kpair = KeyPair.load(jsch, prvfile, pubfile);
return new IdentityFile(jsch, prvfile, kpair);
}

static IdentityFile newInstance(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{
try{
return new IdentityFile(name, prvkey, pubkey, jsch);
}
finally{
Util.bzero(prvkey);
}
}

private IdentityFile(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{
this.identity=name;
this.jsch=jsch;

// prvkey from "ssh-add" command on the remote.
if(pubkey==null &&
prvkey!=null &&
(prvkey.length>11 &&
prvkey[0]==0 && prvkey[1]==0 && prvkey[2]==0 && prvkey[3]==7)){

Buffer buf=new Buffer(prvkey);
String _type = new String(buf.getString()); // ssh-rsa

if(_type.equals("ssh-rsa")){
type=RSA;
n_array=buf.getString();
e_array=buf.getString();
d_array=buf.getString();
buf.getString();
buf.getString();
buf.getString();
this.identity += new String(buf.getString());
}
else if(_type.equals("ssh-dss")){
type=DSS;
P_array=buf.getString();
Q_array=buf.getString();
G_array=buf.getString();
pub_array=buf.getString();
prv_array=buf.getString();
this.identity += new String(buf.getString());
}
else{
throw new JSchException("privatekey: invalid key "+new String(prvkey, 4, 7));
}
encoded_data=prvkey;
encrypted=false;
keytype=OPENSSH;
return;
}

/* TODO: IdentityFile should use KeyPair.
* The following logic exists also in KeyPair. It is redundant.
*/
try{
Class c;
c=Class.forName((String)jsch.getConfig("3des-cbc"));
cipher=(Cipher)(c.newInstance());
key=new byte[cipher.getBlockSize()]; // 24
iv=new byte[cipher.getIVSize()]; // 8
c=Class.forName((String)jsch.getConfig("md5"));
hash=(HASH)(c.newInstance());
hash.init();

byte[] buf=prvkey;
int len=buf.length;

int i=0;

while(i<len){
if(buf[i] == '-' && i+4<len &&
buf[i+1] == '-' && buf[i+2] == '-' &&
buf[i+3] == '-' && buf[i+4] == '-'){
break;
}
i++;
}

while(i<len){
if(buf[i]=='B'&& i+3<len && buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I'){
i+=6;
if(buf[i]=='D'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=DSS; }
else if(buf[i]=='R'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=RSA; }
else if(buf[i]=='S'&& buf[i+1]=='S'&& buf[i+2]=='H'){ // FSecure
type=UNKNOWN;
keytype=FSECURE;
}
else{
//System.err.println("invalid format: "+identity);
throw new JSchException("invalid privatekey: "+identity);
}
i+=3;
continue;
}
if(buf[i]=='A'&& i+7<len && buf[i+1]=='E'&& buf[i+2]=='S'&& buf[i+3]=='-' &&
buf[i+4]=='2'&& buf[i+5]=='5'&& buf[i+6]=='6'&& buf[i+7]=='-'){
i+=8;
if(Session.checkCipher((String)jsch.getConfig("aes256-cbc"))){
c=Class.forName((String)jsch.getConfig("aes256-cbc"));
cipher=(Cipher)(c.newInstance());
key=new byte[cipher.getBlockSize()];
iv=new byte[cipher.getIVSize()];
}
else{
throw new JSchException("privatekey: aes256-cbc is not available "+identity);
}
continue;
}
if(buf[i]=='A'&& i+7<len && buf[i+1]=='E'&& buf[i+2]=='S'&& buf[i+3]=='-' &&
buf[i+4]=='1'&& buf[i+5]=='9'&& buf[i+6]=='2'&& buf[i+7]=='-'){
i+=8;
if(Session.checkCipher((String)jsch.getConfig("aes192-cbc"))){
c=Class.forName((String)jsch.getConfig("aes192-cbc"));
cipher=(Cipher)(c.newInstance());
key=new byte[cipher.getBlockSize()];
iv=new byte[cipher.getIVSize()];
}
else{
throw new JSchException("privatekey: aes192-cbc is not available "+identity);
}
continue;
}
if(buf[i]=='A'&& i+7<len && buf[i+1]=='E'&& buf[i+2]=='S'&& buf[i+3]=='-' &&
buf[i+4]=='1'&& buf[i+5]=='2'&& buf[i+6]=='8'&& buf[i+7]=='-'){
i+=8;
if(Session.checkCipher((String)jsch.getConfig("aes128-cbc"))){
c=Class.forName((String)jsch.getConfig("aes128-cbc"));
cipher=(Cipher)(c.newInstance());
key=new byte[cipher.getBlockSize()];
iv=new byte[cipher.getIVSize()];
}
else{
throw new JSchException("privatekey: aes128-cbc is not available "+identity);
}
continue;
}
if(buf[i]=='C'&& i+3<len && buf[i+1]=='B'&& buf[i+2]=='C'&& buf[i+3]==','){
i+=4;
for(int ii=0; ii<iv.length; ii++){
iv[ii]=(byte)(((a2b(buf[i++])<<4)&0xf0)+
(a2b(buf[i++])&0xf));
}
continue;
}
if(buf[i]==0x0d && i+1<len && buf[i+1]==0x0a){
i++;
continue;
}
if(buf[i]==0x0a && i+1<len){
if(buf[i+1]==0x0a){ i+=2; break; }
if(buf[i+1]==0x0d &&
i+2<len && buf[i+2]==0x0a){
i+=3; break;
}
boolean inheader=false;
for(int j=i+1; j<len; j++){
if(buf[j]==0x0a) break;
//if(buf[j]==0x0d) break;
if(buf[j]==':'){inheader=true; break;}
}
if(!inheader){
i++;
encrypted=false; // no passphrase
break;
}
}
i++;
}

if(type==ERROR){
throw new JSchException("invalid privatekey: "+identity);
}

int start=i;
while(i<len){
if(buf[i]==0x0a){
boolean xd=(buf[i-1]==0x0d);
System.arraycopy(buf, i+1,
buf,
i-(xd ? 1 : 0),
len-i-1-(xd ? 1 : 0)
);
if(xd)len--;
len--;
continue;
}
if(buf[i]=='-'){ break; }
i++;
}
encoded_data=Util.fromBase64(buf, start, i-start);

if(encoded_data.length>4 && // FSecure
encoded_data[0]==(byte)0x3f &&
encoded_data[1]==(byte)0x6f &&
encoded_data[2]==(byte)0xf9 &&
encoded_data[3]==(byte)0xeb){

Buffer _buf=new Buffer(encoded_data);
_buf.getInt(); // 0x3f6ff9be
_buf.getInt();
byte[]_type=_buf.getString();
//System.err.println("type: "+new String(_type));
byte[] _cipher=_buf.getString();
String cipher=Util.byte2str(_cipher);
//System.err.println("cipher: "+cipher);
if(cipher.equals("3des-cbc")){
_buf.getInt();
byte[] foo=new byte[encoded_data.length-_buf.getOffSet()];
_buf.getByte(foo);
encoded_data=foo;
encrypted=true;
throw new JSchException("unknown privatekey format: "+identity);
}
else if(cipher.equals("none")){
_buf.getInt();
//_buf.getInt();

encrypted=false;

byte[] foo=new byte[encoded_data.length-_buf.getOffSet()];
_buf.getByte(foo);
encoded_data=foo;
}

}

if(pubkey==null){
return;
}
buf=pubkey;
len=buf.length;

if(buf.length>4 && // FSecure's public key
buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){
i=0;
do{i++;}while(len>i && buf[i]!=0x0a);
if(len<=i) return;
while(i<len){
if(buf[i]==0x0a){
boolean inheader=false;
for(int j=i+1; j<len; j++){
if(buf[j]==0x0a) break;
if(buf[j]==':'){inheader=true; break;}
}
if(!inheader){
i++;
break;
}
}
i++;
}
if(len<=i) return;

start=i;
while(i<len){
if(buf[i]==0x0a){
System.arraycopy(buf, i+1, buf, i, len-i-1);
len--;
continue;
}
if(buf[i]=='-'){ break; }
i++;
}
publickeyblob=Util.fromBase64(buf, start, i-start);

if(type==UNKNOWN && publickeyblob.length>8){
if(publickeyblob[8]=='d'){
type=DSS;
}
else if(publickeyblob[8]=='r'){
type=RSA;
}
}
}
else{
if(buf[0]!='s'|| buf[1]!='s'|| buf[2]!='h'|| buf[3]!='-') return;
i=0;
while(i<len){ if(buf[i]==' ')break; i++;} i++;
if(i>=len) return;
start=i;
while(i<len){ if(buf[i]==' ' || buf[i]=='\n')break; i++;}
publickeyblob=Util.fromBase64(buf, start, i-start);
if(publickeyblob.length<4+7){ // It must start with "ssh-XXX".
if(JSch.getLogger().isEnabled(Logger.WARN)){
JSch.getLogger().log(Logger.WARN,
"failed to parse the public key");
}
publickeyblob=null;
}
}
}
catch(Exception e){
//System.err.println("IdentityFile: "+e);
if(e instanceof JSchException) throw (JSchException)e;
if(e instanceof Throwable)
throw new JSchException(e.toString(), (Throwable)e);
throw new JSchException(e.toString());
}
KeyPair kpair = KeyPair.load(jsch, prvkey, pubkey);
return new IdentityFile(jsch, name, kpair);
}

public String getAlgName(){
if(type==RSA) return "ssh-rsa";
return "ssh-dss";
private IdentityFile(JSch jsch, String name, KeyPair kpair) throws JSchException{
this.jsch = jsch;
this.identity = name;
this.kpair = kpair;
}

public boolean setPassphrase(byte[] _passphrase) throws JSchException{
/*
hash is MD5
h(0) <- hash(passphrase, iv);
h(n) <- hash(h(n-1), passphrase, iv);
key <- (h(0),...,h(n))[0,..,key.length];
*/
try{
if(encrypted){
if(_passphrase==null) return false;
byte[] passphrase=_passphrase;
int hsize=hash.getBlockSize();
byte[] hn=new byte[key.length/hsize*hsize+
(key.length%hsize==0?0:hsize)];
byte[] tmp=null;
if(keytype==OPENSSH){
for(int index=0; index+hsize<=hn.length;){
if(tmp!=null){ hash.update(tmp, 0, tmp.length); }
hash.update(passphrase, 0, passphrase.length);
hash.update(iv, 0, iv.length > 8 ? 8: iv.length);
tmp=hash.digest();
System.arraycopy(tmp, 0, hn, index, tmp.length);
index+=tmp.length;
}
System.arraycopy(hn, 0, key, 0, key.length);
}
else if(keytype==FSECURE){
for(int index=0; index+hsize<=hn.length;){
if(tmp!=null){ hash.update(tmp, 0, tmp.length); }
hash.update(passphrase, 0, passphrase.length);
tmp=hash.digest();
System.arraycopy(tmp, 0, hn, index, tmp.length);
index+=tmp.length;
}
System.arraycopy(hn, 0, key, 0, key.length);
}
Util.bzero(passphrase);
}
if(decrypt()){
encrypted=false;
return true;
}
P_array=Q_array=G_array=pub_array=prv_array=null;
return false;
}
catch(Exception e){
if(e instanceof JSchException) throw (JSchException)e;
if(e instanceof Throwable)
throw new JSchException(e.toString(), (Throwable)e);
throw new JSchException(e.toString());
}
/**
* Decrypts this identity with the specified pass-phrase.
* @param passphrase the pass-phrase for this identity.
* @return <tt>true</tt> if the decryption is succeeded
* or this identity is not cyphered.
*/
public boolean setPassphrase(byte[] passphrase) throws JSchException{
return kpair.decrypt(passphrase);
}

/**
* Returns the public-key blob.
* @return the public-key blob
*/
public byte[] getPublicKeyBlob(){
if(publickeyblob!=null) return publickeyblob;
if(type==RSA) return getPublicKeyBlob_rsa();
return getPublicKeyBlob_dss();
}

byte[] getPublicKeyBlob_rsa(){
if(e_array==null) return null;
Buffer buf=new Buffer("ssh-rsa".length()+4+
e_array.length+4+
n_array.length+4);
buf.putString(Util.str2byte("ssh-rsa"));
buf.putString(e_array);
buf.putString(n_array);
return buf.buffer;
}

byte[] getPublicKeyBlob_dss(){
if(P_array==null) return null;
Buffer buf=new Buffer("ssh-dss".length()+4+
P_array.length+4+
Q_array.length+4+
G_array.length+4+
pub_array.length+4);
buf.putString(Util.str2byte("ssh-dss"));
buf.putString(P_array);
buf.putString(Q_array);
buf.putString(G_array);
buf.putString(pub_array);
return buf.buffer;
return kpair.getPublicKeyBlob();
}

/**
* Signs on data with this identity, and returns the result.
* @param data data to be signed
* @return the signature
*/
public byte[] getSignature(byte[] data){
if(type==RSA) return getSignature_rsa(data);
return getSignature_dss(data);
}

byte[] getSignature_rsa(byte[] data){
try{
Class c=Class.forName((String)jsch.getConfig("signature.rsa"));
SignatureRSA rsa=(SignatureRSA)(c.newInstance());

rsa.init();
rsa.setPrvKey(d_array, n_array);

rsa.update(data);
byte[] sig = rsa.sign();
Buffer buf=new Buffer("ssh-rsa".length()+4+
sig.length+4);
buf.putString(Util.str2byte("ssh-rsa"));
buf.putString(sig);
return buf.buffer;
}
catch(Exception e){
}
return null;
}

byte[] getSignature_dss(byte[] data){
/*
byte[] foo;
int i;
System.err.print("P ");
foo=P_array;
for(i=0; i<foo.length; i++){
System.err.print(Integer.toHexString(foo[i]&0xff)+":");
}
System.err.println("");
System.err.print("Q ");
foo=Q_array;
for(i=0; i<foo.length; i++){
System.err.print(Integer.toHexString(foo[i]&0xff)+":");
}
System.err.println("");
System.err.print("G ");
foo=G_array;
for(i=0; i<foo.length; i++){
System.err.print(Integer.toHexString(foo[i]&0xff)+":");
}
System.err.println("");
*/

try{
Class c=Class.forName((String)jsch.getConfig("signature.dss"));
SignatureDSA dsa=(SignatureDSA)(c.newInstance());
dsa.init();
dsa.setPrvKey(prv_array, P_array, Q_array, G_array);

dsa.update(data);
byte[] sig = dsa.sign();
Buffer buf=new Buffer("ssh-dss".length()+4+
sig.length+4);
buf.putString(Util.str2byte("ssh-dss"));
buf.putString(sig);
return buf.buffer;
}
catch(Exception e){
//System.err.println("e "+e);
}
return null;
return kpair.getSignature(data);
}

/**
* @deprecated This method should not be invoked.
* @see #setPassphrase(byte[] passphrase)
*/
public boolean decrypt(){
if(type==RSA) return decrypt_rsa();
return decrypt_dss();
}

boolean decrypt_rsa(){
byte[] p_array;
byte[] q_array;
byte[] dmp1_array;
byte[] dmq1_array;
byte[] iqmp_array;

try{
byte[] plain;
if(encrypted){
if(keytype==OPENSSH){
cipher.init(Cipher.DECRYPT_MODE, key, iv);
plain=new byte[encoded_data.length];
cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
}
else if(keytype==FSECURE){
for(int i=0; i<iv.length; i++)iv[i]=0;
cipher.init(Cipher.DECRYPT_MODE, key, iv);
plain=new byte[encoded_data.length];
cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
}
else{
return false;
}
}
else{
if(n_array!=null) return true;
plain=encoded_data;
}

if(keytype==FSECURE){ // FSecure
Buffer buf=new Buffer(plain);
int foo=buf.getInt();
if(plain.length!=foo+4){
return false;
}
e_array=buf.getMPIntBits();
d_array=buf.getMPIntBits();
n_array=buf.getMPIntBits();
byte[] u_array=buf.getMPIntBits();
p_array=buf.getMPIntBits();
q_array=buf.getMPIntBits();
return true;
}

int index=0;
int length=0;

if(plain[index]!=0x30)return false;
index++; // SEQUENCE
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}

if(plain[index]!=0x02)return false;
index++; // INTEGER
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
index+=length;

//System.err.println("int: len="+length);
//System.err.print(Integer.toHexString(plain[index-1]&0xff)+":");
//System.err.println("");

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
n_array=new byte[length];
System.arraycopy(plain, index, n_array, 0, length);
index+=length;
/*
System.err.println("int: N len="+length);
for(int i=0; i<n_array.length; i++){
System.err.print(Integer.toHexString(n_array[i]&0xff)+":");
}
System.err.println("");
*/
index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
e_array=new byte[length];
System.arraycopy(plain, index, e_array, 0, length);
index+=length;
/*
System.err.println("int: E len="+length);
for(int i=0; i<e_array.length; i++){
System.err.print(Integer.toHexString(e_array[i]&0xff)+":");
}
System.err.println("");
*/
index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
d_array=new byte[length];
System.arraycopy(plain, index, d_array, 0, length);
index+=length;
/*
System.err.println("int: D len="+length);
for(int i=0; i<d_array.length; i++){
System.err.print(Integer.toHexString(d_array[i]&0xff)+":");
}
System.err.println("");
*/

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
p_array=new byte[length];
System.arraycopy(plain, index, p_array, 0, length);
index+=length;
/*
System.err.println("int: P len="+length);
for(int i=0; i<p_array.length; i++){
System.err.print(Integer.toHexString(p_array[i]&0xff)+":");
}
System.err.println("");
*/
index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
q_array=new byte[length];
System.arraycopy(plain, index, q_array, 0, length);
index+=length;
/*
System.err.println("int: q len="+length);
for(int i=0; i<q_array.length; i++){
System.err.print(Integer.toHexString(q_array[i]&0xff)+":");
}
System.err.println("");
*/
index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
dmp1_array=new byte[length];
System.arraycopy(plain, index, dmp1_array, 0, length);
index+=length;
/*
System.err.println("int: dmp1 len="+length);
for(int i=0; i<dmp1_array.length; i++){
System.err.print(Integer.toHexString(dmp1_array[i]&0xff)+":");
}
System.err.println("");
*/
index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
dmq1_array=new byte[length];
System.arraycopy(plain, index, dmq1_array, 0, length);
index+=length;
/*
System.err.println("int: dmq1 len="+length);
for(int i=0; i<dmq1_array.length; i++){
System.err.print(Integer.toHexString(dmq1_array[i]&0xff)+":");
}
System.err.println("");
*/
index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
iqmp_array=new byte[length];
System.arraycopy(plain, index, iqmp_array, 0, length);
index+=length;
/*
System.err.println("int: iqmp len="+length);
for(int i=0; i<iqmp_array.length; i++){
System.err.print(Integer.toHexString(iqmp_array[i]&0xff)+":");
}
System.err.println("");
*/
}
catch(Exception e){
//System.err.println(e);
return false;
}
return true;
}

boolean decrypt_dss(){
try{
byte[] plain;
if(encrypted){
if(keytype==OPENSSH){
cipher.init(Cipher.DECRYPT_MODE, key, iv);
plain=new byte[encoded_data.length];
cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
/*
for(int i=0; i<plain.length; i++){
System.err.print(Integer.toHexString(plain[i]&0xff)+":");
}
System.err.println("");
*/
}
else if(keytype==FSECURE){
for(int i=0; i<iv.length; i++)iv[i]=0;
cipher.init(Cipher.DECRYPT_MODE, key, iv);
plain=new byte[encoded_data.length];
cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
}
else{
return false;
}
}
else{
if(P_array!=null) return true;
plain=encoded_data;
}

if(keytype==FSECURE){ // FSecure
Buffer buf=new Buffer(plain);
int foo=buf.getInt();
if(plain.length!=foo+4){
return false;
}
P_array=buf.getMPIntBits();
G_array=buf.getMPIntBits();
Q_array=buf.getMPIntBits();
pub_array=buf.getMPIntBits();
prv_array=buf.getMPIntBits();
return true;
}

int index=0;
int length=0;
if(plain[index]!=0x30)return false;
index++; // SEQUENCE
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
if(plain[index]!=0x02)return false;
index++; // INTEGER
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
index+=length;

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
P_array=new byte[length];
System.arraycopy(plain, index, P_array, 0, length);
index+=length;

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
Q_array=new byte[length];
System.arraycopy(plain, index, Q_array, 0, length);
index+=length;

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
G_array=new byte[length];
System.arraycopy(plain, index, G_array, 0, length);
index+=length;

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
pub_array=new byte[length];
System.arraycopy(plain, index, pub_array, 0, length);
index+=length;

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
}
prv_array=new byte[length];
System.arraycopy(plain, index, prv_array, 0, length);
index+=length;
}
catch(Exception e){
//System.err.println(e);
//e.printStackTrace();
return false;
}
return true;
throw new RuntimeException("not implemented");
}

public boolean isEncrypted(){
return encrypted;
/**
* Returns the name of the key algorithm.
* @return "ssh-rsa" or "ssh-dss"
*/
public String getAlgName(){
return new String(kpair.getKeyTypeName());
}

/**
* Returns the name of this identity.
* It will be useful to identify this object in the {@link IdentityRepository}.
*/
public String getName(){
return identity;
}

private byte a2b(byte c){
if('0'<=c&&c<='9') return (byte)(c-'0');
if('a'<=c&&c<='z') return (byte)(c-'a'+10);
return (byte)(c-'A'+10);
}

public boolean equals(Object o){
if(!(o instanceof IdentityFile)) return super.equals(o);
IdentityFile foo=(IdentityFile)o;
return getName().equals(foo.getName());
/**
* Returns <tt>true</tt> if this identity is cyphered.
* @return <tt>true</tt> if this identity is cyphered.
*/
public boolean isEncrypted(){
return kpair.isEncrypted();
}

/**
* Disposes internally allocated data, like byte array for the private key.
*/
public void clear(){
Util.bzero(encoded_data);
Util.bzero(prv_array);
Util.bzero(d_array);
Util.bzero(key);
Util.bzero(iv);
kpair.dispose();
kpair = null;
}

public void finalize (){
clear();
/**
* Returns an instance of {@link KeyPair} used in this {@link Identity}.
* @return an instance of {@link KeyPair} used in this {@link Identity}.
*/
public KeyPair getKeyPair(){
return kpair;
}
}

+ 77
- 2
java/com/jcraft/jsch/IdentityRepository.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2012-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,10 +31,85 @@ package com.jcraft.jsch;

import java.util.Vector;

@SuppressWarnings({"rawtypes"})
public interface IdentityRepository {
public static final int UNAVAILABLE=0;
public static final int NOTRUNNING=1;
public static final int RUNNING=2;
public String getName();
public int getStatus();
public Vector getIdentities();
public boolean add(byte[] identity);
public boolean remove(byte[] blob);
public void removeAll();

/**
* JSch will accept ciphered keys, but some implementations of
* IdentityRepository can not. For example, IdentityRepository for
* ssh-agent and pageant only accept plain keys. The following class has
* been introduced to cache ciphered keys for them, and pass them
* whenever they are de-ciphered.
*/
static class Wrapper implements IdentityRepository {
private IdentityRepository ir;
private Vector cache = new Vector();
private boolean keep_in_cache = false;
Wrapper(IdentityRepository ir){
this(ir, false);
}
Wrapper(IdentityRepository ir, boolean keep_in_cache){
this.ir = ir;
this.keep_in_cache = keep_in_cache;
}
public String getName() {
return ir.getName();
}
public int getStatus() {
return ir.getStatus();
}
public boolean add(byte[] identity) {
return ir.add(identity);
}
public boolean remove(byte[] blob) {
return ir.remove(blob);
}
public void removeAll() {
cache.removeAllElements();
ir.removeAll();
}
public Vector getIdentities() {
Vector result = new Vector();
for(int i = 0; i< cache.size(); i++){
Identity identity = (Identity)(cache.elementAt(i));
result.add(identity);
}
Vector tmp = ir.getIdentities();
for(int i = 0; i< tmp.size(); i++){
result.add(tmp.elementAt(i));
}
return result;
}
void add(Identity identity) {
if(!keep_in_cache &&
!identity.isEncrypted() && (identity instanceof IdentityFile)) {
try {
ir.add(((IdentityFile)identity).getKeyPair().forSSHAgent());
}
catch(JSchException e){
// an exception will not be thrown.
}
}
else
cache.addElement(identity);
}
void check() {
if(cache.size() > 0){
Object[] identities = cache.toArray();
for(int i = 0; i < identities.length; i++){
Identity identity = (Identity)(identities[i]);
cache.removeElement(identity);
add(identity);
}
}
}
}
}

+ 307
- 33
java/com/jcraft/jsch/JSch.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -32,28 +32,25 @@ package com.jcraft.jsch;
import java.io.InputStream;
import java.util.Vector;

@SuppressWarnings({"rawtypes","unchecked"})
public class JSch{
public static final String VERSION = "0.1.46";
/**
* The version number.
*/
public static final String VERSION = "0.1.53";

static java.util.Hashtable config=new java.util.Hashtable();
static{
// config.put("kex", "diffie-hellman-group-exchange-sha1");
config.put("kex", "diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1");
config.put("server_host_key", "ssh-rsa,ssh-dss");
// config.put("server_host_key", "ssh-dss,ssh-rsa");

config.put("kex", "ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1");
config.put("server_host_key", "ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521");
config.put("cipher.s2c",
"aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc");
"aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc");
config.put("cipher.c2s",
"aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc");
"aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc");

config.put("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96");
config.put("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96");
config.put("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96");
config.put("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96");
config.put("compression.s2c", "none");
// config.put("compression.s2c", "zlib@openssh.com,zlib,none");
config.put("compression.c2s", "none");
// config.put("compression.c2s", "zlib@openssh.com,zlib,none");

config.put("lang.s2c", "");
config.put("lang.c2s", "");
@@ -65,21 +62,42 @@ public class JSch{
config.put("diffie-hellman-group1-sha1",
"com.jcraft.jsch.DHG1");
config.put("diffie-hellman-group14-sha1",
"com.jcraft.jsch.DHG14");
"com.jcraft.jsch.DHG14"); // available since JDK8.
config.put("diffie-hellman-group-exchange-sha256",
"com.jcraft.jsch.DHGEX256"); // available since JDK1.4.2.
// On JDK8, 2048bits will be used.
config.put("ecdsa-sha2-nistp256", "com.jcraft.jsch.jce.SignatureECDSA");
config.put("ecdsa-sha2-nistp384", "com.jcraft.jsch.jce.SignatureECDSA");
config.put("ecdsa-sha2-nistp521", "com.jcraft.jsch.jce.SignatureECDSA");

config.put("ecdh-sha2-nistp256", "com.jcraft.jsch.DHEC256");
config.put("ecdh-sha2-nistp384", "com.jcraft.jsch.DHEC384");
config.put("ecdh-sha2-nistp521", "com.jcraft.jsch.DHEC521");

config.put("ecdh-sha2-nistp", "com.jcraft.jsch.jce.ECDHN");

config.put("dh", "com.jcraft.jsch.jce.DH");
config.put("3des-cbc", "com.jcraft.jsch.jce.TripleDESCBC");
config.put("blowfish-cbc", "com.jcraft.jsch.jce.BlowfishCBC");
config.put("hmac-sha1", "com.jcraft.jsch.jce.HMACSHA1");
config.put("hmac-sha1-96", "com.jcraft.jsch.jce.HMACSHA196");
config.put("hmac-sha2-256", "com.jcraft.jsch.jce.HMACSHA256");
// The "hmac-sha2-512" will require the key-length 2048 for DH,
// but Sun's JCE has not allowed to use such a long key.
//config.put("hmac-sha2-512", "com.jcraft.jsch.jce.HMACSHA512");
config.put("hmac-md5", "com.jcraft.jsch.jce.HMACMD5");
config.put("hmac-md5-96", "com.jcraft.jsch.jce.HMACMD596");
config.put("sha-1", "com.jcraft.jsch.jce.SHA1");
config.put("sha-256", "com.jcraft.jsch.jce.SHA256");
config.put("sha-384", "com.jcraft.jsch.jce.SHA384");
config.put("sha-512", "com.jcraft.jsch.jce.SHA512");
config.put("md5", "com.jcraft.jsch.jce.MD5");
config.put("signature.dss", "com.jcraft.jsch.jce.SignatureDSA");
config.put("signature.rsa", "com.jcraft.jsch.jce.SignatureRSA");
config.put("signature.ecdsa", "com.jcraft.jsch.jce.SignatureECDSA");
config.put("keypairgen.dsa", "com.jcraft.jsch.jce.KeyPairGenDSA");
config.put("keypairgen.rsa", "com.jcraft.jsch.jce.KeyPairGenRSA");
config.put("keypairgen.ecdsa", "com.jcraft.jsch.jce.KeyPairGenECDSA");
config.put("random", "com.jcraft.jsch.jce.Random");

config.put("none", "com.jcraft.jsch.CipherNone");
@@ -106,30 +124,60 @@ public class JSch{
config.put("zlib", "com.jcraft.jsch.jcraft.Compression");
config.put("zlib@openssh.com", "com.jcraft.jsch.jcraft.Compression");

config.put("pbkdf", "com.jcraft.jsch.jce.PBKDF");

config.put("StrictHostKeyChecking", "ask");
config.put("HashKnownHosts", "no");
//config.put("HashKnownHosts", "yes");
config.put("PreferredAuthentications", "gssapi-with-mic,publickey,keyboard-interactive,password");

config.put("CheckCiphers", "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256");
config.put("CheckKexes", "diffie-hellman-group14-sha1");
config.put("CheckKexes", "diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521");
config.put("CheckSignatures", "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521");

config.put("MaxAuthTries", "6");
config.put("ClearAllForwardings", "no");
}

private java.util.Vector sessionPool = new java.util.Vector();

private IdentityRepository identityRepository =
private IdentityRepository defaultIdentityRepository =
new LocalIdentityRepository(this);

private IdentityRepository identityRepository = defaultIdentityRepository;

private ConfigRepository configRepository = null;

/**
* Sets the <code>identityRepository</code>, which will be referred
* in the public key authentication.
*
* @param identityRepository if <code>null</code> is given,
* the default repository, which usually refers to ~/.ssh/, will be used.
*
* @see #getIdentityRepository()
*/
public synchronized void setIdentityRepository(IdentityRepository identityRepository){
this.identityRepository = identityRepository;
if(identityRepository == null){
this.identityRepository = defaultIdentityRepository;
}
else{
this.identityRepository = identityRepository;
}
}

synchronized IdentityRepository getIdentityRepository(){
public synchronized IdentityRepository getIdentityRepository(){
return this.identityRepository;
}

public ConfigRepository getConfigRepository() {
return this.configRepository;
}

public void setConfigRepository(ConfigRepository configRepository) {
this.configRepository = configRepository;
}

private HostKeyRepository known_hosts=null;

private static final Logger DEVNULL=new Logger(){
@@ -139,7 +187,9 @@ public class JSch{
static Logger logger=DEVNULL;

public JSch(){

/*
// The JCE of Sun's Java5 on Mac OS X has the resource leak bug
// in calculating HMAC, so we need to use our own implementations.
try{
String osname=(String)(System.getProperties().get("os.name"));
if(osname!=null && osname.equals("Mac OS X")){
@@ -151,21 +201,77 @@ public class JSch{
}
catch(Exception e){
}
*/
}

/**
* Instantiates the <code>Session</code> object with
* <code>host</code>. The user name and port number will be retrieved from
* ConfigRepository. If user name is not given,
* the system property "user.name" will be referred.
*
* @param host hostname
*
* @throws JSchException
* if <code>username</code> or <code>host</code> are invalid.
*
* @return the instance of <code>Session</code> class.
*
* @see #getSession(String username, String host, int port)
* @see com.jcraft.jsch.Session
* @see com.jcraft.jsch.ConfigRepository
*/
public Session getSession(String host)
throws JSchException {
return getSession(null, host, 22);
}

public Session getSession(String username, String host) throws JSchException { return getSession(username, host, 22); }
/**
* Instantiates the <code>Session</code> object with
* <code>username</code> and <code>host</code>.
* The TCP port 22 will be used in making the connection.
* Note that the TCP connection must not be established
* until Session#connect().
*
* @param username user name
* @param host hostname
*
* @throws JSchException
* if <code>username</code> or <code>host</code> are invalid.
*
* @return the instance of <code>Session</code> class.
*
* @see #getSession(String username, String host, int port)
* @see com.jcraft.jsch.Session
*/
public Session getSession(String username, String host)
throws JSchException {
return getSession(username, host, 22);
}

/**
* Instantiates the <code>Session</code> object with given
* <code>username</code>, <code>host</code> and <code>port</code>.
* Note that the TCP connection must not be established
* until Session#connect().
*
* @param username user name
* @param host hostname
* @param port port number
*
* @throws JSchException
* if <code>username</code> or <code>host</code> are invalid.
*
* @return the instance of <code>Session</code> class.
*
* @see #getSession(String username, String host, int port)
* @see com.jcraft.jsch.Session
*/
public Session getSession(String username, String host, int port) throws JSchException {
if(username==null){
throw new JSchException("username must not be null.");
}
if(host==null){
throw new JSchException("host must not be null.");
}
Session s=new Session(this);
s.setUserName(username);
s.setHost(host);
s.setPort(port);
Session s = new Session(this, username, host, port);
return s;
}

@@ -180,10 +286,30 @@ public class JSch{
return sessionPool.remove(session);
}
}

/**
* Sets the hostkey repository.
*
* @param hkrepo
*
* @see com.jcraft.jsch.HostKeyRepository
* @see com.jcraft.jsch.KnownHosts
*/
public void setHostKeyRepository(HostKeyRepository hkrepo){
known_hosts=hkrepo;
}

/**
* Sets the instance of <code>KnownHosts</code>, which refers
* to <code>filename</code>.
*
* @param filename filename of known_hosts file.
*
* @throws JSchException
* if the given filename is invalid.
*
* @see com.jcraft.jsch.KnownHosts
*/
public void setKnownHosts(String filename) throws JSchException{
if(known_hosts==null) known_hosts=new KnownHosts(this);
if(known_hosts instanceof KnownHosts){
@@ -193,6 +319,17 @@ public class JSch{
}
}

/**
* Sets the instance of <code>KnownHosts</code> generated with
* <code>stream</code>.
*
* @param stream the instance of InputStream from known_hosts file.
*
* @throws JSchException
* if an I/O error occurs.
*
* @see com.jcraft.jsch.KnownHosts
*/
public void setKnownHosts(InputStream stream) throws JSchException{
if(known_hosts==null) known_hosts=new KnownHosts(this);
if(known_hosts instanceof KnownHosts){
@@ -202,15 +339,47 @@ public class JSch{
}
}

/**
* Returns the current hostkey repository.
* By the default, this method will the instance of <code>KnownHosts</code>.
*
* @return current hostkey repository.
*
* @see com.jcraft.jsch.HostKeyRepository
* @see com.jcraft.jsch.KnownHosts
*/
public HostKeyRepository getHostKeyRepository(){
if(known_hosts==null) known_hosts=new KnownHosts(this);
return known_hosts;
}

/**
* Sets the private key, which will be referred in
* the public key authentication.
*
* @param prvkey filename of the private key.
*
* @throws JSchException if <code>prvkey</code> is invalid.
*
* @see #addIdentity(String prvkey, String passphrase)
*/
public void addIdentity(String prvkey) throws JSchException{
addIdentity(prvkey, (byte[])null);
}

/**
* Sets the private key, which will be referred in
* the public key authentication.
* Before registering it into identityRepository,
* it will be deciphered with <code>passphrase</code>.
*
* @param prvkey filename of the private key.
* @param passphrase passphrase for <code>prvkey</code>.
*
* @throws JSchException if <code>passphrase</code> is not right.
*
* @see #addIdentity(String prvkey, byte[] passphrase)
*/
public void addIdentity(String prvkey, String passphrase) throws JSchException{
byte[] _passphrase=null;
if(passphrase!=null){
@@ -221,20 +390,70 @@ public class JSch{
Util.bzero(_passphrase);
}

/**
* Sets the private key, which will be referred in
* the public key authentication.
* Before registering it into identityRepository,
* it will be deciphered with <code>passphrase</code>.
*
* @param prvkey filename of the private key.
* @param passphrase passphrase for <code>prvkey</code>.
*
* @throws JSchException if <code>passphrase</code> is not right.
*
* @see #addIdentity(String prvkey, String pubkey, byte[] passphrase)
*/
public void addIdentity(String prvkey, byte[] passphrase) throws JSchException{
Identity identity=IdentityFile.newInstance(prvkey, null, this);
addIdentity(identity, passphrase);
}

/**
* Sets the private key, which will be referred in
* the public key authentication.
* Before registering it into identityRepository,
* it will be deciphered with <code>passphrase</code>.
*
* @param prvkey filename of the private key.
* @param pubkey filename of the public key.
* @param passphrase passphrase for <code>prvkey</code>.
*
* @throws JSchException if <code>passphrase</code> is not right.
*/
public void addIdentity(String prvkey, String pubkey, byte[] passphrase) throws JSchException{
Identity identity=IdentityFile.newInstance(prvkey, pubkey, this);
addIdentity(identity, passphrase);
}

/**
* Sets the private key, which will be referred in
* the public key authentication.
* Before registering it into identityRepository,
* it will be deciphered with <code>passphrase</code>.
*
* @param name name of the identity to be used to
retrieve it in the identityRepository.
* @param prvkey private key in byte array.
* @param pubkey public key in byte array.
* @param passphrase passphrase for <code>prvkey</code>.
*
*/
public void addIdentity(String name, byte[]prvkey, byte[]pubkey, byte[] passphrase) throws JSchException{
Identity identity=IdentityFile.newInstance(name, prvkey, pubkey, this);
addIdentity(identity, passphrase);
}

/**
* Sets the private key, which will be referred in
* the public key authentication.
* Before registering it into identityRepository,
* it will be deciphered with <code>passphrase</code>.
*
* @param identity private key.
* @param passphrase passphrase for <code>identity</code>.
*
* @throws JSchException if <code>passphrase</code> is not right.
*/
public void addIdentity(Identity identity, byte[] passphrase) throws JSchException{
if(passphrase!=null){
try{
@@ -251,13 +470,21 @@ public class JSch{
if(identityRepository instanceof LocalIdentityRepository){
((LocalIdentityRepository)identityRepository).add(identity);
}
else if(identity instanceof IdentityFile && !identity.isEncrypted()) {
identityRepository.add(((IdentityFile)identity).getKeyPair().forSSHAgent());
}
else {
// TODO
synchronized(this){
if(!(identityRepository instanceof IdentityRepository.Wrapper)){
setIdentityRepository(new IdentityRepository.Wrapper(identityRepository));
}
}
((IdentityRepository.Wrapper)identityRepository).add(identity);
}
}

/**
* @deprecated use JSch#removeIdentity(Identity identity)
* @deprecated use #removeIdentity(Identity identity)
*/
public void removeIdentity(String name) throws JSchException{
Vector identities = identityRepository.getIdentities();
@@ -265,15 +492,32 @@ public class JSch{
Identity identity=(Identity)(identities.elementAt(i));
if(!identity.getName().equals(name))
continue;
identityRepository.remove(identity.getPublicKeyBlob());
break;
if(identityRepository instanceof LocalIdentityRepository){
((LocalIdentityRepository)identityRepository).remove(identity);
}
else
identityRepository.remove(identity.getPublicKeyBlob());
}
}

/**
* Removes the identity from identityRepository.
*
* @param identity the indentity to be removed.
*
* @throws JSchException if <code>identity</code> is invalid.
*/
public void removeIdentity(Identity identity) throws JSchException{
identityRepository.remove(identity.getPublicKeyBlob());
}

/**
* Lists names of identities included in the identityRepository.
*
* @return names of identities
*
* @throws JSchException if identityReposory has problems.
*/
public Vector getIdentityNames() throws JSchException{
Vector foo=new Vector();
Vector identities = identityRepository.getIdentities();
@@ -284,16 +528,32 @@ public class JSch{
return foo;
}

/**
* Removes all identities from identityRepository.
*
* @throws JSchException if identityReposory has problems.
*/
public void removeAllIdentity() throws JSchException{
identityRepository.removeAll();
}

/**
* Returns the config value for the specified key.
*
* @param key key for the configuration.
* @return config value
*/
public static String getConfig(String key){
synchronized(config){
return (String)(config.get(key));
}
}

/**
* Sets or Overrides the configuration.
*
* @param newconf configurations
*/
public static void setConfig(java.util.Hashtable newconf){
synchronized(config){
for(java.util.Enumeration e=newconf.keys() ; e.hasMoreElements() ;) {
@@ -303,14 +563,28 @@ public class JSch{
}
}

/**
* Sets or Overrides the configuration.
*
* @param key key for the configuration
* @param value value for the configuration
*/
public static void setConfig(String key, String value){
config.put(key, value);
}

/**
* Sets the logger
*
* @param logger logger
*
* @see com.jcraft.jsch.Logger
*/
public static void setLogger(Logger logger){
if(logger==null) logger=DEVNULL;
JSch.logger=logger;
}

static Logger getLogger(){
return logger;
}

+ 1
- 1
java/com/jcraft/jsch/JSchAuthCancelException.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/JSchException.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/JSchPartialAuthException.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 182
- 17
java/com/jcraft/jsch/KeyExchange.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,7 +29,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.jcraft.jsch;

@SuppressWarnings({"rawtypes"})
public abstract class KeyExchange{

static final int PROPOSAL_KEX_ALGS=0;
@@ -71,25 +70,43 @@ public abstract class KeyExchange{
public abstract void init(Session session,
byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception;
public abstract boolean next(Buffer buf) throws Exception;
public abstract String getKeyType();
public abstract int getState();

/*
void dump(byte[] foo){
for(int i=0; i<foo.length; i++){
if((foo[i]&0xf0)==0)System.err.print("0");
System.err.print(Integer.toHexString(foo[i]&0xff));
if(i%16==15){System.err.println(""); continue;}
if(i%2==1)System.err.print(" ");
}
}
*/
protected final int RSA=0;
protected final int DSS=1;
protected final int ECDSA=2;
private int type=0;
private String key_alg_name = "";

public String getKeyType() {
if(type==DSS) return "DSA";
if(type==RSA) return "RSA";
return "ECDSA";
}

public String getKeyAlgorithName() {
return key_alg_name;
}

protected static String[] guess(byte[]I_S, byte[]I_C){
String[] guess=new String[PROPOSAL_MAX];
Buffer sb=new Buffer(I_S); sb.setOffSet(17);
Buffer cb=new Buffer(I_C); cb.setOffSet(17);

if(JSch.getLogger().isEnabled(Logger.INFO)){
for(int i=0; i<PROPOSAL_MAX; i++){
JSch.getLogger().log(Logger.INFO,
"kex: server: "+Util.byte2str(sb.getString()));
}
for(int i=0; i<PROPOSAL_MAX; i++){
JSch.getLogger().log(Logger.INFO,
"kex: client: "+Util.byte2str(cb.getString()));
}
sb.setOffSet(17);
cb.setOffSet(17);
}

for(int i=0; i<PROPOSAL_MAX; i++){
byte[] sp=sb.getString(); // server proposal
byte[] cp=cb.getString(); // client proposal
@@ -137,10 +154,6 @@ public abstract class KeyExchange{
" "+guess[PROPOSAL_COMP_ALGS_CTOS]);
}

// for(int i=0; i<PROPOSAL_MAX; i++){
// System.err.println("guess: ["+guess[i]+"]");
// }

return guess;
}

@@ -157,4 +170,156 @@ public abstract class KeyExchange{
byte[] getH(){ return H; }
HASH getHash(){ return sha; }
byte[] getHostKey(){ return K_S; }

/*
* It seems JCE included in Oracle's Java7u6(and later) has suddenly changed
* its behavior. The secrete generated by KeyAgreement#generateSecret()
* may start with 0, even if it is a positive value.
*/
protected byte[] normalize(byte[] secret) {
if(secret.length > 1 &&
secret[0] == 0 && (secret[1]&0x80) == 0) {
byte[] tmp=new byte[secret.length-1];
System.arraycopy(secret, 1, tmp, 0, tmp.length);
return normalize(tmp);
}
else {
return secret;
}
}

protected boolean verify(String alg, byte[] K_S, int index,
byte[] sig_of_H) throws Exception {
int i,j;

i=index;
boolean result=false;

if(alg.equals("ssh-rsa")){
byte[] tmp;
byte[] ee;
byte[] n;

type=RSA;
key_alg_name=alg;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
ee=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
n=tmp;
SignatureRSA sig=null;
try{
Class c=Class.forName(session.getConfig("signature.rsa"));
sig=(SignatureRSA)(c.newInstance());
sig.init();
}
catch(Exception e){
System.err.println(e);
}
sig.setPubKey(ee, n);
sig.update(H);
result=sig.verify(sig_of_H);

if(JSch.getLogger().isEnabled(Logger.INFO)){
JSch.getLogger().log(Logger.INFO,
"ssh_rsa_verify: signature "+result);
}
}
else if(alg.equals("ssh-dss")){
byte[] q=null;
byte[] tmp;
byte[] p;
byte[] g;
byte[] f;
type=DSS;
key_alg_name=alg;

j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
p=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
q=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
g=tmp;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
f=tmp;

SignatureDSA sig=null;
try{
Class c=Class.forName(session.getConfig("signature.dss"));
sig=(SignatureDSA)(c.newInstance());
sig.init();
}
catch(Exception e){
System.err.println(e);
}
sig.setPubKey(f, p, q, g);
sig.update(H);
result=sig.verify(sig_of_H);

if(JSch.getLogger().isEnabled(Logger.INFO)){
JSch.getLogger().log(Logger.INFO,
"ssh_dss_verify: signature "+result);
}
}
else if(alg.equals("ecdsa-sha2-nistp256") ||
alg.equals("ecdsa-sha2-nistp384") ||
alg.equals("ecdsa-sha2-nistp521")) {
byte[] tmp;
byte[] r;
byte[] s;

// RFC 5656,
type=ECDSA;
key_alg_name=alg;

j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
i++;
tmp=new byte[(j-1)/2];
System.arraycopy(K_S, i, tmp, 0, tmp.length); i+=(j-1)/2;
r=tmp;
tmp=new byte[(j-1)/2];
System.arraycopy(K_S, i, tmp, 0, tmp.length); i+=(j-1)/2;
s=tmp;

SignatureECDSA sig=null;
try{
Class c=Class.forName(session.getConfig("signature.ecdsa"));
sig=(SignatureECDSA)(c.newInstance());
sig.init();
}
catch(Exception e){
System.err.println(e);
}

sig.setPubKey(r, s);

sig.update(H);

result=sig.verify(sig_of_H);
}
else{
System.err.println("unknown alg");
}

return result;
}

}

+ 593
- 67
java/com/jcraft/jsch/KeyPair.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -32,15 +32,20 @@ package com.jcraft.jsch;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.File;
import java.io.IOException;

public abstract class KeyPair{
public static final int ERROR=0;
public static final int DSA=1;
public static final int RSA=2;
public static final int UNKNOWN=3;
public static final int ECDSA=3;
public static final int UNKNOWN=4;

static final int VENDOR_OPENSSH=0;
static final int VENDOR_FSECURE=1;
static final int VENDOR_PUTTY=2;
static final int VENDOR_PKCS8=3;

int vendor=VENDOR_OPENSSH;

private static final byte[] cr=Util.str2byte("\n");
@@ -52,6 +57,7 @@ public abstract class KeyPair{
KeyPair kpair=null;
if(type==DSA){ kpair=new KeyPairDSA(jsch); }
else if(type==RSA){ kpair=new KeyPairRSA(jsch); }
else if(type==ECDSA){ kpair=new KeyPairECDSA(jsch); }
if(kpair!=null){
kpair.generate(key_size);
}
@@ -64,10 +70,20 @@ public abstract class KeyPair{
abstract byte[] getEnd();
abstract int getKeySize();

public abstract byte[] getSignature(byte[] data);
public abstract Signature getVerifier();

public abstract byte[] forSSHAgent() throws JSchException;

public String getPublicKeyComment(){
return publicKeyComment;
}
private String publicKeyComment = "";

public void setPublicKeyComment(String publicKeyComment){
this.publicKeyComment = publicKeyComment;
}

protected String publicKeyComment = "no comment";

JSch jsch=null;
private Cipher cipher;
@@ -85,10 +101,27 @@ public abstract class KeyPair{

abstract byte[] getPrivateKey();

/**
* Writes the plain private key to the given output stream.
* @param out output stream
* @see #writePrivateKey(java.io.OutputStream out, byte[] passphrase)
*/
public void writePrivateKey(java.io.OutputStream out){
this.writePrivateKey(out, null);
}

/**
* Writes the cyphered private key to the given output stream.
* @param out output stream
* @param passphrase a passphrase to encrypt the private key
*/
public void writePrivateKey(java.io.OutputStream out, byte[] passphrase){
if(passphrase == null)
passphrase = this.passphrase;

byte[] plain=getPrivateKey();
byte[][] _iv=new byte[1][];
byte[] encoded=encrypt(plain, _iv);
byte[] encoded=encrypt(plain, _iv, passphrase);
if(encoded!=plain)
Util.bzero(plain);
byte[] iv=_iv[0];
@@ -130,8 +163,22 @@ public abstract class KeyPair{
abstract byte[] getKeyTypeName();
public abstract int getKeyType();

public byte[] getPublicKeyBlob(){ return publickeyblob; }
/**
* Returns the blob of the public key.
* @return blob of the public key
*/
public byte[] getPublicKeyBlob() {
// TODO JSchException should be thrown
//if(publickeyblob == null)
// throw new JSchException("public-key blob is not available");
return publickeyblob;
}

/**
* Writes the public key with the specified comment to the output stream.
* @param out output stream
* @param comment comment
*/
public void writePublicKey(java.io.OutputStream out, String comment){
byte[] pubblob=getPublicKeyBlob();
byte[] pub=Util.toBase64(pubblob, 0, pubblob.length);
@@ -145,12 +192,24 @@ public abstract class KeyPair{
}
}

/**
* Writes the public key with the specified comment to the file.
* @param name file name
* @param comment comment
* @see #writePublicKey(java.io.OutputStream out, String comment)
*/
public void writePublicKey(String name, String comment) throws java.io.FileNotFoundException, java.io.IOException{
FileOutputStream fos=new FileOutputStream(name);
writePublicKey(fos, comment);
fos.close();
}

/**
* Writes the public key with the specified comment to the output stream in
* the format defined in http://www.ietf.org/rfc/rfc4716.txt
* @param out output stream
* @param comment comment
*/
public void writeSECSHPublicKey(java.io.OutputStream out, String comment){
byte[] pubblob=getPublicKeyBlob();
byte[] pub=Util.toBase64(pubblob, 0, pubblob.length);
@@ -170,27 +229,52 @@ public abstract class KeyPair{
}
}

/**
* Writes the public key with the specified comment to the output stream in
* the format defined in http://www.ietf.org/rfc/rfc4716.txt
* @param name file name
* @param comment comment
* @see #writeSECSHPublicKey(java.io.OutputStream out, String comment)
*/
public void writeSECSHPublicKey(String name, String comment) throws java.io.FileNotFoundException, java.io.IOException{
FileOutputStream fos=new FileOutputStream(name);
writeSECSHPublicKey(fos, comment);
fos.close();
}


/**
* Writes the plain private key to the file.
* @param name file name
* @see #writePrivateKey(String name, byte[] passphrase)
*/
public void writePrivateKey(String name) throws java.io.FileNotFoundException, java.io.IOException{
this.writePrivateKey(name, null);
}

/**
* Writes the cyphered private key to the file.
* @param name file name
* @param passphrase a passphrase to encrypt the private key
* @see #writePrivateKey(java.io.OutputStream out, byte[] passphrase)
*/
public void writePrivateKey(String name, byte[] passphrase) throws java.io.FileNotFoundException, java.io.IOException{
FileOutputStream fos=new FileOutputStream(name);
writePrivateKey(fos);
writePrivateKey(fos, passphrase);
fos.close();
}

/**
* Returns the finger-print of the public key.
* @return finger print
*/
public String getFingerPrint(){
if(hash==null) hash=genHash();
byte[] kblob=getPublicKeyBlob();
if(kblob==null) return null;
return getKeySize()+" "+Util.getFingerPrint(hash, kblob);
return Util.getFingerPrint(hash, kblob);
}

private byte[] encrypt(byte[] plain, byte[][] _iv){
private byte[] encrypt(byte[] plain, byte[][] _iv, byte[] passphrase){
if(passphrase==null) return plain;

if(cipher==null) cipher=genCipher();
@@ -229,12 +313,7 @@ public abstract class KeyPair{
abstract boolean parse(byte[] data);

private byte[] decrypt(byte[] data, byte[] passphrase, byte[] iv){
/*
if(iv==null){ // FSecure
iv=new byte[8];
for(int i=0; i<iv.length; i++)iv[i]=0;
}
*/

try{
byte[] key=genKey(passphrase, iv);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
@@ -262,6 +341,22 @@ public abstract class KeyPair{
return index;
}

int writeOCTETSTRING(byte[] buf, int index, byte[] data){
buf[index++]=0x04;
index=writeLength(buf, index, data.length);
System.arraycopy(data, 0, buf, index, data.length);
index+=data.length;
return index;
}

int writeDATA(byte[] buf, byte n, int index, byte[] data){
buf[index++]=n;
index=writeLength(buf, index, data.length);
System.arraycopy(data, 0, buf, index, data.length);
index+=data.length;
return index;
}

int countLength(int len){
int i=1;
if(len<=0x7f) return i;
@@ -357,6 +452,19 @@ public abstract class KeyPair{
}
System.arraycopy(hn, 0, key, 0, key.length);
}
else if(vendor==VENDOR_PUTTY){
Class c=Class.forName((String)jsch.getConfig("sha-1"));
HASH sha1=(HASH)(c.newInstance());
tmp = new byte[4];
key = new byte[20*2];
for(int i = 0; i < 2; i++){
sha1.init();
tmp[3]=(byte)i;
sha1.update(tmp, 0, tmp.length);
sha1.update(passphrase, 0, passphrase.length);
System.arraycopy(sha1.digest(), 0, key, i*20, 20);
}
}
}
catch(Exception e){
System.err.println(e);
@@ -364,6 +472,9 @@ public abstract class KeyPair{
return key;
}

/**
* @deprecated use #writePrivateKey(java.io.OutputStream out, byte[] passphrase)
*/
public void setPassphrase(String passphrase){
if(passphrase==null || passphrase.length()==0){
setPassphrase((byte[])null);
@@ -372,14 +483,18 @@ public abstract class KeyPair{
setPassphrase(Util.str2byte(passphrase));
}
}

/**
* @deprecated use #writePrivateKey(String name, byte[] passphrase)
*/
public void setPassphrase(byte[] passphrase){
if(passphrase!=null && passphrase.length==0)
passphrase=null;
this.passphrase=passphrase;
}

private boolean encrypted=false;
private byte[] data=null;
protected boolean encrypted=false;
protected byte[] data=null;
private byte[] iv=null;
private byte[] publickeyblob=null;

@@ -391,6 +506,7 @@ public abstract class KeyPair{
return decrypt(Util.str2byte(_passphrase));
}
public boolean decrypt(byte[] _passphrase){

if(!encrypted){
return true;
}
@@ -415,7 +531,41 @@ public abstract class KeyPair{
}
return load(jsch, prvkey, pubkey);
}
public static KeyPair load(JSch jsch, String prvkey, String pubkey) throws JSchException{
public static KeyPair load(JSch jsch, String prvfile, String pubfile) throws JSchException{

byte[] prvkey=null;
byte[] pubkey=null;

try{
prvkey = Util.fromFile(prvfile);
}
catch(IOException e){
throw new JSchException(e.toString(), (Throwable)e);
}

String _pubfile=pubfile;
if(pubfile==null){
_pubfile=prvfile+".pub";
}

try{
pubkey = Util.fromFile(_pubfile);
}
catch(IOException e){
if(pubfile!=null){
throw new JSchException(e.toString(), (Throwable)e);
}
}

try {
return load(jsch, prvkey, pubkey);
}
finally {
Util.bzero(prvkey);
}
}

public static KeyPair load(JSch jsch, byte[] prvkey, byte[] pubkey) throws JSchException{

byte[] iv=new byte[8]; // 8
boolean encrypted=true;
@@ -428,21 +578,49 @@ public abstract class KeyPair{
String publicKeyComment = "";
Cipher cipher=null;

// prvkey from "ssh-add" command on the remote.
if(pubkey==null &&
prvkey!=null &&
(prvkey.length>11 &&
prvkey[0]==0 && prvkey[1]==0 && prvkey[2]==0 &&
(prvkey[3]==7 || prvkey[3]==19))){

Buffer buf=new Buffer(prvkey);
buf.skip(prvkey.length); // for using Buffer#available()
String _type = new String(buf.getString()); // ssh-rsa or ssh-dss
buf.rewind();

KeyPair kpair=null;
if(_type.equals("ssh-rsa")){
kpair=KeyPairRSA.fromSSHAgent(jsch, buf);
}
else if(_type.equals("ssh-dss")){
kpair=KeyPairDSA.fromSSHAgent(jsch, buf);
}
else if(_type.equals("ecdsa-sha2-nistp256") ||
_type.equals("ecdsa-sha2-nistp384") ||
_type.equals("ecdsa-sha2-nistp512")){
kpair=KeyPairECDSA.fromSSHAgent(jsch, buf);
}
else{
throw new JSchException("privatekey: invalid key "+new String(prvkey, 4, 7));
}
return kpair;
}

try{
File file=new File(prvkey);
FileInputStream fis=new FileInputStream(prvkey);
byte[] buf=new byte[(int)(file.length())];
int len=0;
while(true){
int i=fis.read(buf, len, buf.length-len);
if(i<=0)
break;
len+=i;
byte[] buf=prvkey;

if(buf!=null){
KeyPair ppk = loadPPK(jsch, buf);
if(ppk !=null)
return ppk;
}
fis.close();

int len = (buf!=null ? buf.length : 0);
int i=0;

// skip garbage lines.
while(i<len){
if(buf[i] == '-' && i+4<len &&
buf[i+1] == '-' && buf[i+2] == '-' &&
@@ -454,13 +632,34 @@ public abstract class KeyPair{

while(i<len){
if(buf[i]=='B'&& i+3<len && buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I'){
i+=6;
i+=6;
if(i+2 >= len)
throw new JSchException("invalid privatekey: "+prvkey);
if(buf[i]=='D'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=DSA; }
else if(buf[i]=='R'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=RSA; }
else if(buf[i]=='E'&& buf[i+1]=='C'){ type=ECDSA; }
else if(buf[i]=='S'&& buf[i+1]=='S'&& buf[i+2]=='H'){ // FSecure
type=UNKNOWN;
vendor=VENDOR_FSECURE;
}
else if(i+6 < len &&
buf[i]=='P' && buf[i+1]=='R' &&
buf[i+2]=='I' && buf[i+3]=='V' &&
buf[i+4]=='A' && buf[i+5]=='T' && buf[i+6]=='E'){
type=UNKNOWN;
vendor=VENDOR_PKCS8;
encrypted=false;
i+=3;
}
else if(i+8 < len &&
buf[i]=='E' && buf[i+1]=='N' &&
buf[i+2]=='C' && buf[i+3]=='R' &&
buf[i+4]=='Y' && buf[i+5]=='P' && buf[i+6]=='T' &&
buf[i+7]=='E' && buf[i+8]=='D'){
type=UNKNOWN;
vendor=VENDOR_PKCS8;
i+=5;
}
else{
throw new JSchException("invalid privatekey: "+prvkey);
}
@@ -534,36 +733,60 @@ public abstract class KeyPair{
}
if(!inheader){
i++;
encrypted=false; // no passphrase
if(vendor!=VENDOR_PKCS8)
encrypted=false; // no passphrase
break;
}
}
i++;
}

if(type==ERROR){
throw new JSchException("invalid privatekey: "+prvkey);
}
if(buf!=null){

int start=i;
while(i<len){
if(buf[i]==0x0a){
boolean xd=(buf[i-1]==0x0d);
System.arraycopy(buf, i+1,
buf,
i-(xd ? 1 : 0),
len-i-1-(xd ? 1 : 0)
);
if(xd)len--;
len--;
continue;
if(type==ERROR){
throw new JSchException("invalid privatekey: "+prvkey);
}
if(buf[i]=='-'){ break; }
i++;

int start = i;
while(i < len){
if(buf[i] == '-'){ break; }
i++;
}

if((len-i) == 0 || (i-start) == 0){
throw new JSchException("invalid privatekey: "+prvkey);
}

// The content of 'buf' will be changed, so it should be copied.
byte[] tmp = new byte[i-start];
System.arraycopy(buf, start, tmp, 0, tmp.length);
byte[] _buf=tmp;

start = 0;
i = 0;

int _len = _buf.length;
while(i<_len){
if(_buf[i]==0x0a){
boolean xd=(_buf[i-1]==0x0d);
// ignore 0x0a (or 0x0d0x0a)
System.arraycopy(_buf, i+1, _buf, i-(xd ? 1 : 0), _len-(i+1));
if(xd)_len--;
_len--;
continue;
}
if(_buf[i]=='-'){ break; }
i++;
}
if(i-start > 0)
data=Util.fromBase64(_buf, start, i-start);

Util.bzero(_buf);
}
data=Util.fromBase64(buf, start, i-start);

if(data.length>4 && // FSecure
if(data!=null &&
data.length>4 && // FSecure
data[0]==(byte)0x3f &&
data[1]==(byte)0x6f &&
data[2]==(byte)0xf9 &&
@@ -598,18 +821,8 @@ public abstract class KeyPair{

if(pubkey!=null){
try{
file=new File(pubkey);
fis=new FileInputStream(pubkey);
buf=new byte[(int)(file.length())];
len=0;
while(true){
i=fis.read(buf, len, buf.length-len);
if(i<=0)
break;
len+=i;
}
fis.close();

buf=pubkey;
len=buf.length;
if(buf.length>4 && // FSecure's public key
buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){

@@ -634,7 +847,7 @@ public abstract class KeyPair{
}
if(buf.length<=i){valid=false;}

start=i;
int start=i;
while(valid && i<len){
if(buf[i]==0x0a){
System.arraycopy(buf, i+1, buf, i, len-i-1);
@@ -646,7 +859,7 @@ public abstract class KeyPair{
}
if(valid){
publickeyblob=Util.fromBase64(buf, start, i-start);
if(type==UNKNOWN){
if(prvkey==null || type==UNKNOWN){
if(publickeyblob[8]=='d'){ type=DSA; }
else if(publickeyblob[8]=='r'){ type=RSA; }
}
@@ -654,21 +867,47 @@ public abstract class KeyPair{
}
else{
if(buf[0]=='s'&& buf[1]=='s'&& buf[2]=='h' && buf[3]=='-'){
if(prvkey==null &&
buf.length>7){
if(buf[4]=='d'){ type=DSA; }
else if(buf[4]=='r'){ type=RSA; }
}
i=0;
while(i<len){ if(buf[i]==' ')break; i++;} i++;
if(i<len){
start=i;
int start=i;
while(i<len){ if(buf[i]==' ')break; i++;}
publickeyblob=Util.fromBase64(buf, start, i-start);
}
if(i++<len){
int s=i;
int start=i;
while(i<len){ if(buf[i]=='\n')break; i++;}
if(i<len){
publicKeyComment = new String(buf, s, i-s);
if(i>0 && buf[i-1]==0x0d) i--;
if(start<i){
publicKeyComment = new String(buf, start, i-start);
}
}
}
else if(buf[0]=='e'&& buf[1]=='c'&& buf[2]=='d' && buf[3]=='s'){
if(prvkey==null && buf.length>7){
type=ECDSA;
}
i=0;
while(i<len){ if(buf[i]==' ')break; i++;} i++;
if(i<len){
int start=i;
while(i<len){ if(buf[i]==' ')break; i++;}
publickeyblob=Util.fromBase64(buf, start, i-start);
}
if(i++<len){
int start=i;
while(i<len){ if(buf[i]=='\n')break; i++;}
if(i>0 && buf[i-1]==0x0d) i--;
if(start<i){
publicKeyComment = new String(buf, start, i-start);
}
}
}
}
}
catch(Exception ee){
@@ -685,6 +924,8 @@ public abstract class KeyPair{
KeyPair kpair=null;
if(type==DSA){ kpair=new KeyPairDSA(jsch); }
else if(type==RSA){ kpair=new KeyPairRSA(jsch); }
else if(type==ECDSA){ kpair=new KeyPairECDSA(jsch); }
else if(vendor==VENDOR_PKCS8){ kpair = new KeyPairPKCS8(jsch); }

if(kpair!=null){
kpair.encrypted=encrypted;
@@ -694,11 +935,13 @@ public abstract class KeyPair{
kpair.cipher=cipher;

if(encrypted){
kpair.encrypted=true;
kpair.iv=iv;
kpair.data=data;
}
else{
if(kpair.parse(data)){
kpair.encrypted=false;
return kpair;
}
else{
@@ -726,4 +969,287 @@ public abstract class KeyPair{
public void finalize (){
dispose();
}

private static final String[] header1 = {
"PuTTY-User-Key-File-2: ",
"Encryption: ",
"Comment: ",
"Public-Lines: "
};

private static final String[] header2 = {
"Private-Lines: "
};

private static final String[] header3 = {
"Private-MAC: "
};

static KeyPair loadPPK(JSch jsch, byte[] buf) throws JSchException {
byte[] pubkey = null;
byte[] prvkey = null;
int lines = 0;

Buffer buffer = new Buffer(buf);
java.util.Hashtable v = new java.util.Hashtable();

while(true){
if(!parseHeader(buffer, v))
break;
}

String typ = (String)v.get("PuTTY-User-Key-File-2");
if(typ == null){
return null;
}

lines = Integer.parseInt((String)v.get("Public-Lines"));
pubkey = parseLines(buffer, lines);

while(true){
if(!parseHeader(buffer, v))
break;
}
lines = Integer.parseInt((String)v.get("Private-Lines"));
prvkey = parseLines(buffer, lines);

while(true){
if(!parseHeader(buffer, v))
break;
}

prvkey = Util.fromBase64(prvkey, 0, prvkey.length);
pubkey = Util.fromBase64(pubkey, 0, pubkey.length);

KeyPair kpair = null;

if(typ.equals("ssh-rsa")) {

Buffer _buf = new Buffer(pubkey);
_buf.skip(pubkey.length);

int len = _buf.getInt();
_buf.getByte(new byte[len]); // ssh-rsa
byte[] pub_array = new byte[_buf.getInt()];
_buf.getByte(pub_array);
byte[] n_array = new byte[_buf.getInt()];
_buf.getByte(n_array);

kpair = new KeyPairRSA(jsch, n_array, pub_array, null);
}
else if(typ.equals("ssh-dss")){
Buffer _buf = new Buffer(pubkey);
_buf.skip(pubkey.length);

int len = _buf.getInt();
_buf.getByte(new byte[len]); // ssh-dss

byte[] p_array = new byte[_buf.getInt()];
_buf.getByte(p_array);
byte[] q_array = new byte[_buf.getInt()];
_buf.getByte(q_array);
byte[] g_array = new byte[_buf.getInt()];
_buf.getByte(g_array);
byte[] y_array = new byte[_buf.getInt()];
_buf.getByte(y_array);

kpair = new KeyPairDSA(jsch, p_array, q_array, g_array, y_array, null);
}
else {
return null;
}

if(kpair == null)
return null;

kpair.encrypted = !v.get("Encryption").equals("none");
kpair.vendor = VENDOR_PUTTY;
kpair.publicKeyComment = (String)v.get("Comment");
if(kpair.encrypted){
if(Session.checkCipher((String)jsch.getConfig("aes256-cbc"))){
try {
Class c=Class.forName((String)jsch.getConfig("aes256-cbc"));
kpair.cipher=(Cipher)(c.newInstance());
kpair.iv=new byte[kpair.cipher.getIVSize()];
}
catch(Exception e){
throw new JSchException("The cipher 'aes256-cbc' is required, but it is not available.");
}
}
else {
throw new JSchException("The cipher 'aes256-cbc' is required, but it is not available.");
}
kpair.data = prvkey;
}
else {
kpair.data = prvkey;
kpair.parse(prvkey);
}
return kpair;
}

private static byte[] parseLines(Buffer buffer, int lines){
byte[] buf = buffer.buffer;
int index = buffer.index;
byte[] data = null;

int i = index;
while(lines-->0){
while(buf.length > i){
if(buf[i++] == 0x0d){
if(data == null){
data = new byte[i - index - 1];
System.arraycopy(buf, index, data, 0, i - index - 1);
}
else {
byte[] tmp = new byte[data.length + i - index - 1];
System.arraycopy(data, 0, tmp, 0, data.length);
System.arraycopy(buf, index, tmp, data.length, i - index -1);
for(int j = 0; j < data.length; j++) data[j] = 0; // clear
data = tmp;
}
break;
}
}
if(buf[i]==0x0a)
i++;
index=i;
}

if(data != null)
buffer.index = index;

return data;
}

private static boolean parseHeader(Buffer buffer, java.util.Hashtable v){
byte[] buf = buffer.buffer;
int index = buffer.index;
String key = null;
String value = null;
for(int i = index; i < buf.length; i++){
if(buf[i] == 0x0d){
break;
}
if(buf[i] == ':'){
key = new String(buf, index, i - index);
i++;
if(i < buf.length && buf[i] == ' '){
i++;
}
index = i;
break;
}
}

if(key == null)
return false;

for(int i = index; i < buf.length; i++){
if(buf[i] == 0x0d){
value = new String(buf, index, i - index);
i++;
if(i < buf.length && buf[i] == 0x0a){
i++;
}
index = i;
break;
}
}

if(value != null){
v.put(key, value);
buffer.index = index;
}

return (key != null && value != null);
}

void copy(KeyPair kpair){
this.publickeyblob=kpair.publickeyblob;
this.vendor=kpair.vendor;
this.publicKeyComment=kpair.publicKeyComment;
this.cipher=kpair.cipher;
}

class ASN1Exception extends Exception {
}

class ASN1 {
byte[] buf;
int start;
int length;
ASN1(byte[] buf) throws ASN1Exception {
this(buf, 0, buf.length);
}
ASN1(byte[] buf, int start, int length) throws ASN1Exception {
this.buf = buf;
this.start = start;
this.length = length;
if(start+length>buf.length)
throw new ASN1Exception();
}
int getType() {
return buf[start]&0xff;
}
boolean isSEQUENCE() {
return getType()==(0x30&0xff);
}
boolean isINTEGER() {
return getType()==(0x02&0xff);
}
boolean isOBJECT() {
return getType()==(0x06&0xff);
}
boolean isOCTETSTRING() {
return getType()==(0x04&0xff);
}
private int getLength(int[] indexp) {
int index=indexp[0];
int length=buf[index++]&0xff;
if((length&0x80)!=0) {
int foo=length&0x7f; length=0;
while(foo-->0){ length=(length<<8)+(buf[index++]&0xff); }
}
indexp[0]=index;
return length;
}
byte[] getContent() {
int[] indexp=new int[1];
indexp[0]=start+1;
int length = getLength(indexp);
int index=indexp[0];
byte[] tmp = new byte[length];
System.arraycopy(buf, index, tmp, 0, tmp.length);
return tmp;
}
ASN1[] getContents() throws ASN1Exception {
int typ = buf[start];
int[] indexp=new int[1];
indexp[0]=start+1;
int length = getLength(indexp);
if(typ == 0x05){
return new ASN1[0];
}
int index=indexp[0];
java.util.Vector values = new java.util.Vector();
while(length>0) {
index++; length--;
int tmp=index;
indexp[0]=index;
int l=getLength(indexp);
index=indexp[0];
length-=(index-tmp);
values.addElement(new ASN1(buf, tmp-1, 1+(index-tmp)+l));
index+=l;
length-=l;
}
ASN1[] result = new ASN1[values.size()];
for(int i = 0; i <values.size(); i++) {
result[i]=(ASN1)values.elementAt(i);
}
return result;
}
}
}

+ 123
- 12
java/com/jcraft/jsch/KeyPairDSA.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -40,7 +40,23 @@ public class KeyPairDSA extends KeyPair{
private int key_size=1024;

public KeyPairDSA(JSch jsch){
this(jsch, null, null, null, null, null);
}

public KeyPairDSA(JSch jsch,
byte[] P_array,
byte[] Q_array,
byte[] G_array,
byte[] pub_array,
byte[] prv_array){
super(jsch);
this.P_array = P_array;
this.Q_array = Q_array;
this.G_array = G_array;
this.pub_array = pub_array;
this.prv_array = prv_array;
if(P_array!=null)
key_size = (new java.math.BigInteger(P_array)).bitLength();
}

void generate(int key_size) throws JSchException{
@@ -107,10 +123,26 @@ public class KeyPairDSA extends KeyPair{
Q_array=buf.getMPIntBits();
pub_array=buf.getMPIntBits();
prv_array=buf.getMPIntBits();
if(P_array!=null)
key_size = (new java.math.BigInteger(P_array)).bitLength();
return true;
}
return false;
}
else if(vendor==VENDOR_PUTTY){
Buffer buf=new Buffer(plain);
buf.skip(plain.length);

try {
byte[][] tmp = buf.getBytes(1, "");
prv_array = tmp[0];
}
catch(JSchException e){
return false;
}

return true;
}

int index=0;
int length=0;
@@ -181,6 +213,9 @@ public class KeyPairDSA extends KeyPair{
prv_array=new byte[length];
System.arraycopy(plain, index, prv_array, 0, length);
index+=length;

if(P_array!=null)
key_size = (new java.math.BigInteger(P_array)).bitLength();
}
catch(Exception e){
//System.err.println(e);
@@ -195,25 +230,101 @@ public class KeyPairDSA extends KeyPair{
if(foo!=null) return foo;

if(P_array==null) return null;
byte[][] tmp = new byte[5][];
tmp[0] = sshdss;
tmp[1] = P_array;
tmp[2] = Q_array;
tmp[3] = G_array;
tmp[4] = pub_array;
return Buffer.fromBytes(tmp).buffer;
}

private static final byte[] sshdss=Util.str2byte("ssh-dss");
byte[] getKeyTypeName(){return sshdss;}
public int getKeyType(){return DSA;}

public int getKeySize(){
return key_size;
}

public byte[] getSignature(byte[] data){
try{
Class c=Class.forName((String)jsch.getConfig("signature.dss"));
SignatureDSA dsa=(SignatureDSA)(c.newInstance());
dsa.init();
dsa.setPrvKey(prv_array, P_array, Q_array, G_array);

Buffer buf=new Buffer(sshdss.length+4+
P_array.length+4+
Q_array.length+4+
G_array.length+4+
pub_array.length+4);
dsa.update(data);
byte[] sig = dsa.sign();
byte[][] tmp = new byte[2][];
tmp[0] = sshdss;
tmp[1] = sig;
return Buffer.fromBytes(tmp).buffer;
}
catch(Exception e){
//System.err.println("e "+e);
}
return null;
}

public Signature getVerifier(){
try{
Class c=Class.forName((String)jsch.getConfig("signature.dss"));
SignatureDSA dsa=(SignatureDSA)(c.newInstance());
dsa.init();

if(pub_array == null && P_array == null && getPublicKeyBlob()!=null){
Buffer buf = new Buffer(getPublicKeyBlob());
buf.getString();
P_array = buf.getString();
Q_array = buf.getString();
G_array = buf.getString();
pub_array = buf.getString();
}

dsa.setPubKey(pub_array, P_array, Q_array, G_array);
return dsa;
}
catch(Exception e){
//System.err.println("e "+e);
}
return null;
}

static KeyPair fromSSHAgent(JSch jsch, Buffer buf) throws JSchException {

byte[][] tmp = buf.getBytes(7, "invalid key format");

byte[] P_array = tmp[1];
byte[] Q_array = tmp[2];
byte[] G_array = tmp[3];
byte[] pub_array = tmp[4];
byte[] prv_array = tmp[5];
KeyPairDSA kpair = new KeyPairDSA(jsch,
P_array, Q_array, G_array,
pub_array, prv_array);
kpair.publicKeyComment = new String(tmp[6]);
kpair.vendor=VENDOR_OPENSSH;
return kpair;
}

public byte[] forSSHAgent() throws JSchException {
if(isEncrypted()){
throw new JSchException("key is encrypted.");
}
Buffer buf = new Buffer();
buf.putString(sshdss);
buf.putString(P_array);
buf.putString(Q_array);
buf.putString(G_array);
buf.putString(pub_array);
return buf.buffer;
buf.putString(prv_array);
buf.putString(Util.str2byte(publicKeyComment));
byte[] result = new byte[buf.getLength()];
buf.getByte(result, 0, result.length);
return result;
}

private static final byte[] sshdss=Util.str2byte("ssh-dss");
byte[] getKeyTypeName(){return sshdss;}
public int getKeyType(){return DSA;}

public int getKeySize(){return key_size; }
public void dispose(){
super.dispose();
Util.bzero(prv_array);

+ 391
- 0
java/com/jcraft/jsch/KeyPairECDSA.java View File

@@ -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);
}
}

+ 1
- 1
java/com/jcraft/jsch/KeyPairGenDSA.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 37
- 0
java/com/jcraft/jsch/KeyPairGenECDSA.java View File

@@ -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();
}

+ 1
- 1
java/com/jcraft/jsch/KeyPairGenRSA.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 363
- 0
java/com/jcraft/jsch/KeyPairPKCS8.java View File

@@ -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;
}
}

+ 183
- 85
java/com/jcraft/jsch/KeyPairRSA.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,22 +29,36 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.jcraft.jsch;

import java.math.BigInteger;

public class KeyPairRSA extends KeyPair{
private byte[] prv_array;
private byte[] pub_array;
private byte[] n_array;
private byte[] n_array; // modulus p multiply q
private byte[] pub_array; // e
private byte[] prv_array; // d e^-1 mod (p-1)(q-1)

private byte[] p_array; // prime p
private byte[] q_array; // prime q
private byte[] ep_array; // prime exponent p
private byte[] eq_array; // prime exponent q
private byte[] c_array; // coefficient
private byte[] ep_array; // prime exponent p dmp1 == prv mod (p-1)
private byte[] eq_array; // prime exponent q dmq1 == prv mod (q-1)
private byte[] c_array; // coefficient iqmp == modinv(q, p) == q^-1 mod p

//private int key_size=0;
private int key_size=1024;

public KeyPairRSA(JSch jsch){
this(jsch, null, null, null);
}

public KeyPairRSA(JSch jsch,
byte[] n_array,
byte[] pub_array,
byte[] prv_array){
super(jsch);
this.n_array = n_array;
this.pub_array = pub_array;
this.prv_array = prv_array;
if(n_array!=null){
key_size = (new java.math.BigInteger(n_array)).bitLength();
}
}

void generate(int key_size) throws JSchException{
@@ -110,17 +124,32 @@ public class KeyPairRSA extends KeyPair{
}

boolean parse(byte [] plain){
/*
byte[] p_array;
byte[] q_array;
byte[] dmp1_array;
byte[] dmq1_array;
byte[] iqmp_array;
*/

try{
int index=0;
int length=0;

if(vendor==VENDOR_PUTTY){
Buffer buf = new Buffer(plain);
buf.skip(plain.length);

try {
byte[][] tmp = buf.getBytes(4, "");
prv_array = tmp[0];
p_array = tmp[1];
q_array = tmp[2];
c_array = tmp[3];
}
catch(JSchException e){
return false;
}

getEPArray();
getEQArray();

return true;
}

if(vendor==VENDOR_FSECURE){
if(plain[index]!=0x30){ // FSecure
Buffer buf=new Buffer(plain);
@@ -130,11 +159,35 @@ public class KeyPairRSA extends KeyPair{
byte[] u_array=buf.getMPIntBits();
p_array=buf.getMPIntBits();
q_array=buf.getMPIntBits();
if(n_array!=null){
key_size = (new java.math.BigInteger(n_array)).bitLength();
}

getEPArray();
getEQArray();
getCArray();

return true;
}
return false;
}

/*
Key must be in the following ASN.1 DER encoding,
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
*/

index++; // SEQUENCE
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -151,10 +204,6 @@ public class KeyPairRSA extends KeyPair{
}
index+=length;

//System.err.println("int: len="+length);
//System.err.print(Integer.toHexString(plain[index-1]&0xff)+":");
//System.err.println("");

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -164,13 +213,7 @@ public class KeyPairRSA extends KeyPair{
n_array=new byte[length];
System.arraycopy(plain, index, n_array, 0, length);
index+=length;
/*
System.err.println("int: N len="+length);
for(int i=0; i<n_array.length; i++){
System.err.print(Integer.toHexString(n_array[i]&0xff)+":");
}
System.err.println("");
*/

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -180,13 +223,7 @@ System.err.println("");
pub_array=new byte[length];
System.arraycopy(plain, index, pub_array, 0, length);
index+=length;
/*
System.err.println("int: E len="+length);
for(int i=0; i<pub_array.length; i++){
System.err.print(Integer.toHexString(pub_array[i]&0xff)+":");
}
System.err.println("");
*/

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -196,13 +233,6 @@ System.err.println("");
prv_array=new byte[length];
System.arraycopy(plain, index, prv_array, 0, length);
index+=length;
/*
System.err.println("int: prv len="+length);
for(int i=0; i<prv_array.length; i++){
System.err.print(Integer.toHexString(prv_array[i]&0xff)+":");
}
System.err.println("");
*/

index++;
length=plain[index++]&0xff;
@@ -213,13 +243,7 @@ System.err.println("");
p_array=new byte[length];
System.arraycopy(plain, index, p_array, 0, length);
index+=length;
/*
System.err.println("int: P len="+length);
for(int i=0; i<p_array.length; i++){
System.err.print(Integer.toHexString(p_array[i]&0xff)+":");
}
System.err.println("");
*/

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -229,13 +253,7 @@ System.err.println("");
q_array=new byte[length];
System.arraycopy(plain, index, q_array, 0, length);
index+=length;
/*
System.err.println("int: q len="+length);
for(int i=0; i<q_array.length; i++){
System.err.print(Integer.toHexString(q_array[i]&0xff)+":");
}
System.err.println("");
*/

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -245,13 +263,7 @@ System.err.println("");
ep_array=new byte[length];
System.arraycopy(plain, index, ep_array, 0, length);
index+=length;
/*
System.err.println("int: ep len="+length);
for(int i=0; i<ep_array.length; i++){
System.err.print(Integer.toHexString(ep_array[i]&0xff)+":");
}
System.err.println("");
*/

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -261,13 +273,7 @@ System.err.println("");
eq_array=new byte[length];
System.arraycopy(plain, index, eq_array, 0, length);
index+=length;
/*
System.err.println("int: eq len="+length);
for(int i=0; i<eq_array.length; i++){
System.err.print(Integer.toHexString(eq_array[i]&0xff)+":");
}
System.err.println("");
*/

index++;
length=plain[index++]&0xff;
if((length&0x80)!=0){
@@ -277,13 +283,11 @@ System.err.println("");
c_array=new byte[length];
System.arraycopy(plain, index, c_array, 0, length);
index+=length;
/*
System.err.println("int: c len="+length);
for(int i=0; i<c_array.length; i++){
System.err.print(Integer.toHexString(c_array[i]&0xff)+":");
}
System.err.println("");
*/

if(n_array!=null){
key_size = (new java.math.BigInteger(n_array)).bitLength();
}

}
catch(Exception e){
//System.err.println(e);
@@ -292,27 +296,121 @@ System.err.println("");
return true;
}


public byte[] getPublicKeyBlob(){
byte[] foo=super.getPublicKeyBlob();
if(foo!=null) return foo;

if(pub_array==null) return null;

Buffer buf=new Buffer(sshrsa.length+4+
pub_array.length+4+
n_array.length+4);
buf.putString(sshrsa);
buf.putString(pub_array);
buf.putString(n_array);
return buf.buffer;
byte[][] tmp = new byte[3][];
tmp[0] = sshrsa;
tmp[1] = pub_array;
tmp[2] = n_array;
return Buffer.fromBytes(tmp).buffer;
}

private static final byte[] sshrsa=Util.str2byte("ssh-rsa");
byte[] getKeyTypeName(){return sshrsa;}
public int getKeyType(){return RSA;}

public int getKeySize(){return key_size; }
public int getKeySize(){
return key_size;
}

public byte[] getSignature(byte[] data){
try{
Class c=Class.forName((String)jsch.getConfig("signature.rsa"));
SignatureRSA rsa=(SignatureRSA)(c.newInstance());
rsa.init();
rsa.setPrvKey(prv_array, n_array);

rsa.update(data);
byte[] sig = rsa.sign();
byte[][] tmp = new byte[2][];
tmp[0] = sshrsa;
tmp[1] = sig;
return Buffer.fromBytes(tmp).buffer;
}
catch(Exception e){
}
return null;
}

public Signature getVerifier(){
try{
Class c=Class.forName((String)jsch.getConfig("signature.rsa"));
SignatureRSA rsa=(SignatureRSA)(c.newInstance());
rsa.init();

if(pub_array == null && n_array == null && getPublicKeyBlob()!=null){
Buffer buf = new Buffer(getPublicKeyBlob());
buf.getString();
pub_array = buf.getString();
n_array = buf.getString();
}

rsa.setPubKey(pub_array, n_array);
return rsa;
}
catch(Exception e){
}
return null;
}

static KeyPair fromSSHAgent(JSch jsch, Buffer buf) throws JSchException {

byte[][] tmp = buf.getBytes(8, "invalid key format");

byte[] n_array = tmp[1];
byte[] pub_array = tmp[2];
byte[] prv_array = tmp[3];
KeyPairRSA kpair = new KeyPairRSA(jsch, n_array, pub_array, prv_array);
kpair.c_array = tmp[4]; // iqmp
kpair.p_array = tmp[5];
kpair.q_array = tmp[6];
kpair.publicKeyComment = new String(tmp[7]);
kpair.vendor=VENDOR_OPENSSH;
return kpair;
}

public byte[] forSSHAgent() throws JSchException {
if(isEncrypted()){
throw new JSchException("key is encrypted.");
}
Buffer buf = new Buffer();
buf.putString(sshrsa);
buf.putString(n_array);
buf.putString(pub_array);
buf.putString(prv_array);
buf.putString(getCArray());
buf.putString(p_array);
buf.putString(q_array);
buf.putString(Util.str2byte(publicKeyComment));
byte[] result = new byte[buf.getLength()];
buf.getByte(result, 0, result.length);
return result;
}

private byte[] getEPArray(){
if(ep_array==null){
ep_array=(new BigInteger(prv_array)).mod(new BigInteger(p_array).subtract(BigInteger.ONE)).toByteArray();
}
return ep_array;
}

private byte[] getEQArray(){
if(eq_array==null){
eq_array=(new BigInteger(prv_array)).mod(new BigInteger(q_array).subtract(BigInteger.ONE)).toByteArray();
}
return eq_array;
}

private byte[] getCArray(){
if(c_array==null){
c_array=(new BigInteger(q_array)).modInverse(new BigInteger(p_array)).toByteArray();
}
return c_array;
}

public void dispose(){
super.dispose();
Util.bzero(prv_array);

+ 127
- 46
java/com/jcraft/jsch/KnownHosts.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,17 +31,10 @@ package com.jcraft.jsch;

import java.io.*;

@SuppressWarnings({"rawtypes","unchecked","static"})
public
class KnownHosts implements HostKeyRepository{
private static final String _known_hosts="known_hosts";

/*
static final int SSHDSS=0;
static final int SSHRSA=1;
static final int UNKNOWN=2;
*/

private JSch jsch=null;
private String known_hosts=null;
private java.util.Vector pool=null;
@@ -54,23 +47,24 @@ class KnownHosts implements HostKeyRepository{
pool=new java.util.Vector();
}

void setKnownHosts(String foo) throws JSchException{
void setKnownHosts(String filename) throws JSchException{
try{
known_hosts=foo;
FileInputStream fis=new FileInputStream(foo);
known_hosts = filename;
FileInputStream fis=new FileInputStream(Util.checkTilde(filename));
setKnownHosts(fis);
}
catch(FileNotFoundException e){
throw new JSchException(e.toString(), (Throwable)e);
}
}
void setKnownHosts(InputStream foo) throws JSchException{
void setKnownHosts(InputStream input) throws JSchException{
pool.removeAllElements();
StringBuffer sb=new StringBuffer();
byte i;
int j;
boolean error=false;
try{
InputStream fis=foo;
InputStream fis=input;
String host;
String key=null;
int type;
@@ -123,6 +117,35 @@ loop:
continue loop;
}

while(j<bufl){
i=buf[j];
if(i==' '||i=='\t'){ j++; continue; }
break;
}

String marker="";
if(host.charAt(0) == '@'){
marker = host;

sb.setLength(0);
while(j<bufl){
i=buf[j++];
if(i==0x20 || i=='\t'){ break; }
sb.append((char)i);
}
host=sb.toString();
if(j>=bufl || host.length()==0){
addInvalidLine(Util.byte2str(buf, 0, bufl));
continue loop;
}

while(j<bufl){
i=buf[j];
if(i==' '||i=='\t'){ j++; continue; }
break;
}
}

sb.setLength(0);
type=-1;
while(j<bufl){
@@ -130,19 +153,28 @@ loop:
if(i==0x20 || i=='\t'){ break; }
sb.append((char)i);
}
if(sb.toString().equals("ssh-dss")){ type=HostKey.SSHDSS; }
else if(sb.toString().equals("ssh-rsa")){ type=HostKey.SSHRSA; }
String tmp = sb.toString();
if(HostKey.name2type(tmp)!=HostKey.UNKNOWN){
type=HostKey.name2type(tmp);
}
else { j=bufl; }
if(j>=bufl){
addInvalidLine(Util.byte2str(buf, 0, bufl));
continue loop;
}

while(j<bufl){
i=buf[j];
if(i==' '||i=='\t'){ j++; continue; }
break;
}

sb.setLength(0);
while(j<bufl){
i=buf[j++];
if(i==0x0d){ continue; }
if(i==0x0a){ break; }
if(i==0x20 || i=='\t'){ break; }
sb.append((char)i);
}
key=sb.toString();
@@ -151,16 +183,43 @@ loop:
continue loop;
}

while(j<bufl){
i=buf[j];
if(i==' '||i=='\t'){ j++; continue; }
break;
}

/**
"man sshd" has following descriptions,
Note that the lines in these files are typically hundreds
of characters long, and you definitely don't want to type
in the host keys by hand. Rather, generate them by a script,
ssh-keyscan(1) or by taking /usr/local/etc/ssh_host_key.pub and
adding the host names at the front.
This means that a comment is allowed to appear at the end of each
key entry.
*/
String comment=null;
if(j<bufl){
sb.setLength(0);
while(j<bufl){
i=buf[j++];
if(i==0x0d){ continue; }
if(i==0x0a){ break; }
sb.append((char)i);
}
comment=sb.toString();
}

//System.err.println(host);
//System.err.println("|"+key+"|");

HostKey hk = null;
hk = new HashedHostKey(host, type,
hk = new HashedHostKey(marker, host, type,
Util.fromBase64(Util.str2byte(key), 0,
key.length()));
key.length()), comment);
pool.addElement(hk);
}
fis.close();
if(error){
throw new JSchException("KnownHosts: invalid format");
}
@@ -172,6 +231,12 @@ loop:
throw new JSchException(e.toString(), (Throwable)e);
throw new JSchException(e.toString());
}
finally {
try{ input.close(); }
catch(IOException e){
throw new JSchException(e.toString(), (Throwable)e);
}
}
}
private void addInvalidLine(String line) throws JSchException {
HostKey hk = new HostKey(line, HostKey.UNKNOWN, null);
@@ -186,14 +251,19 @@ loop:
return result;
}

int type=getType(key);
HostKey hk;
HostKey hk = null;
try {
hk = new HostKey(host, HostKey.GUESS, key);
}
catch(JSchException e){ // unsupported key
return result;
}

synchronized(pool){
for(int i=0; i<pool.size(); i++){
hk=(HostKey)(pool.elementAt(i));
if(hk.isMatched(host) && hk.type==type){
if(Util.array_equals(hk.key, key)){
HostKey _hk=(HostKey)(pool.elementAt(i));
if(_hk.isMatched(host) && _hk.type==hk.type){
if(Util.array_equals(_hk.key, key)){
return OK;
}
else{
@@ -212,6 +282,7 @@ loop:

return result;
}

public void add(HostKey hostkey, UserInfo userinfo){
int type=hostkey.type;
String host=hostkey.getHost();
@@ -244,7 +315,7 @@ loop:
String bar=getKnownHostsRepositoryID();
if(bar!=null){
boolean foo=true;
File goo=new File(bar);
File goo=new File(Util.checkTilde(bar));
if(!goo.exists()){
foo=false;
if(userinfo!=null){
@@ -279,31 +350,33 @@ loop:
}

public HostKey[] getHostKey(){
return getHostKey(null, null);
return getHostKey(null, (String)null);
}
public HostKey[] getHostKey(String host, String type){
synchronized(pool){
int count=0;
java.util.ArrayList v = new java.util.ArrayList();
for(int i=0; i<pool.size(); i++){
HostKey hk=(HostKey)pool.elementAt(i);
if(hk.type==HostKey.UNKNOWN) continue;
if(host==null ||
(hk.isMatched(host) &&
(type==null || hk.getType().equals(type)))){
count++;
v.add(hk);
}
}
if(count==0)return null;
HostKey[] foo=new HostKey[count];
int j=0;
for(int i=0; i<pool.size(); i++){
HostKey hk=(HostKey)pool.elementAt(i);
if(hk.type==HostKey.UNKNOWN) continue;
if(host==null ||
(hk.isMatched(host) &&
(type==null || hk.getType().equals(type)))){
foo[j++]=hk;
}
HostKey[] foo = new HostKey[v.size()];
for(int i=0; i<v.size(); i++){
foo[i] = (HostKey)v.get(i);
}
if(host != null && host.startsWith("[") && host.indexOf("]:")>1){
HostKey[] tmp =
getHostKey(host.substring(1, host.indexOf("]:")), type);
if(tmp.length > 0){
HostKey[] bar = new HostKey[foo.length + tmp.length];
System.arraycopy(foo, 0, bar, 0, foo.length);
System.arraycopy(tmp, 0, bar, foo.length, tmp.length);
foo = bar;
}
}
return foo;
}
@@ -344,7 +417,7 @@ loop:
}
protected synchronized void sync(String foo) throws IOException {
if(foo==null) return;
FileOutputStream fos=new FileOutputStream(foo);
FileOutputStream fos=new FileOutputStream(Util.checkTilde(foo));
dump(fos);
fos.close();
}
@@ -358,18 +431,28 @@ loop:
for(int i=0; i<pool.size(); i++){
hk=(HostKey)(pool.elementAt(i));
//hk.dump(out);
String marker=hk.getMarker();
String host=hk.getHost();
String type=hk.getType();
String comment = hk.getComment();
if(type.equals("UNKNOWN")){
out.write(Util.str2byte(host));
out.write(cr);
continue;
}
if(marker.length()!=0){
out.write(Util.str2byte(marker));
out.write(space);
}
out.write(Util.str2byte(host));
out.write(space);
out.write(Util.str2byte(type));
out.write(space);
out.write(Util.str2byte(hk.getKey()));
if(comment!=null){
out.write(space);
out.write(Util.str2byte(comment));
}
out.write(cr);
}
}
@@ -378,11 +461,7 @@ loop:
System.err.println(e);
}
}
private int getType(byte[] key){
if(key[8]=='d') return HostKey.SSHDSS;
if(key[8]=='r') return HostKey.SSHRSA;
return HostKey.UNKNOWN;
}

private String deleteSubString(String hosts, String host){
int i=0;
int hostlen=host.length();
@@ -429,12 +508,14 @@ loop:
byte[] salt=null;
byte[] hash=null;


HashedHostKey(String host, byte[] key) throws JSchException {
this(host, GUESS, key);
}
HashedHostKey(String host, int type, byte[] key) throws JSchException {
super(host, type, key);
this("", host, type, key, null);
}
HashedHostKey(String marker, String host, int type, byte[] key, String comment) throws JSchException {
super(marker, host, type, key, comment);
if(this.host.startsWith(HASH_MAGIC) &&
this.host.substring(HASH_MAGIC.length()).indexOf(HASH_DELIM)>0){
String data=this.host.substring(HASH_MAGIC.length());

+ 1
- 1
java/com/jcraft/jsch/LICENSE.txt View File

@@ -2,7 +2,7 @@ JSch 0.0.* was released under the GNU LGPL license. Later, we have switched
over to a BSD-style license.

------------------------------------------------------------------------------
Copyright (c) 2002-2012 Atsuhiko Yamanaka, JCraft,Inc.
Copyright (c) 2002-2015 Atsuhiko Yamanaka, JCraft,Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without

+ 63
- 3
java/com/jcraft/jsch/LocalIdentityRepository.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2012-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,8 +31,8 @@ package com.jcraft.jsch;

import java.util.Vector;

@SuppressWarnings({"rawtypes","unchecked"})
class LocalIdentityRepository implements IdentityRepository {
private static final String name = "Local Identity Repository";

private Vector identities = new Vector();
private JSch jsch;
@@ -41,7 +41,16 @@ class LocalIdentityRepository implements IdentityRepository {
this.jsch = jsch;
}

public String getName(){
return name;
}

public int getStatus(){
return RUNNING;
}

public synchronized Vector getIdentities() {
removeDupulicates();
Vector v = new Vector();
for(int i=0; i<identities.size(); i++){
v.addElement(identities.elementAt(i));
@@ -51,6 +60,23 @@ class LocalIdentityRepository implements IdentityRepository {

public synchronized void add(Identity identity) {
if(!identities.contains(identity)) {
byte[] blob1 = identity.getPublicKeyBlob();
if(blob1 == null) {
identities.addElement(identity);
return;
}
for(int i = 0; i<identities.size(); i++){
byte[] blob2 = ((Identity)identities.elementAt(i)).getPublicKeyBlob();
if(blob2 != null && Util.array_equals(blob1, blob2)){
if(!identity.isEncrypted() &&
((Identity)identities.elementAt(i)).isEncrypted()){
remove(blob2);
}
else {
return;
}
}
}
identities.addElement(identity);
}
}
@@ -59,7 +85,7 @@ class LocalIdentityRepository implements IdentityRepository {
try{
Identity _identity =
IdentityFile.newInstance("from remote:", identity, null, jsch);
identities.addElement(_identity);
add(_identity);
return true;
}
catch(JSchException e){
@@ -67,6 +93,16 @@ class LocalIdentityRepository implements IdentityRepository {
}
}

synchronized void remove(Identity identity) {
if(identities.contains(identity)) {
identities.removeElement(identity);
identity.clear();
}
else {
remove(identity.getPublicKeyBlob());
}
}

public synchronized boolean remove(byte[] blob) {
if(blob == null) return false;
for(int i=0; i<identities.size(); i++) {
@@ -88,4 +124,28 @@ class LocalIdentityRepository implements IdentityRepository {
}
identities.removeAllElements();
}

private void removeDupulicates(){
Vector v = new Vector();
int len = identities.size();
if(len == 0) return;
for(int i=0; i<len; i++){
Identity foo = (Identity)identities.elementAt(i);
byte[] foo_blob = foo.getPublicKeyBlob();
if(foo_blob == null) continue;
for(int j=i+1; j<len; j++){
Identity bar = (Identity)identities.elementAt(j);
byte[] bar_blob = bar.getPublicKeyBlob();
if(bar_blob == null) continue;
if(Util.array_equals(foo_blob, bar_blob) &&
foo.isEncrypted() == bar.isEncrypted()){
v.addElement(foo_blob);
break;
}
}
}
for(int i=0; i<v.size(); i++){
remove((byte[])v.elementAt(i));
}
}
}

+ 1
- 1
java/com/jcraft/jsch/Logger.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/MAC.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 264
- 0
java/com/jcraft/jsch/OpenSSHConfig.java View File

@@ -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); }
}
}

+ 34
- 0
java/com/jcraft/jsch/PBKDF.java View File

@@ -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);
}

+ 1
- 1
java/com/jcraft/jsch/Packet.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 18
- 4
java/com/jcraft/jsch/PortWatcher.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -32,7 +32,6 @@ package com.jcraft.jsch;
import java.net.*;
import java.io.*;

@SuppressWarnings({"rawtypes","unchecked"})
class PortWatcher implements Runnable{
private static java.util.Vector pool=new java.util.Vector();
private static InetAddress anyLocalAddress=null;
@@ -55,6 +54,7 @@ class PortWatcher implements Runnable{
InetAddress boundaddress;
Runnable thread;
ServerSocket ss;
int connectTimeout=0;

static String[] getPortForwarding(Session session){
java.util.Vector foo=new java.util.Vector();
@@ -93,7 +93,17 @@ class PortWatcher implements Runnable{
return null;
}
}
private static String normalize(String address){
if(address!=null){
if(address.length()==0 || address.equals("*"))
address="0.0.0.0";
else if(address.equals("localhost"))
address="127.0.0.1";
}
return address;
}
static PortWatcher addPort(Session session, String address, int lport, String host, int rport, ServerSocketFactory ssf) throws JSchException{
address = normalize(address);
if(getPort(session, address, lport)!=null){
throw new JSchException("PortForwardingL: local port "+ address+":"+lport+" is already registered.");
}
@@ -102,6 +112,7 @@ class PortWatcher implements Runnable{
return pw;
}
static void delPort(Session session, String address, int lport) throws JSchException{
address = normalize(address);
PortWatcher pw=getPort(session, address, lport);
if(pw==null){
throw new JSchException("PortForwardingL: local port "+address+":"+lport+" is not registered.");
@@ -171,7 +182,7 @@ class PortWatcher implements Runnable{
((ChannelDirectTCPIP)channel).setPort(rport);
((ChannelDirectTCPIP)channel).setOrgIPAddress(socket.getInetAddress().getHostAddress());
((ChannelDirectTCPIP)channel).setOrgPort(socket.getPort());
channel.connect();
channel.connect(connectTimeout);
if(channel.exitstatus!=-1){
}
}
@@ -179,7 +190,6 @@ class PortWatcher implements Runnable{
catch(Exception e){
//System.err.println("! "+e);
}

delete();
}

@@ -192,4 +202,8 @@ class PortWatcher implements Runnable{
catch(Exception e){
}
}

void setConnectTimeout(int connectTimeout){
this.connectTimeout=connectTimeout;
}
}

+ 1
- 1
java/com/jcraft/jsch/Proxy.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/ProxyHTTP.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/ProxySOCKS4.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/ProxySOCKS5.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 12
- 4
java/com/jcraft/jsch/README View File

@@ -6,7 +6,7 @@

http://www.jcraft.com/jsch/

Last modified: Wed Nov 1 14:43:31 UTC 2006
Last modified: Thu Mar 18 13:58:16 UTC 2015


Description
@@ -50,14 +50,21 @@ Features
o J2SE 1.2.2 and later and Bouncycastle's JCE implementation that
can be obtained at http://www.bouncycastle.org/
* SSH2 protocol support.
* Key exchange: diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1
* Key exchange: diffie-hellman-group-exchange-sha1,
diffie-hellman-group1-sha1,
diffie-hellman-group14-sha1,
diffie-hellman-group-exchange-sha256,
ecdh-sha2-nistp256,
ecdh-sha2-nistp384,
ecdh-sha2-nistp521
* Cipher: blowfish-cbc,3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc
3des-ctr,aes128-ctr,aes192-ctr,aes256-ctc,
arcfour,arcfour128,arcfour256
* MAC: hmac-md5,hmac-md5-96,hmac-sha1,hmac-sha1-96
* Host key type: ssh-dss, ssh-rsa
* Host key type: ssh-dss,ssh-rsa,
ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
* Userauth: password
* Userauth: publickey(DSA,RSA)
* Userauth: publickey(DSA,RSA,ECDSA)
* Userauth: keyboard-interactive
* Userauth: gssapi-with-mic
* X11 forwarding.
@@ -72,6 +79,7 @@ Features
* envrironment variable passing.
* remote exec.
* generating DSA and RSA key pairs.
* supporting private keys in OpenSSL(traditional SSLeay) and PKCS#8 format.
* SSH File Transfer Protocol(version 0, 1, 2, 3)
* partial authentication
* packet compression: zlib, zlib@openssh.com

+ 1
- 1
java/com/jcraft/jsch/Random.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/Request.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestAgentForwarding.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestEnv.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestExec.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestPtyReq.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestSftp.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestShell.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestSignal.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestSubsystem.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2005-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestWindowChange.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/RequestX11.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/ServerSocketFactory.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 847
- 75
java/com/jcraft/jsch/Session.java
File diff suppressed because it is too large
View File


+ 40
- 9
java/com/jcraft/jsch/SftpATTRS.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -108,12 +108,12 @@ public class SftpATTRS {
}

public String getAtimeString(){
SimpleDateFormat locale=new SimpleDateFormat();
return (locale.format(new Date(atime)));
Date date= new Date(((long)atime)*1000L);
return (date.toString());
}

public String getMtimeString(){
Date date= new Date(((long)mtime)*1000);
Date date= new Date(((long)mtime)*1000L);
return (date.toString());
}

@@ -123,8 +123,14 @@ public class SftpATTRS {
public static final int SSH_FILEXFER_ATTR_ACMODTIME= 0x00000008;
public static final int SSH_FILEXFER_ATTR_EXTENDED= 0x80000000;

static final int S_IFMT=0xf000;
static final int S_IFIFO=0x1000;
static final int S_IFCHR=0x2000;
static final int S_IFDIR=0x4000;
static final int S_IFBLK=0x6000;
static final int S_IFREG=0x8000;
static final int S_IFLNK=0xa000;
static final int S_IFSOCK=0xc000;

int flags=0;
long size;
@@ -231,14 +237,39 @@ public class SftpATTRS {
this.permissions=permissions;
}

private boolean isType(int mask) {
return (flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 &&
(permissions&S_IFMT)==mask;
}

public boolean isReg(){
return isType(S_IFREG);
}

public boolean isDir(){
return ((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 &&
((permissions&S_IFDIR)==S_IFDIR));
return isType(S_IFDIR);
}
public boolean isLink(){
return ((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 &&
((permissions&S_IFLNK)==S_IFLNK));

public boolean isChr(){
return isType(S_IFCHR);
}

public boolean isBlk(){
return isType(S_IFBLK);
}

public boolean isFifo(){
return isType(S_IFIFO);
}

public boolean isLink(){
return isType(S_IFLNK);
}

public boolean isSock(){
return isType(S_IFSOCK);
}

public int getFlags() { return flags; }
public long getSize() { return size; }
public int getUId() { return uid; }

+ 1
- 1
java/com/jcraft/jsch/SftpException.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/SftpProgressMonitor.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 122
- 0
java/com/jcraft/jsch/SftpStatVFS.java View File

@@ -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 ""; }
}

+ 37
- 0
java/com/jcraft/jsch/Signature.java View File

@@ -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;
}

+ 2
- 6
java/com/jcraft/jsch/SignatureDSA.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,11 +29,7 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.jcraft.jsch;

public interface SignatureDSA{
void init() throws Exception;
public interface SignatureDSA extends Signature {
void setPubKey(byte[] y, byte[] p, byte[] q, byte[] g) throws Exception;
void setPrvKey(byte[] x, byte[] p, byte[] q, byte[] g) throws Exception;
void update(byte[] H) throws Exception;
boolean verify(byte[] sig) throws Exception;
byte[] sign() throws Exception;
}

+ 35
- 0
java/com/jcraft/jsch/SignatureECDSA.java View File

@@ -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;
}

+ 2
- 6
java/com/jcraft/jsch/SignatureRSA.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,11 +29,7 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.jcraft.jsch;

public interface SignatureRSA{
void init() throws Exception;
public interface SignatureRSA extends Signature {
void setPubKey(byte[] e, byte[] n) throws Exception;
void setPrvKey(byte[] d, byte[] n) throws Exception;
void update(byte[] H) throws Exception;
boolean verify(byte[] sig) throws Exception;
byte[] sign() throws Exception;
}

+ 1
- 1
java/com/jcraft/jsch/SocketFactory.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/UIKeyboardInteractive.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/UserAuth.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2006-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2006-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 2
- 2
java/com/jcraft/jsch/UserAuthKeyboardInteractive.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -128,7 +128,7 @@ class UserAuthKeyboardInteractive extends UserAuth{
if(password!=null &&
prompt.length==1 &&
!echo[0] &&
prompt[0].toLowerCase().startsWith("password:")){
prompt[0].toLowerCase().indexOf("password:") >= 0){
response=new byte[1][];
response[0]=password;
password=null;

+ 1
- 1
java/com/jcraft/jsch/UserAuthNone.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 1
- 1
java/com/jcraft/jsch/UserAuthPassword.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 19
- 14
java/com/jcraft/jsch/UserAuthPublicKey.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -31,13 +31,12 @@ package com.jcraft.jsch;

import java.util.Vector;

@SuppressWarnings({"rawtypes"})
class UserAuthPublicKey extends UserAuth{

public boolean start(Session session) throws Exception{
super.start(session);

Vector identities=session.jsch.getIdentityRepository().getIdentities();
Vector identities=session.getIdentityRepository().getIdentities();

byte[] passphrase=null;
byte[] _username=null;
@@ -60,8 +59,6 @@ class UserAuthPublicKey extends UserAuth{
Identity identity=(Identity)(identities.elementAt(i));
byte[] pubkeyblob=identity.getPublicKeyBlob();

//System.err.println("UserAuthPublicKey: "+identity+" "+pubkeyblob);

if(pubkeyblob!=null){
// send
// byte SSH_MSG_USERAUTH_REQUEST(50)
@@ -69,7 +66,8 @@ class UserAuthPublicKey extends UserAuth{
// string service name ("ssh-connection")
// string "publickey"
// boolen FALSE
// string plaintext password (ISO-10646 UTF-8)
// string public key algorithm name
// string public key blob
packet.reset();
buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
buf.putString(_username);
@@ -132,8 +130,13 @@ class UserAuthPublicKey extends UserAuth{
}

if(!identity.isEncrypted() || passphrase!=null){
if(identity.setPassphrase(passphrase))
if(identity.setPassphrase(passphrase)){
if(passphrase!=null &&
(session.getIdentityRepository() instanceof IdentityRepository.Wrapper)){
((IdentityRepository.Wrapper)session.getIdentityRepository()).check();
}
break;
}
}
Util.bzero(passphrase);
passphrase=null;
@@ -152,13 +155,15 @@ class UserAuthPublicKey extends UserAuth{

if(pubkeyblob==null) continue;

// send
// byte SSH_MSG_USERAUTH_REQUEST(50)
// string user name
// string service name ("ssh-connection")
// string "publickey"
// boolen TRUE
// string plaintext password (ISO-10646 UTF-8)
// send
// byte SSH_MSG_USERAUTH_REQUEST(50)
// string user name
// string service name ("ssh-connection")
// string "publickey"
// boolen TRUE
// string public key algorithm name
// string public key blob
// string signature
packet.reset();
buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
buf.putString(_username);

+ 1
- 1
java/com/jcraft/jsch/UserInfo.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

+ 67
- 16
java/com/jcraft/jsch/Util.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -29,8 +29,10 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.jcraft.jsch;
import java.net.Socket;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

@SuppressWarnings({"rawtypes","unchecked"})
class Util{

private static final byte[] b64 =Util.str2byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=");
@@ -41,20 +43,25 @@ class Util{
}
return 0;
}
static byte[] fromBase64(byte[] buf, int start, int length){
byte[] foo=new byte[length];
int j=0;
for (int i=start;i<start+length;i+=4){
foo[j]=(byte)((val(buf[i])<<2)|((val(buf[i+1])&0x30)>>>4));
if(buf[i+2]==(byte)'='){ j++; break;}
foo[j+1]=(byte)(((val(buf[i+1])&0x0f)<<4)|((val(buf[i+2])&0x3c)>>>2));
if(buf[i+3]==(byte)'='){ j+=2; break;}
foo[j+2]=(byte)(((val(buf[i+2])&0x03)<<6)|(val(buf[i+3])&0x3f));
j+=3;
static byte[] fromBase64(byte[] buf, int start, int length) throws JSchException {
try {
byte[] foo=new byte[length];
int j=0;
for (int i=start;i<start+length;i+=4){
foo[j]=(byte)((val(buf[i])<<2)|((val(buf[i+1])&0x30)>>>4));
if(buf[i+2]==(byte)'='){ j++; break;}
foo[j+1]=(byte)(((val(buf[i+1])&0x0f)<<4)|((val(buf[i+2])&0x3c)>>>2));
if(buf[i+3]==(byte)'='){ j+=2; break;}
foo[j+2]=(byte)(((val(buf[i+2])&0x03)<<6)|(val(buf[i+3])&0x3f));
j+=3;
}
byte[] bar=new byte[j];
System.arraycopy(foo, 0, bar, 0, j);
return bar;
}
catch(ArrayIndexOutOfBoundsException e) {
throw new JSchException("fromBase64: invalid base64 data", e);
}
byte[] bar=new byte[j];
System.arraycopy(foo, 0, bar, 0, j);
return bar;
}
static byte[] toBase64(byte[] buf, int start, int length){

@@ -384,7 +391,7 @@ class Util{
}
tmp.interrupt();
tmp=null;
throw new JSchException(message);
throw new JSchException(message, ee[0]);
}
return socket;
}
@@ -421,6 +428,17 @@ class Util{
return byte2str(str, s, l, "UTF-8");
}

static String toHex(byte[] str){
StringBuffer sb = new StringBuffer();
for(int i = 0; i<str.length; i++){
String foo = Integer.toHexString(str[i]&0xff);
sb.append("0x"+(foo.length() == 1 ? "0" : "")+foo);
if(i+1<str.length)
sb.append(":");
}
return sb.toString();
}

static final byte[] empty = str2byte("");

/*
@@ -466,10 +484,43 @@ class Util{
return result;
}

static String checkTilde(String str){
try{
if(str.startsWith("~")){
str = str.replace("~", System.getProperty("user.home"));
}
}
catch(SecurityException e){
}
return str;
}

private static int skipUTF8Char(byte b){
if((byte)(b&0x80)==0) return 1;
if((byte)(b&0xe0)==(byte)0xc0) return 2;
if((byte)(b&0xf0)==(byte)0xe0) return 3;
return 1;
}

static byte[] fromFile(String _file) throws IOException {
_file = checkTilde(_file);
File file = new File(_file);
FileInputStream fis = new FileInputStream(_file);
try {
byte[] result = new byte[(int)(file.length())];
int len=0;
while(true){
int i=fis.read(result, len, result.length-len);
if(i<=0)
break;
len+=i;
}
fis.close();
return result;
}
finally {
if(fis!=null)
fis.close();
}
}
}

+ 7
- 5
java/com/jcraft/jsch/jce/AES128CBC.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2005-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -55,10 +55,12 @@ public class AES128CBC implements Cipher{
try{
SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
cipher=javax.crypto.Cipher.getInstance("AES/CBC/"+pad);
cipher.init((mode==ENCRYPT_MODE?
javax.crypto.Cipher.ENCRYPT_MODE:
javax.crypto.Cipher.DECRYPT_MODE),
keyspec, new IvParameterSpec(iv));
synchronized(javax.crypto.Cipher.class){
cipher.init((mode==ENCRYPT_MODE?
javax.crypto.Cipher.ENCRYPT_MODE:
javax.crypto.Cipher.DECRYPT_MODE),
keyspec, new IvParameterSpec(iv));
}
}
catch(Exception e){
cipher=null;

+ 7
- 5
java/com/jcraft/jsch/jce/AES128CTR.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2008-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2008-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -55,10 +55,12 @@ public class AES128CTR implements Cipher{
try{
SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
cipher=javax.crypto.Cipher.getInstance("AES/CTR/"+pad);
cipher.init((mode==ENCRYPT_MODE?
javax.crypto.Cipher.ENCRYPT_MODE:
javax.crypto.Cipher.DECRYPT_MODE),
keyspec, new IvParameterSpec(iv));
synchronized(javax.crypto.Cipher.class){
cipher.init((mode==ENCRYPT_MODE?
javax.crypto.Cipher.ENCRYPT_MODE:
javax.crypto.Cipher.DECRYPT_MODE),
keyspec, new IvParameterSpec(iv));
}
}
catch(Exception e){
cipher=null;

+ 7
- 5
java/com/jcraft/jsch/jce/AES192CBC.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2005-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2005-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -54,10 +54,12 @@ public class AES192CBC implements Cipher{
try{
SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
cipher=javax.crypto.Cipher.getInstance("AES/CBC/"+pad);
cipher.init((mode==ENCRYPT_MODE?
javax.crypto.Cipher.ENCRYPT_MODE:
javax.crypto.Cipher.DECRYPT_MODE),
keyspec, new IvParameterSpec(iv));
synchronized(javax.crypto.Cipher.class){
cipher.init((mode==ENCRYPT_MODE?
javax.crypto.Cipher.ENCRYPT_MODE:
javax.crypto.Cipher.DECRYPT_MODE),
keyspec, new IvParameterSpec(iv));
}
}
catch(Exception e){
cipher=null;

+ 7
- 5
java/com/jcraft/jsch/jce/AES192CTR.java View File

@@ -1,6 +1,6 @@
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2008-2012 ymnk, JCraft,Inc. All rights reserved.
Copyright (c) 2008-2015 ymnk, JCraft,Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -54,10 +54,12 @@ public class AES192CTR implements Cipher{
try{
SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
cipher=javax.crypto.Cipher.getInstance("AES/CTR/"+pad);
cipher.init((mode==ENCRYPT_MODE?
javax.crypto.Cipher.ENCRYPT_MODE:
javax.crypto.Cipher.DECRYPT_MODE),
keyspec, new IvParameterSpec(iv));
synchronized(javax.crypto.Cipher.class){
cipher.init((mode==ENCRYPT_MODE?
javax.crypto.Cipher.ENCRYPT_MODE:
javax.crypto.Cipher.DECRYPT_MODE),
keyspec, new IvParameterSpec(iv));
}
}
catch(Exception e){
cipher=null;

+ 0
- 0
java/com/jcraft/jsch/jce/AES256CBC.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save