@@ -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 |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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" |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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); | |||
} |
@@ -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(); |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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; | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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); |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: |
@@ -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; } | |||
}; | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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; | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; } | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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; } | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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; } | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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; | |||
} | |||
} |
@@ -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"; | |||
} | |||
} |
@@ -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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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); |
@@ -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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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(); | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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; | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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; | |||
} | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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); |
@@ -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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: |
@@ -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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: |
@@ -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; | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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); |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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()); |
@@ -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 |
@@ -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,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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: |
@@ -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); } | |||
} | |||
} |
@@ -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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: |
@@ -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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions are met: |
@@ -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 ""; } | |||
} |
@@ -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; | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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; | |||
} |
@@ -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; | |||
} |
@@ -1,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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,6 +1,6 @@ | |||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |||
/* | |||
Copyright (c) 2002-2012 ymnk, JCraft,Inc. All rights reserved. | |||
Copyright (c) 2002-2015 ymnk, JCraft,Inc. 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(); | |||
} | |||
} | |||
} |
@@ -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; |
@@ -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; |
@@ -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; |
@@ -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; |