mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-08 16:18:05 +03:00
Compare commits
406 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ca2bbd633 | ||
|
|
256e65dea4 | ||
|
|
1feb7fe9a6 | ||
|
|
d95b4db930 | ||
|
|
677f482a69 | ||
|
|
179b30ef4e | ||
|
|
f59bbccc5f | ||
|
|
bf34072c3a | ||
|
|
771751ca4c | ||
|
|
968d4284a0 | ||
|
|
63927a3e2b | ||
|
|
ac262f8086 | ||
|
|
6e56cd9d0a | ||
|
|
2f6025d9ba | ||
|
|
275e98e55b | ||
|
|
655d070571 | ||
|
|
c9775ca2c7 | ||
|
|
a2fb4fbd98 | ||
|
|
6185ac4db8 | ||
|
|
e420593fa9 | ||
|
|
68b924863e | ||
|
|
613ace1864 | ||
|
|
78e0ecd264 | ||
|
|
64085e62f4 | ||
|
|
8c7d2fa8d0 | ||
|
|
766d292bad | ||
|
|
a40957fffc | ||
|
|
8ffd852e67 | ||
|
|
b90be512e7 | ||
|
|
c0d49cf6b3 | ||
|
|
1b5b2b25b7 | ||
|
|
1dad19ca6e | ||
|
|
90fa26925d | ||
|
|
9425300262 | ||
|
|
f2bfe9bfcf | ||
|
|
71498ad961 | ||
|
|
7b8b1cfdf5 | ||
|
|
3f29879eca | ||
|
|
79c1ae2bb0 | ||
|
|
819d411cf1 | ||
|
|
6579f6f710 | ||
|
|
cf5830eda5 | ||
|
|
36ad389ccf | ||
|
|
f63a88ec9f | ||
|
|
7379a89268 | ||
|
|
219901211e | ||
|
|
8c1329036a | ||
|
|
733c19350c | ||
|
|
e5ec84c06a | ||
|
|
ed0156c985 | ||
|
|
6321685881 | ||
|
|
f6b4d47945 | ||
|
|
d198ef121c | ||
|
|
7786468875 | ||
|
|
0847e8460a | ||
|
|
62b8726807 | ||
|
|
a6af27ae91 | ||
|
|
628cbf5eba | ||
|
|
e134e00574 | ||
|
|
1caa7ac722 | ||
|
|
4183776adb | ||
|
|
791f112752 | ||
|
|
233f3765c9 | ||
|
|
5f292d398f | ||
|
|
ba347f927d | ||
|
|
6f9ecf69e4 | ||
|
|
e78ae4dbeb | ||
|
|
618f2fd111 | ||
|
|
8503046302 | ||
|
|
c6cde27e4b | ||
|
|
113aa0aebd | ||
|
|
e7c50165c7 | ||
|
|
09616c4834 | ||
|
|
df710d8dc9 | ||
|
|
df82774ea3 | ||
|
|
caa6cca665 | ||
|
|
9a5ccefb5d | ||
|
|
90f8c592b0 | ||
|
|
f491e8d101 | ||
|
|
77c10334f1 | ||
|
|
0edc4a5787 | ||
|
|
b43cff07bf | ||
|
|
1ab72b7eaf | ||
|
|
3229584a95 | ||
|
|
364a82154d | ||
|
|
11fbf2964b | ||
|
|
a248d50301 | ||
|
|
fddc943565 | ||
|
|
ae834134d0 | ||
|
|
bc41908694 | ||
|
|
bf1a855647 | ||
|
|
cd3b0a5bd6 | ||
|
|
b01eccda4a | ||
|
|
4c9ebc306d | ||
|
|
c3f75cda19 | ||
|
|
1f0e2b1e69 | ||
|
|
8e55e50fd9 | ||
|
|
eb8b7b51ca | ||
|
|
a2cccd5cef | ||
|
|
50403483da | ||
|
|
3c230a0fc4 | ||
|
|
4f152749ce | ||
|
|
e0df6a5fb5 | ||
|
|
f36c011844 | ||
|
|
94113eb6f5 | ||
|
|
0532f27a78 | ||
|
|
bd67135ffa | ||
|
|
ca49ca324f | ||
|
|
ac2ffbc367 | ||
|
|
dbb0eb0238 | ||
|
|
347e6ad655 | ||
|
|
2622833831 | ||
|
|
c0487c9ee5 | ||
|
|
3372db75b5 | ||
|
|
db75bad25c | ||
|
|
a73776ad40 | ||
|
|
237c7d18b6 | ||
|
|
b7c8cda851 | ||
|
|
2b6fedc939 | ||
|
|
51e1ff24e4 | ||
|
|
05efcb4889 | ||
|
|
d456612d25 | ||
|
|
6feed72251 | ||
|
|
67e44241d0 | ||
|
|
a2a5923767 | ||
|
|
bdf9ab7452 | ||
|
|
afdfa91eb7 | ||
|
|
29a6cf6f79 | ||
|
|
eece80cf48 | ||
|
|
7973cb1ff6 | ||
|
|
75c0ae9a83 | ||
|
|
f2314e74ed | ||
|
|
e041e3e1e3 | ||
|
|
47df71c836 | ||
|
|
e24ed6ee7b | ||
|
|
10f8645ecd | ||
|
|
d520585a09 | ||
|
|
28a11b0b45 | ||
|
|
a335185827 | ||
|
|
74a4012023 | ||
|
|
c98ad22a7a | ||
|
|
1c749da957 | ||
|
|
5d81e87bce | ||
|
|
d18e9d9961 | ||
|
|
84990ada08 | ||
|
|
9c424f9431 | ||
|
|
dec00efcaa | ||
|
|
742553912c | ||
|
|
e81fdb8d8b | ||
|
|
782ff9b83e | ||
|
|
84d15f4cf5 | ||
|
|
1ebcbb07ba | ||
|
|
9982e5c30e | ||
|
|
3f340d6927 | ||
|
|
b8eec64a37 | ||
|
|
314d9d01cf | ||
|
|
c526f8e3de | ||
|
|
9529c30105 | ||
|
|
6a476858d1 | ||
|
|
6bfb268c11 | ||
|
|
e334525da5 | ||
|
|
8776500fa0 | ||
|
|
a747db88ed | ||
|
|
97065264de | ||
|
|
7c26ac669a | ||
|
|
1c5b462206 | ||
|
|
4cb9610cdd | ||
|
|
b9d0a03cb3 | ||
|
|
4adc83b9df | ||
|
|
14edb33fa9 | ||
|
|
8e74330b0b | ||
|
|
5217d34198 | ||
|
|
d3d019c1c2 | ||
|
|
49185b044d | ||
|
|
a18d623f44 | ||
|
|
6855873ffd | ||
|
|
2ca8d8b19e | ||
|
|
da32b145df | ||
|
|
8ea6bb4a66 | ||
|
|
6cf767528a | ||
|
|
b123a6ae30 | ||
|
|
4250c61e45 | ||
|
|
ace09fa8c8 | ||
|
|
8398b6e3c3 | ||
|
|
3c1e0c1629 | ||
|
|
e6c7c17664 | ||
|
|
1e061aef25 | ||
|
|
66b772bac1 | ||
|
|
fc535a5e76 | ||
|
|
c7373f05cc | ||
|
|
3ebd2eb363 | ||
|
|
8638091517 | ||
|
|
5fc08a3fc8 | ||
|
|
92df7c6924 | ||
|
|
8c0967ca93 | ||
|
|
cb5b7f0943 | ||
|
|
de2ede05e7 | ||
|
|
4a90f99c5f | ||
|
|
e348f698e6 | ||
|
|
d59efaa5f9 | ||
|
|
83c5f2f815 | ||
|
|
b17d3fe867 | ||
|
|
3cefda5bd3 | ||
|
|
18f364a283 | ||
|
|
d68032a9b8 | ||
|
|
c73ba8bfa7 | ||
|
|
7bbfd40627 | ||
|
|
7ae84be548 | ||
|
|
f2793d1acf | ||
|
|
bca5883422 | ||
|
|
3e54e2c955 | ||
|
|
a7802ddcde | ||
|
|
a7872b394b | ||
|
|
3ade3977ef | ||
|
|
efb2c547f9 | ||
|
|
703a0df09d | ||
|
|
73de5b7b08 | ||
|
|
665cbf078a | ||
|
|
b3ea908996 | ||
|
|
11da49a4e7 | ||
|
|
5b1f9f2a7d | ||
|
|
268de458e3 | ||
|
|
834f0f22cd | ||
|
|
1daf456cbe | ||
|
|
ea11d34ac8 | ||
|
|
e961dc1b27 | ||
|
|
25fbff245f | ||
|
|
333c23e167 | ||
|
|
cf32842d0d | ||
|
|
70720de71b | ||
|
|
44e1ce1358 | ||
|
|
921f41f9de | ||
|
|
34c4be848a | ||
|
|
d10e303b1a | ||
|
|
46791c87f5 | ||
|
|
af0d873e5b | ||
|
|
d37b54b1fd | ||
|
|
c4408ac6dd | ||
|
|
ebbf440304 | ||
|
|
ef5a54d33f | ||
|
|
66514836c8 | ||
|
|
e943d80049 | ||
|
|
81931f3b7a | ||
|
|
b8bfc19ecf | ||
|
|
0cb62c6d44 | ||
|
|
0ccc57b5af | ||
|
|
4806b1d6c7 | ||
|
|
ecc1d06dc2 | ||
|
|
d95586508d | ||
|
|
5ee2f0a417 | ||
|
|
2a7278d239 | ||
|
|
0875417dde | ||
|
|
0a3ad4f68f | ||
|
|
fe58ecdee5 | ||
|
|
264e10b40c | ||
|
|
a00015969b | ||
|
|
d6c22fef55 | ||
|
|
9886facf42 | ||
|
|
01be48508d | ||
|
|
bdc541c959 | ||
|
|
f2ebbe288f | ||
|
|
9297338195 | ||
|
|
a8d2ea2028 | ||
|
|
f34667521d | ||
|
|
77f5d7fdb8 | ||
|
|
08d0e59b6b | ||
|
|
5c540b6889 | ||
|
|
baa8c8e995 | ||
|
|
f354fd6661 | ||
|
|
93f1543af8 | ||
|
|
63424657da | ||
|
|
131e85c4d0 | ||
|
|
587684c6a8 | ||
|
|
66f67db21b | ||
|
|
3356f533d0 | ||
|
|
97535bbcae | ||
|
|
896b0ea288 | ||
|
|
60d54fa5de | ||
|
|
06e421e752 | ||
|
|
b5796f5e74 | ||
|
|
0f7355a277 | ||
|
|
466ff99e1c | ||
|
|
1f992c3fae | ||
|
|
df6019accc | ||
|
|
fdb891b842 | ||
|
|
5159a799df | ||
|
|
78e5a2e30e | ||
|
|
db22f08f97 | ||
|
|
c8cfc796af | ||
|
|
d9c0c6725c | ||
|
|
b2297c6b44 | ||
|
|
e10ad28f2f | ||
|
|
61fc00a90a | ||
|
|
c8ef7ff0ca | ||
|
|
e6c4f6ae69 | ||
|
|
3418df7a56 | ||
|
|
0ddd1f38c5 | ||
|
|
0ec6918d7a | ||
|
|
88a88c5dba | ||
|
|
6656214803 | ||
|
|
c781724028 | ||
|
|
eefaa26882 | ||
|
|
0d52441f01 | ||
|
|
9539ff6b7a | ||
|
|
1ced1d4fdc | ||
|
|
77924fd0be | ||
|
|
3f195649fa | ||
|
|
42a4358f5c | ||
|
|
61ce0f4868 | ||
|
|
777995af3b | ||
|
|
635cf88acd | ||
|
|
ce515fddcd | ||
|
|
9acff6202c | ||
|
|
cbd118e0b1 | ||
|
|
a8cf749d95 | ||
|
|
f3d4707ef0 | ||
|
|
4c5da634ad | ||
|
|
2fdafb76fd | ||
|
|
80b164a299 | ||
|
|
75418f33b7 | ||
|
|
732de2b605 | ||
|
|
4fb56b868f | ||
|
|
a877ec1448 | ||
|
|
b44631ea97 | ||
|
|
a50962ba2f | ||
|
|
e8215e4af2 | ||
|
|
3c2bda3196 | ||
|
|
b13e22084b | ||
|
|
e7ba0e1e26 | ||
|
|
f712720538 | ||
|
|
540708e540 | ||
|
|
e4d3a1f866 | ||
|
|
33969340e2 | ||
|
|
d65df3c9bc | ||
|
|
d2b9248535 | ||
|
|
431be8e7c7 | ||
|
|
885c602ab8 | ||
|
|
8262e8fc98 | ||
|
|
844c5d7f77 | ||
|
|
fb690c4fb0 | ||
|
|
ab04596a20 | ||
|
|
9ffdc35f93 | ||
|
|
93e23f4cfb | ||
|
|
504637099d | ||
|
|
cafd9217bf | ||
|
|
c627fabebd | ||
|
|
1c4781a65d | ||
|
|
aac7af2827 | ||
|
|
11c286b9b9 | ||
|
|
7fae513fd8 | ||
|
|
53ad9d2288 | ||
|
|
ee07072846 | ||
|
|
d38bbbcdf7 | ||
|
|
bc59c81dbc | ||
|
|
d70d37cf4e | ||
|
|
777d82912c | ||
|
|
f5db3e1563 | ||
|
|
7e524f5c6f | ||
|
|
dbb3f62e82 | ||
|
|
16a363fef6 | ||
|
|
9b0d39a798 | ||
|
|
81e36153d7 | ||
|
|
3026be282a | ||
|
|
8eedeb25fa | ||
|
|
de11880648 | ||
|
|
1ff4772f3f | ||
|
|
22a5ffe735 | ||
|
|
7a77f85ced | ||
|
|
0002fe8b40 | ||
|
|
3028e7f218 | ||
|
|
333e1cb7b8 | ||
|
|
945d430916 | ||
|
|
73b903784a | ||
|
|
7d53649a85 | ||
|
|
e193db9a14 | ||
|
|
a942edb911 | ||
|
|
137a7f5956 | ||
|
|
718ff503df | ||
|
|
d933b2538e | ||
|
|
ea6f9ceed2 | ||
|
|
07c61b14e8 | ||
|
|
4b175e6938 | ||
|
|
f7e47cffa0 | ||
|
|
42dddc7f7e | ||
|
|
f1b3dbb102 | ||
|
|
f83bf2cd3f | ||
|
|
be11cbb848 | ||
|
|
43b0599e1f | ||
|
|
b218186cae | ||
|
|
184236c3d5 | ||
|
|
cb1d773659 | ||
|
|
378665cb46 | ||
|
|
a5272dc413 | ||
|
|
60552fd001 | ||
|
|
ef082c668a | ||
|
|
e66386eb1c | ||
|
|
0937ec9800 | ||
|
|
4b2f42804e | ||
|
|
01765d24d2 | ||
|
|
1a2351c5ee | ||
|
|
1cec011401 | ||
|
|
52338c13cb | ||
|
|
09cf21f61a | ||
|
|
04c2e7b6b8 | ||
|
|
822f196dd8 | ||
|
|
a88a574b10 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.bat text eol=crlf
|
||||||
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# IntelliJ IDEA
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# Eclipe
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
# Output dirs
|
||||||
|
target/
|
||||||
|
build/
|
||||||
|
docs/
|
||||||
|
.gradle/
|
||||||
|
sshj.jar
|
||||||
|
|
||||||
|
# MacOS X
|
||||||
|
.DS_Store
|
||||||
5
.travis.yml
Normal file
5
.travis.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
language: java
|
||||||
|
sudo: false
|
||||||
|
jdk:
|
||||||
|
- oraclejdk7
|
||||||
|
- oraclejdk8
|
||||||
@@ -1,5 +1 @@
|
|||||||
Shikhar Bhushan <shikhar@schmizz.net>
|
git log --format='%aN <%aE>' | awk '{arr[$0]++} END{for (i in arr){print arr[i], i;}}' | sort -rn | cut -d\ -f2-
|
||||||
Cyril Ledru <cledru@keynectis.net>
|
|
||||||
Incendium <incendium@gmail.com>
|
|
||||||
Philip Langdale <philipl@cloudera.com>
|
|
||||||
Adar Dembo <adar@cloudera.com>
|
|
||||||
|
|||||||
13
LICENSE_HEADER
Normal file
13
LICENSE_HEADER
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright (C)2009 - SSHJ Contributors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
2
NOTICE
2
NOTICE
@@ -1,5 +1,5 @@
|
|||||||
sshj - SSHv2 library for Java
|
sshj - SSHv2 library for Java
|
||||||
Copyright 2010-2011 sshj contributors
|
Copyright 2010-2012 sshj contributors
|
||||||
|
|
||||||
This product includes code derived from software developed at
|
This product includes code derived from software developed at
|
||||||
The Apache Software Foundation (http://www.apache.org/):
|
The Apache Software Foundation (http://www.apache.org/):
|
||||||
|
|||||||
166
README.adoc
Normal file
166
README.adoc
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
= sshj - SSHv2 library for Java
|
||||||
|
Jeroen van Erp
|
||||||
|
:sshj_groupid: com.hierynomus
|
||||||
|
:sshj_version: 0.19.0
|
||||||
|
:source-highlighter: pygments
|
||||||
|
|
||||||
|
image:https://travis-ci.org/hierynomus/sshj.svg?branch=master[link="https://travis-ci.org/hierynomus/sshj"]
|
||||||
|
image:https://api.codacy.com/project/badge/Grade/14a0a316bb9149739b5ea26dbfa8da8a["Codacy code quality", link="https://www.codacy.com/app/jeroen_2/sshj?utm_source=github.com&utm_medium=referral&utm_content=hierynomus/sshj&utm_campaign=Badge_Grade"]
|
||||||
|
image:https://maven-badges.herokuapp.com/maven-central/com.hierynomus/sshj/badge.svg["Maven Central",link="https://maven-badges.herokuapp.com/maven-central/com.hierynomus/sshj"]
|
||||||
|
image:https://javadoc-emblem.rhcloud.com/doc/com.hierynomus/sshj/badge.svg["Javadoc",link="http://www.javadoc.io/doc/com.hierynomus/sshj"]
|
||||||
|
|
||||||
|
To get started, have a look at one of the examples. Hopefully you will find the API pleasant to work with :)
|
||||||
|
|
||||||
|
== Getting SSHJ
|
||||||
|
|
||||||
|
To get SSHJ, you have two options:
|
||||||
|
|
||||||
|
. Add a dependency to SSHJ to your project.
|
||||||
|
. Build SSHJ yourself.
|
||||||
|
|
||||||
|
And, if you want, you can also run the SSHJ examples.
|
||||||
|
|
||||||
|
Binary releases of SSHJ are not provided here, but you can download it http://search.maven.org/#artifactdetails%7C{sshj_groupid}%7Csshj%7C{sshj_version}%7Cjar[straight from the Maven Central repository] if you want to.
|
||||||
|
|
||||||
|
== Depending on SSHJ
|
||||||
|
If you're building your project using Maven, you can add the following dependency to the `pom.xml`:
|
||||||
|
|
||||||
|
[source,xml,subs="verbatim,attributes"]
|
||||||
|
----
|
||||||
|
<dependency>
|
||||||
|
<groupId>{sshj_groupid}</groupId>
|
||||||
|
<artifactId>sshj</artifactId>
|
||||||
|
<version>{sshj_version}</version>
|
||||||
|
</dependency>
|
||||||
|
----
|
||||||
|
|
||||||
|
If your project is built using another build tool that uses the Maven Central repository, translate this dependency into the format used by your build tool.
|
||||||
|
|
||||||
|
== Building SSHJ
|
||||||
|
. Clone the Overthere repository.
|
||||||
|
. Ensure you have Java6 installed with the http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html[Unlimited strength Java Cryptography Extensions (JCE)].
|
||||||
|
. Run the command `./gradlew clean build`.
|
||||||
|
|
||||||
|
== Running the examples
|
||||||
|
In the `examples` directory, there is a separate Maven project that shows how the library can be used in some sample cases. If you want to run them, follow these guidelines:
|
||||||
|
|
||||||
|
. Install http://maven.apache.org/[Maven 2.2.1] or up.
|
||||||
|
. Clone the Overthere repository.
|
||||||
|
. Go into the `examples` directory and run the command `mvn eclipse:eclipse`.
|
||||||
|
. Import the `examples` project into Eclipse.
|
||||||
|
. Change the login details in the example classes (address, username and password) and run them!
|
||||||
|
|
||||||
|
== Features of the library include:
|
||||||
|
|
||||||
|
* reading known_hosts files for host key verification
|
||||||
|
* publickey, password and keyboard-interactive authentication
|
||||||
|
* command, subsystem and shell channels
|
||||||
|
* local and remote port forwarding
|
||||||
|
* scp + complete sftp version 0-3 implementation
|
||||||
|
|
||||||
|
== Supported algorithms
|
||||||
|
Implementations / adapters for the following algorithms are included:
|
||||||
|
|
||||||
|
ciphers::
|
||||||
|
`aes{128,192,256}-{cbc,ctr}`, `blowfish-{cbc,ctr}`, `3des-{cbc,ctr}`, `twofish{128,192,256}-{cbc,ctr}`, `twofish-cbc`, `serpent{128,192,256}-{cbc,ctr}`, `idea-{cbc,ctr}`, `cast128-{cbc,ctr}`, `arcfour`, `arcfour{128,256}`
|
||||||
|
SSHJ also supports the following extended (non official) ciphers: `camellia{128,192,256}-{cbc,ctr}`, `camellia{128,192,256}-{cbc,ctr}@openssh.org`
|
||||||
|
|
||||||
|
key exchange::
|
||||||
|
`diffie-hellman-group1-sha1`, `diffie-hellman-group14-sha1`, `diffie-hellman-group-exchange-sha1`, `diffie-hellman-group-exchange-sha256`,
|
||||||
|
`ecdh-sha2-nistp256`, `ecdh-sha2-nistp384`, `ecdh-sha2-nistp521`, `curve25519-sha256@libssh.org`
|
||||||
|
|
||||||
|
signatures::
|
||||||
|
`ssh-rsa`, `ssh-dss`, `ecdsa-sha2-nistp256`, `ssh-ed25519`
|
||||||
|
|
||||||
|
mac::
|
||||||
|
`hmac-md5`, `hmac-md5-96`, `hmac-sha1`, `hmac-sha1-96`, `hmac-sha2-256`, `hmac-sha2-512`
|
||||||
|
|
||||||
|
compression::
|
||||||
|
`zlib` and `zlib@openssh.com` (delayed zlib)
|
||||||
|
|
||||||
|
private key files::
|
||||||
|
`pkcs8` encoded (what openssh uses)
|
||||||
|
|
||||||
|
If you need something that is not included, it shouldn't be too hard to add (do contribute it!)
|
||||||
|
|
||||||
|
== Comparing to other implementations
|
||||||
|
http://ssh-comparison.quendi.de/comparison.html[SSH Implementation Comparison]
|
||||||
|
|
||||||
|
== Dependencies
|
||||||
|
Java 6+. http://www.slf4j.org/download.html[slf4j] is required. http://www.bouncycastle.org/java.html[bouncycastle] is highly recommended and required for using some of the crypto algorithms. http://www.jcraft.com/jzlib/[jzlib] is required for using zlib compression.
|
||||||
|
|
||||||
|
== Reporting bugs
|
||||||
|
Issue tracker: https://github.com/hierynomus/sshj/issues
|
||||||
|
|
||||||
|
== Discussion
|
||||||
|
Google Group: http://groups.google.com/group/sshj-users
|
||||||
|
|
||||||
|
== Contributing
|
||||||
|
Fork away!
|
||||||
|
|
||||||
|
== Release history
|
||||||
|
SSHJ 0.19.0 (2016-11-25)::
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/276[#276]: Add support for ed-25519 and new OpenSSH key format
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/280[#280]: Read version from a generated sshj.properties file to correctly output version during negotiation
|
||||||
|
SSHJ 0.18.0 (2016-09-30)::
|
||||||
|
* Fixed Android compatibility
|
||||||
|
* Upgrade to Gradle 3.0
|
||||||
|
* Merged https://github.com/hierynomus/sshj/pulls/271[#271]: Load known_hosts without requiring BouncyCastle
|
||||||
|
* Merged https://github.com/hierynomus/sshj/pulls/269[#269]: Brought back Java6 support by popular demand
|
||||||
|
* Merged https://github.com/hierynomus/sshj/pulls/267[#267]: Added support for per connection logging (Fixes https://github.com/hierynomus/sshj/issues/264[#264])
|
||||||
|
* Merged https://github.com/hierynomus/sshj/pulls/262[#262], https://github.com/hierynomus/sshj/pulls/265[#265] and https://github.com/hierynomus/sshj/pulls/266[#266]: Added PKCS5 key file support
|
||||||
|
* Fixed toString of sftp FileAttributes (Fixes https://github.com/hierynomus/sshj/pulls/258[#258])
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/255[#255]: No longer depending on 'privately marked' classes in `net.i2p.crypto.eddsa.math` package, fixes OSGI dependencies
|
||||||
|
SSHJ 0.17.2 (2016-07-07)::
|
||||||
|
* Treating SSH Server identification line ending in '\n' instead of '\r\n' leniently.
|
||||||
|
SSHJ 0.17.1 (2016-07-06)::
|
||||||
|
* Improved parsing of the SSH Server identification. Too long header lines now no longer break the protocol.
|
||||||
|
SSHJ 0.17.0 (2016-07-05)::
|
||||||
|
* *Introduced breaking change in SFTP copy behaviour*: Previously an SFTP copy operation would behave differently if both source and target were folders with different names.
|
||||||
|
In this case instead of copying the contents of the source into the target directory, the directory itself was copied as a sub directory of the target directory.
|
||||||
|
This behaviour has been removed in favour of the default behaviour which is to copy the contents of the source into the target. Bringing the behaviour in line with how SCP works.
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/252[#252] (via: https://github.com/hierynomus/sshj/pulls/253[#253]): Same name subdirs are no longer merged by accident
|
||||||
|
SSHJ 0.16.0 (2016-04-11)::
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/239[#239]: Remote port forwards did not work if you used the empty string as address, or a catch-all address.
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/242[#242]: Added OSGI headers to sources jar manifest
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/236[#236]: Remote Port forwarding with dynamic port allocation fails with BufferUnderflowException
|
||||||
|
* Upgraded gradle distribution to 2.12
|
||||||
|
* Closed https://github.com/hierynomus/sshj/issues/234[#234]: Dropped Java6 support (0.15.0 was already Java6 incompatible due to Java7 dependency)
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/118[#118]: Added configuration switch for waiting on a server ident before sending the client ident.
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/114[#114]: Added javadoc that you always need to call close() on a Command before inspecting the exit codes.
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/237[#237]: Fixed race condition if a `hostkeys-00@openssh.com` global request is received directly after a successful auth.
|
||||||
|
SSHJ 0.15.0 (2015-11-20)::
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/220[#220]: Added support for `ssh-ed25519` host keys
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/225[#225]: Fixed bug in ECDSA fingerprint calculation that sometimes produced an incorrect fingerprint
|
||||||
|
* Added `arcfour` Stream Ciphers from RFC4253 and RFC4345
|
||||||
|
* Added all Block Ciphers from RFC4344 and RFC4253
|
||||||
|
SSHJ 0.14.0 (2015-11-04)::
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/171[#171]: Added support for `curve25519-sha256@libssh.org` key exchange algorithm
|
||||||
|
* Added support for `ecdh-sha2-nistp256`, `ecdh-sha2-nistp384` and `ecdh-sha2-nistp521` key exchange algorithms
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/167[#167]: Added support for `diffie-hellman-group-exchange-sha1` and `diffie-hellman-group-exchange-sha256` key exchange methods
|
||||||
|
* Fixed https://github.com/hierynomus/sshj/issues/212[#212]: Configure path escaping to enable shell expansion to work correctly
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/210[#210]: RemoteFileInputStream.skip returns wrong value (Fixes https://github.com/hierynomus/sshj/issues/209[#209])
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/208[#208]: Added SCP bandwidth limitation support
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/211[#211]: Made keyfile format detection more robust
|
||||||
|
SSHJ 0.13.0 (2015-08-18)::
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/199[#199]: Fix for IndexOutOfBoundsException in ReadAheadRemoteFileInputStream, fixes https://github.com/hierynomus/sshj/issues/183[#183]
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/195[#195]: New authentication supported: `gssapi-with-mic`
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/201[#201]: New option to verify negotiated key exchange algorithms
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/196[#196]: Fix for looking up complete hostname in known hosts file
|
||||||
|
SSHJ 0.12.0 (2015-04-14)::
|
||||||
|
* Added support for HTTP proxies when running JDK6 or JDK7, fixes: https://github.com/hierynomus/sshj/issues/170[#170]
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/186[#186]: Fix for detecting end-of-stream
|
||||||
|
* Compiling to JDK6, fixes https://github.com/hierynomus/sshj/issues/179[#179] and https://github.com/hierynomus/sshj/issues/185[#185]
|
||||||
|
* Correctly close socket and channel when LocalPortForwarder fails to open and start the channel (Fixes https://github.com/hierynomus/sshj/issues/175[#175] and https://github.com/hierynomus/sshj/issues/176[#176])
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/181[#181]: Invalid write packet length when reading with offset (Fixes https://github.com/hierynomus/sshj/issues/180[#180])
|
||||||
|
SSHJ 0.11.0 (2015-01-23)::
|
||||||
|
* New maven coordinates `com.hierynomus:sshj:0.11.0` as https://github.com/hierynomus[@hierynomus] took over as maintainer of SSHJ
|
||||||
|
* Migrated build system to Gradle 2.2.1
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/150[#150]: Fix for incorrect file handle on some SSH servers, fixes: https://github.com/hierynomus/sshj/issues/54[#54], https://github.com/hierynomus/sshj/issues/119[#119], https://github.com/hierynomus/sshj/issues/168[#168], https://github.com/hierynomus/sshj/issues/169[#169]
|
||||||
|
* Made `jzlib` optional in OSGi bundling, fixes: https://github.com/hierynomus/sshj/issues/162[#162]
|
||||||
|
* Improved some log levels, fixes: https://github.com/hierynomus/sshj/issues/161[#161]
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/156[#156], https://github.com/hierynomus/sshj/issues/164[#164], https://github.com/hierynomus/sshj/issues/165[#165]: Fixed block sizes for `hmac-sha2-256` and `hmac-sha2-512`
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/141[#141]: Add proxy support
|
||||||
|
* Merged https://github.com/hierynomus/sshj/issues/157[#157], https://github.com/hierynomus/sshj/issues/163[#163]: Doc and build fixes
|
||||||
|
* Upgraded BouncyCastle to 1.51, fixes: https://github.com/hierynomus/sshj/issues/142[#142]
|
||||||
|
* Implemented keep-alive with connection drop detection, fixes https://github.com/hierynomus/sshj/issues/166[#166]
|
||||||
58
README.rst
58
README.rst
@@ -1,58 +0,0 @@
|
|||||||
sshj - SSHv2 library for Java
|
|
||||||
==============================
|
|
||||||
|
|
||||||
To get started, have a look at one of the examples. Hopefully you will find the API pleasant to work with :)
|
|
||||||
|
|
||||||
Features of the library include:
|
|
||||||
|
|
||||||
* reading known_hosts files for host key verification
|
|
||||||
* publickey, password and keyboard-interactive authentication
|
|
||||||
* command, subsystem and shell channels
|
|
||||||
* local and remote port forwarding
|
|
||||||
* scp + complete sftp version 0-3 implementation
|
|
||||||
|
|
||||||
Implementations / adapters for the following algorithms are included:
|
|
||||||
|
|
||||||
ciphers
|
|
||||||
``aes{128,192,256}-{cbc,ctr}``, ``blowfish-cbc``, ``3des-cbc``
|
|
||||||
|
|
||||||
key exchange
|
|
||||||
``diffie-hellman-group1-sha1``, ``diffie-hellman-group14-sha1``
|
|
||||||
|
|
||||||
signatures
|
|
||||||
``ssh-rsa``, ``ssh-dss``
|
|
||||||
|
|
||||||
mac
|
|
||||||
``hmac-md5``, ``hmac-md5-96``, ``hmac-sha1``, ``hmac-sha1-96``
|
|
||||||
|
|
||||||
compression
|
|
||||||
``zlib`` and ``zlib@openssh.com`` (delayed zlib)
|
|
||||||
|
|
||||||
private key files
|
|
||||||
``pkcs8`` encoded (what openssh uses)
|
|
||||||
|
|
||||||
If you need something that is not included, it shouldn't be too hard to add (do contribute it!)
|
|
||||||
|
|
||||||
|
|
||||||
Dependencies
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Java 6+. slf4j_ is required. bouncycastle_ is highly recommended and required for using some of the crypto algorithms. jzlib_ is required for using zlib compression.
|
|
||||||
|
|
||||||
Bugs, questions
|
|
||||||
----------------
|
|
||||||
|
|
||||||
`Issue tracker <https://github.com/shikhar/sshj/issues>`_
|
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
------------
|
|
||||||
|
|
||||||
Fork away!
|
|
||||||
|
|
||||||
|
|
||||||
.. _slf4j: http://www.slf4j.org/download.html
|
|
||||||
|
|
||||||
.. _bouncycastle: http://www.bouncycastle.org/java.html
|
|
||||||
|
|
||||||
.. _jzlib: http://www.jcraft.com/jzlib/
|
|
||||||
177
build-publishing.gradle
Normal file
177
build-publishing.gradle
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "maven-publish"
|
||||||
|
apply plugin: "signing"
|
||||||
|
|
||||||
|
group = "nl.javadude"
|
||||||
|
version = "0.10.1-SNAPSHOT"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compile {
|
||||||
|
transitive = false
|
||||||
|
}
|
||||||
|
pom
|
||||||
|
}
|
||||||
|
|
||||||
|
def bouncycastleVersion = "1.50"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile "org.slf4j:slf4j-api:1.7.7"
|
||||||
|
compile "org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion"
|
||||||
|
compile "org.bouncycastle:bcpkix-jdk15on:$bouncycastleVersion"
|
||||||
|
compile "com.jcraft:jzlib:1.1.3"
|
||||||
|
|
||||||
|
testCompile "junit:junit:4.11"
|
||||||
|
testCompile "org.mockito:mockito-core:1.9.5"
|
||||||
|
testCompile "org.apache.sshd:sshd-core:0.11.0"
|
||||||
|
testRuntime "ch.qos.logback:logback-classic:1.1.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadocJar(type: Jar) {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
from javadoc
|
||||||
|
}
|
||||||
|
|
||||||
|
task sourcesJar(type: Jar) {
|
||||||
|
classifier = 'sources'
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
}
|
||||||
|
|
||||||
|
task generatePom(type: GenerateMavenPom) {
|
||||||
|
destination = file("$buildDir/generated-pom.xml")
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives javadocJar, sourcesJar
|
||||||
|
pom generatePom.destination
|
||||||
|
}
|
||||||
|
|
||||||
|
signing {
|
||||||
|
sign configurations.archives
|
||||||
|
}
|
||||||
|
|
||||||
|
task signPom(type: Sign) {
|
||||||
|
sign configurations.pom
|
||||||
|
}
|
||||||
|
|
||||||
|
def getSignatureFiles = {
|
||||||
|
def allFiles = project.tasks.signArchives.signatureFiles.collect { it }
|
||||||
|
def signedSources = allFiles.find { it.name.contains('-sources') }
|
||||||
|
def signedJavadoc = allFiles.find { it.name.contains('-javadoc') }
|
||||||
|
def signedJar = (allFiles - [signedSources, signedJavadoc])[0]
|
||||||
|
return [
|
||||||
|
[archive: signedSources, classifier: 'sources', extension: 'jar.asc'],
|
||||||
|
[archive: signedJavadoc, classifier: 'javadoc', extension: 'jar.asc'],
|
||||||
|
[archive: signedJar, classifier: null, extension: 'jar.asc']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def getPomSignature = {
|
||||||
|
return project.tasks.signPom.signatureFiles.collect{it}[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
gpgJars(MavenPublication) {
|
||||||
|
getSignatureFiles().each {signature ->
|
||||||
|
artifact (signature.archive) {
|
||||||
|
classifier = signature.classifier
|
||||||
|
extension = signature.extension
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gpgPom(MavenPublication) {
|
||||||
|
artifact(getPomSignature()) {
|
||||||
|
classifier = null
|
||||||
|
extension = "pom.asc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maven(MavenPublication) {
|
||||||
|
from components.java
|
||||||
|
artifact (javadocJar) {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
}
|
||||||
|
|
||||||
|
artifact (sourcesJar) {
|
||||||
|
classifier = 'sources'
|
||||||
|
}
|
||||||
|
|
||||||
|
pom.withXml {
|
||||||
|
asNode().children().last() + {
|
||||||
|
resolveStrategy = Closure.DELEGATE_FIRST
|
||||||
|
name "sshj"
|
||||||
|
description "SSHv2 library for Java"
|
||||||
|
url "https://github.com/hierynomus/sshj"
|
||||||
|
inceptionYear "2009"
|
||||||
|
|
||||||
|
issueManagement {
|
||||||
|
system "github"
|
||||||
|
url "https://github.com/hierynomus/sshj/issues"
|
||||||
|
}
|
||||||
|
|
||||||
|
scm {
|
||||||
|
connection "scm:git:git://github.com/hierynomus/sshj.git"
|
||||||
|
developerConnection "scm:git:git@github.com:hierynomus/sshj.git"
|
||||||
|
url "https://github.com/hierynomus/sshj.git"
|
||||||
|
}
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name "Apache 2"
|
||||||
|
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
distribution "repo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id "hierynomus"
|
||||||
|
name "Jeroen van Erp"
|
||||||
|
email "jeroen@javadude.nl"
|
||||||
|
roles {
|
||||||
|
role "Lead developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id "shikhar"
|
||||||
|
name "Shikhar Bhushan"
|
||||||
|
email "shikhar@schmizz.net"
|
||||||
|
url "http://schmizz.net"
|
||||||
|
roles {
|
||||||
|
role "Previous lead developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id "iterate"
|
||||||
|
name "David Kocher"
|
||||||
|
email "dkocher@iterate.ch"
|
||||||
|
organization "iterage GmbH"
|
||||||
|
organizationUrl "https://iterate.ch"
|
||||||
|
roles {
|
||||||
|
role "Developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url "file:/${project.projectDir}/artifacts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.afterEvaluate { p ->
|
||||||
|
p.tasks.publishGpgPomPublicationToMavenRepository.dependsOn("generatePom", "signPom")
|
||||||
|
}
|
||||||
|
|
||||||
|
generatePom.configure {
|
||||||
|
pom = publishing.publications.getByName("maven").pom
|
||||||
|
}
|
||||||
218
build.gradle
Normal file
218
build.gradle
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
import java.text.SimpleDateFormat
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id "java"
|
||||||
|
id "groovy"
|
||||||
|
id "osgi"
|
||||||
|
id "maven-publish"
|
||||||
|
id "org.ajoberstar.release-opinion" version "1.4.2"
|
||||||
|
id "com.github.hierynomus.license" version "0.12.1"
|
||||||
|
id "com.jfrog.bintray" version "1.7"
|
||||||
|
id 'ru.vyarus.pom' version '1.0.3'
|
||||||
|
id 'ru.vyarus.github-info' version '1.1.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.hierynomus"
|
||||||
|
defaultTasks "build"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceCompatibility = 1.6
|
||||||
|
targetCompatibility = 1.6
|
||||||
|
|
||||||
|
configurations.compile.transitive = false
|
||||||
|
|
||||||
|
def bouncycastleVersion = "1.51"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile "org.slf4j:slf4j-api:1.7.7"
|
||||||
|
compile "org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion"
|
||||||
|
compile "org.bouncycastle:bcpkix-jdk15on:$bouncycastleVersion"
|
||||||
|
compile "com.jcraft:jzlib:1.1.3"
|
||||||
|
|
||||||
|
compile "net.i2p.crypto:eddsa:0.1.0"
|
||||||
|
|
||||||
|
testCompile "junit:junit:4.11"
|
||||||
|
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
|
||||||
|
testCompile "org.mockito:mockito-core:1.9.5"
|
||||||
|
testCompile "org.apache.sshd:sshd-core:1.1.0"
|
||||||
|
testRuntime "ch.qos.logback:logback-classic:1.1.2"
|
||||||
|
testCompile 'org.glassfish.grizzly:grizzly-http-server:2.3.17'
|
||||||
|
testCompile 'org.apache.httpcomponents:httpclient:4.5.2'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
license {
|
||||||
|
header rootProject.file('LICENSE_HEADER')
|
||||||
|
strictCheck true
|
||||||
|
mapping {
|
||||||
|
java = 'SLASHSTAR_STYLE'
|
||||||
|
}
|
||||||
|
excludes(['**/djb/Curve25519.java', '**/sshj/common/Base64.java'])
|
||||||
|
}
|
||||||
|
|
||||||
|
release {
|
||||||
|
grgit = org.ajoberstar.grgit.Grgit.open(project.projectDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This disables the pedantic doclint feature of JDK8
|
||||||
|
if (JavaVersion.current().isJava8Compatible()) {
|
||||||
|
tasks.withType(Javadoc) {
|
||||||
|
options.addStringOption('Xdoclint:none', '-quiet')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task writeSshjVersionProperties << {
|
||||||
|
project.file("${project.buildDir}/resources/main").mkdirs()
|
||||||
|
project.file("${project.buildDir}/resources/main/sshj.properties").withWriter { w ->
|
||||||
|
w.append("sshj.version=${version}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jar.dependsOn writeSshjVersionProperties
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
instruction "Bundle-Description", "SSHv2 library for Java"
|
||||||
|
instruction "Bundle-License", "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
instruction "Import-Package", "!net.schmizz.*"
|
||||||
|
instruction "Import-Package", "javax.crypto*"
|
||||||
|
instruction "Import-Package", "net.i2p*"
|
||||||
|
instruction "Import-Package", "com.jcraft.jzlib*;version=\"[1.1,2)\";resolution:=optional"
|
||||||
|
instruction "Import-Package", "org.slf4j*;version=\"[1.7,5)\""
|
||||||
|
instruction "Import-Package", "org.bouncycastle*"
|
||||||
|
instruction "Import-Package", "*"
|
||||||
|
instruction "Export-Package", "net.schmizz.*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadocJar(type: Jar) {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
from javadoc
|
||||||
|
}
|
||||||
|
|
||||||
|
task sourcesJar(type: Jar) {
|
||||||
|
classifier = 'sources'
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
manifest {
|
||||||
|
attributes(
|
||||||
|
// Add the needed OSGI attributes
|
||||||
|
"Bundle-ManifestVersion": "2",
|
||||||
|
"Bundle-Name": "${project.jar.manifest.name} Source",
|
||||||
|
"Bundle-Version": project.jar.manifest.version,
|
||||||
|
"Eclipse-SourceBundle": "${project.jar.manifest.symbolicName};version=\"${project.jar.manifest.version}\";roots:=\".\"",
|
||||||
|
"Bundle-SymbolicName": "${project.jar.manifest.symbolicName}.source"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
testLogging {
|
||||||
|
exceptionFormat = 'full'
|
||||||
|
}
|
||||||
|
include "**/*Test.*"
|
||||||
|
include "**/*Spec.*"
|
||||||
|
if (!project.hasProperty("allTests")) {
|
||||||
|
useJUnit {
|
||||||
|
excludeCategories 'com.hierynomus.sshj.test.SlowTests'
|
||||||
|
excludeCategories 'com.hierynomus.sshj.test.KnownFailingTests'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
afterSuite { descriptor, result ->
|
||||||
|
if (descriptor.className != null) {
|
||||||
|
def indicator = "\u001B[32m✓\u001b[0m"
|
||||||
|
if (result.failedTestCount > 0) {
|
||||||
|
indicator = "\u001B[31m✘\u001b[0m"
|
||||||
|
}
|
||||||
|
logger.lifecycle("$indicator Test ${descriptor.name}; Executed: ${result.testCount}/\u001B[32m${result.successfulTestCount}\u001B[0m/\u001B[31m${result.failedTestCount}\u001B[0m")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.tasks.compileGroovy.onlyIf { false }
|
||||||
|
|
||||||
|
github {
|
||||||
|
user 'hierynomus'
|
||||||
|
license 'Apache'
|
||||||
|
}
|
||||||
|
|
||||||
|
pom {
|
||||||
|
description "SSHv2 library for Java"
|
||||||
|
url "https://github.com/hierynomus/sshj"
|
||||||
|
inceptionYear "2009"
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id "hierynomus"
|
||||||
|
name "Jeroen van Erp"
|
||||||
|
email "jeroen@javadude.nl"
|
||||||
|
roles {
|
||||||
|
role "Lead developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id "shikhar"
|
||||||
|
name "Shikhar Bhushan"
|
||||||
|
email "shikhar@schmizz.net"
|
||||||
|
url "http://schmizz.net"
|
||||||
|
roles {
|
||||||
|
role "Previous lead developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id "iterate"
|
||||||
|
name "David Kocher"
|
||||||
|
email "dkocher@iterate.ch"
|
||||||
|
organization "iterage GmbH"
|
||||||
|
organizationUrl "https://iterate.ch"
|
||||||
|
roles {
|
||||||
|
role "Developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing.publications {
|
||||||
|
Sshj(MavenPublication) {
|
||||||
|
from components.java
|
||||||
|
artifact sourcesJar
|
||||||
|
artifact javadocJar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (project.hasProperty("bintrayUsername") && project.hasProperty("bintrayApiKey")) {
|
||||||
|
bintray {
|
||||||
|
user = project.property("bintrayUsername")
|
||||||
|
key = project.property("bintrayApiKey")
|
||||||
|
publish = true
|
||||||
|
publications = ["Sshj"]
|
||||||
|
pkg {
|
||||||
|
repo = "maven"
|
||||||
|
name = project.name
|
||||||
|
licenses = ["Apache-2.0"]
|
||||||
|
vcsUrl = "https://github.com/hierynomus/sshj.git"
|
||||||
|
labels = ["ssh", "sftp", "secure-shell", "network", "file-transfer"]
|
||||||
|
githubRepo = "hierynomus/sshj"
|
||||||
|
version {
|
||||||
|
name = project.version.toString()
|
||||||
|
vcsTag = "v${project.version}"
|
||||||
|
released = new SimpleDateFormat('yyyy-MM-dd\'T\'HH:mm:ss.SSSZZ').format(new Date())
|
||||||
|
gpg {
|
||||||
|
sign = true
|
||||||
|
passphrase = project.property("signing.password")
|
||||||
|
}
|
||||||
|
mavenCentralSync {
|
||||||
|
sync = true
|
||||||
|
user = project.property("sonatypeUsername")
|
||||||
|
password = project.property("sonatypePassword")
|
||||||
|
close = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.tasks.release.dependsOn([project.tasks.build, project.tasks.bintrayUpload])
|
||||||
101
examples/pom.xml
Normal file
101
examples/pom.xml
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright 2009 sshj contributors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.hierynomus</groupId>
|
||||||
|
<artifactId>sshj-examples</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>0.19.0</version>
|
||||||
|
|
||||||
|
<name>sshj-examples</name>
|
||||||
|
<description>Examples for SSHv2 library for Java</description>
|
||||||
|
<url>http://github.com/hierynomus/sshj</url>
|
||||||
|
|
||||||
|
<inceptionYear>2015</inceptionYear>
|
||||||
|
|
||||||
|
<issueManagement>
|
||||||
|
<system>github</system>
|
||||||
|
<url>http://github.com/hierynomus/sshj/issues</url>
|
||||||
|
</issueManagement>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<connection>scm:git:git://github.com/hierynomus/sshj.git</connection>
|
||||||
|
<developerConnection>scm:git:git@github.com:hierynomus/sshj.git</developerConnection>
|
||||||
|
<url>http://github.com/hierynomus/sshj</url>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>Apache 2</name>
|
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hierynomus</groupId>
|
||||||
|
<artifactId>sshj</artifactId>
|
||||||
|
<version>0.18.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>hierynomus</id>
|
||||||
|
<name>Jeroen van Erp</name>
|
||||||
|
<email>jeroen@hierynomus.com</email>
|
||||||
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<id>shikhar</id>
|
||||||
|
<name>Shikhar Bhushan</name>
|
||||||
|
<email>shikhar@schmizz.net</email>
|
||||||
|
<url>http://schmizz.net</url>
|
||||||
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<id>iterate</id>
|
||||||
|
<name>David Kocher</name>
|
||||||
|
<email>dkocher@iterate.ch</email>
|
||||||
|
<organization>iterate GmbH</organization>
|
||||||
|
<organizationUrl>https://iterate.ch</organizationUrl>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.1</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
/*
|
package net.schmizz.sshj.examples;
|
||||||
* Copyright 2010, 2011 sshj contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package examples;
|
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package net.schmizz.sshj.examples;
|
||||||
|
|
||||||
|
import net.schmizz.keepalive.KeepAliveProvider;
|
||||||
|
import net.schmizz.sshj.DefaultConfig;
|
||||||
|
import net.schmizz.sshj.SSHClient;
|
||||||
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
|
import net.schmizz.sshj.connection.channel.direct.Session;
|
||||||
|
import net.schmizz.sshj.connection.channel.direct.Session.Command;
|
||||||
|
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/** This examples demonstrates how to setup keep-alive to detect connection dropping. */
|
||||||
|
public class KeepAlive {
|
||||||
|
|
||||||
|
public static void main(String... args)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
DefaultConfig defaultConfig = new DefaultConfig();
|
||||||
|
defaultConfig.setKeepAliveProvider(KeepAliveProvider.KEEP_ALIVE);
|
||||||
|
final SSHClient ssh = new SSHClient(defaultConfig);
|
||||||
|
try {
|
||||||
|
ssh.addHostKeyVerifier(new PromiscuousVerifier());
|
||||||
|
ssh.connect(args[0]);
|
||||||
|
ssh.getConnection().getKeepAlive().setKeepAliveInterval(5); //every 60sec
|
||||||
|
ssh.authPassword(args[1], args[2]);
|
||||||
|
Session session = ssh.startSession();
|
||||||
|
session.allocateDefaultPTY();
|
||||||
|
new CountDownLatch(1).await();
|
||||||
|
try {
|
||||||
|
session.allocateDefaultPTY();
|
||||||
|
} finally {
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
ssh.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +1,11 @@
|
|||||||
/*
|
package net.schmizz.sshj.examples;
|
||||||
* Copyright 2010, 2011 sshj contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package examples;
|
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
|
import net.schmizz.sshj.connection.channel.direct.LocalPortForwarder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This example demonstrates local port forwarding, i.e. when we listen on a particular address and port; and forward
|
* This example demonstrates local port forwarding, i.e. when we listen on a particular address and port; and forward
|
||||||
@@ -41,8 +28,16 @@ public class LocalPF {
|
|||||||
* _We_ listen on localhost:8080 and forward all connections on to server, which then forwards it to
|
* _We_ listen on localhost:8080 and forward all connections on to server, which then forwards it to
|
||||||
* google.com:80
|
* google.com:80
|
||||||
*/
|
*/
|
||||||
ssh.newLocalPortForwarder(new InetSocketAddress("localhost", 8080), "google.com", 80)
|
final LocalPortForwarder.Parameters params
|
||||||
.listen();
|
= new LocalPortForwarder.Parameters("0.0.0.0", 8080, "google.com", 80);
|
||||||
|
final ServerSocket ss = new ServerSocket();
|
||||||
|
ss.setReuseAddress(true);
|
||||||
|
ss.bind(new InetSocketAddress(params.getLocalHost(), params.getLocalPort()));
|
||||||
|
try {
|
||||||
|
ssh.newLocalPortForwarder(params, ss).listen();
|
||||||
|
} finally {
|
||||||
|
ss.close();
|
||||||
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
ssh.disconnect();
|
ssh.disconnect();
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
/*
|
package net.schmizz.sshj.examples;
|
||||||
* Copyright 2010, 2011 sshj contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package examples;
|
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder.Forward;
|
import net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder.Forward;
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
/*
|
package net.schmizz.sshj.examples;
|
||||||
* Copyright 2010, 2011 sshj contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package examples;
|
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.common.StreamCopier;
|
import net.schmizz.sshj.common.StreamCopier;
|
||||||
@@ -24,6 +9,7 @@ import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
|
|
||||||
/** A very rudimentary psuedo-terminal based on console I/O. */
|
/** A very rudimentary psuedo-terminal based on console I/O. */
|
||||||
class RudimentaryPTY {
|
class RudimentaryPTY {
|
||||||
@@ -48,18 +34,18 @@ class RudimentaryPTY {
|
|||||||
|
|
||||||
final Shell shell = session.startShell();
|
final Shell shell = session.startShell();
|
||||||
|
|
||||||
new StreamCopier(shell.getInputStream(), System.out)
|
new StreamCopier(shell.getInputStream(), System.out, LoggerFactory.DEFAULT)
|
||||||
.bufSize(shell.getLocalMaxPacketSize())
|
.bufSize(shell.getLocalMaxPacketSize())
|
||||||
.spawn("stdout");
|
.spawn("stdout");
|
||||||
|
|
||||||
new StreamCopier(shell.getErrorStream(), System.err)
|
new StreamCopier(shell.getErrorStream(), System.err, LoggerFactory.DEFAULT)
|
||||||
.bufSize(shell.getLocalMaxPacketSize())
|
.bufSize(shell.getLocalMaxPacketSize())
|
||||||
.spawn("stderr");
|
.spawn("stderr");
|
||||||
|
|
||||||
// Now make System.in act as stdin. To exit, hit Ctrl+D (since that results in an EOF on System.in)
|
// Now make System.in act as stdin. To exit, hit Ctrl+D (since that results in an EOF on System.in)
|
||||||
// This is kinda messy because java only allows console input after you hit return
|
// This is kinda messy because java only allows console input after you hit return
|
||||||
// But this is just an example... a GUI app could implement a proper PTY
|
// But this is just an example... a GUI app could implement a proper PTY
|
||||||
new StreamCopier(System.in, shell.getOutputStream())
|
new StreamCopier(System.in, shell.getOutputStream(), LoggerFactory.DEFAULT)
|
||||||
.bufSize(shell.getRemoteMaxPacketSize())
|
.bufSize(shell.getRemoteMaxPacketSize())
|
||||||
.copy();
|
.copy();
|
||||||
|
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
/*
|
package net.schmizz.sshj.examples;
|
||||||
* Copyright 2010, 2011 sshj contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package examples;
|
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.xfer.FileSystemFile;
|
import net.schmizz.sshj.xfer.FileSystemFile;
|
||||||
@@ -37,4 +22,4 @@ public class SCPDownload {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
/*
|
package net.schmizz.sshj.examples;
|
||||||
* Copyright 2010, 2011 sshj contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package examples;
|
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.xfer.FileSystemFile;
|
import net.schmizz.sshj.xfer.FileSystemFile;
|
||||||
@@ -42,4 +27,4 @@ public class SCPUpload {
|
|||||||
ssh.disconnect();
|
ssh.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
/*
|
package net.schmizz.sshj.examples;
|
||||||
* Copyright 2010, 2011 sshj contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package examples;
|
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.sftp.SFTPClient;
|
import net.schmizz.sshj.sftp.SFTPClient;
|
||||||
@@ -42,4 +27,4 @@ public class SFTPDownload {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
/*
|
package net.schmizz.sshj.examples;
|
||||||
* Copyright 2010, 2011 sshj contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package examples;
|
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.sftp.SFTPClient;
|
import net.schmizz.sshj.sftp.SFTPClient;
|
||||||
@@ -44,4 +29,4 @@ public class SFTPUpload {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,11 @@
|
|||||||
/*
|
package net.schmizz.sshj.examples;
|
||||||
* Copyright 2010, 2011 sshj contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package examples;
|
|
||||||
|
|
||||||
import net.schmizz.sshj.SSHClient;
|
import net.schmizz.sshj.SSHClient;
|
||||||
import net.schmizz.sshj.common.StreamCopier;
|
import net.schmizz.sshj.common.StreamCopier;
|
||||||
import net.schmizz.sshj.connection.channel.direct.Session;
|
import net.schmizz.sshj.connection.channel.direct.Session;
|
||||||
import net.schmizz.sshj.connection.channel.direct.Session.Command;
|
import net.schmizz.sshj.connection.channel.direct.Session.Command;
|
||||||
import net.schmizz.sshj.connection.channel.forwarded.SocketForwardingConnectListener;
|
import net.schmizz.sshj.connection.channel.forwarded.SocketForwardingConnectListener;
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@@ -57,8 +43,8 @@ public class X11 {
|
|||||||
|
|
||||||
final Command cmd = sess.exec("/usr/X11/bin/xcalc");
|
final Command cmd = sess.exec("/usr/X11/bin/xcalc");
|
||||||
|
|
||||||
new StreamCopier(cmd.getInputStream(), System.out).spawn("stdout");
|
new StreamCopier(cmd.getInputStream(), System.out, LoggerFactory.DEFAULT).spawn("stdout");
|
||||||
new StreamCopier(cmd.getErrorStream(), System.err).spawn("stderr");
|
new StreamCopier(cmd.getErrorStream(), System.err, LoggerFactory.DEFAULT).spawn("stderr");
|
||||||
|
|
||||||
// Wait for session & X11 channel to get closed
|
// Wait for session & X11 channel to get closed
|
||||||
ssh.getConnection().join();
|
ssh.getConnection().join();
|
||||||
@@ -67,4 +53,4 @@ public class X11 {
|
|||||||
ssh.disconnect();
|
ssh.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#Fri Mar 18 11:26:35 CET 2016
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-all.zip
|
||||||
164
gradlew
vendored
Executable file
164
gradlew
vendored
Executable file
@@ -0,0 +1,164 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn ( ) {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die ( ) {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||||
|
if $cygwin ; then
|
||||||
|
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >&-
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >&-
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||||
|
function splitJvmOpts() {
|
||||||
|
JVM_OPTS=("$@")
|
||||||
|
}
|
||||||
|
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||||
|
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||||
90
gradlew.bat
vendored
Normal file
90
gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windowz variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
goto execute
|
||||||
|
|
||||||
|
:4NT_args
|
||||||
|
@rem Get arguments from the 4NT Shell from JP Software
|
||||||
|
set CMD_LINE_ARGS=%$
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
257
pom.xml
257
pom.xml
@@ -1,257 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>net.schmizz</groupId>
|
|
||||||
<artifactId>sshj</artifactId>
|
|
||||||
<packaging>bundle</packaging>
|
|
||||||
<version>0.5.0</version>
|
|
||||||
|
|
||||||
<name>sshj</name>
|
|
||||||
<description>SSHv2 library for Java</description>
|
|
||||||
<url>http://github.com/shikhar/sshj</url>
|
|
||||||
|
|
||||||
<inceptionYear>2009</inceptionYear>
|
|
||||||
|
|
||||||
<issueManagement>
|
|
||||||
<system>github</system>
|
|
||||||
<url>http://github.com/shikhar/sshj/issues</url>
|
|
||||||
</issueManagement>
|
|
||||||
|
|
||||||
<scm>
|
|
||||||
<connection>scm:git:git://github.com/shikhar/sshj.git</connection>
|
|
||||||
<developerConnection>scm:git:git@github.com:shikhar/sshj.git</developerConnection>
|
|
||||||
<url>http://github.com/shikhar/sshj</url>
|
|
||||||
</scm>
|
|
||||||
|
|
||||||
<licenses>
|
|
||||||
<license>
|
|
||||||
<name>Apache 2</name>
|
|
||||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
|
||||||
<distribution>repo</distribution>
|
|
||||||
</license>
|
|
||||||
</licenses>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
<version>1.6.1</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bouncycastle</groupId>
|
|
||||||
<artifactId>bcprov-jdk16</artifactId>
|
|
||||||
<version>1.46</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.8.2</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.jcraft</groupId>
|
|
||||||
<artifactId>jzlib</artifactId>
|
|
||||||
<version>1.0.7</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.sshd</groupId>
|
|
||||||
<artifactId>sshd-core</artifactId>
|
|
||||||
<version>0.5.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ch.qos.logback</groupId>
|
|
||||||
<artifactId>logback-core</artifactId>
|
|
||||||
<version>0.9.29</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ch.qos.logback</groupId>
|
|
||||||
<artifactId>logback-classic</artifactId>
|
|
||||||
<version>0.9.29</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
|
|
||||||
<developers>
|
|
||||||
<developer>
|
|
||||||
<id>shikhar</id>
|
|
||||||
<name>Shikhar Bhushan</name>
|
|
||||||
<email>shikhar@schmizz.net</email>
|
|
||||||
<url>http://schmizz.net</url>
|
|
||||||
</developer>
|
|
||||||
</developers>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>2.3.2</version>
|
|
||||||
<configuration>
|
|
||||||
<excludes>
|
|
||||||
<exclude>examples/*.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
<source>1.6</source>
|
|
||||||
<target>1.6</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-release-plugin</artifactId>
|
|
||||||
<version>2.1</version>
|
|
||||||
<configuration>
|
|
||||||
<mavenExecutorId>forked-path</mavenExecutorId>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
|
||||||
<version>2.2.1</version>
|
|
||||||
<configuration>
|
|
||||||
<descriptors>
|
|
||||||
<descriptor>src/assemble/examples.xml</descriptor>
|
|
||||||
</descriptors>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>make-assembly</id>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>single</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
|
||||||
<version>2.1.2</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>attach-sources</id>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>2.8</version>
|
|
||||||
<configuration>
|
|
||||||
<encoding>${project.build.sourceEncoding}</encoding>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>attach-javadocs</id>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.felix</groupId>
|
|
||||||
<artifactId>maven-bundle-plugin</artifactId>
|
|
||||||
<extensions>true</extensions>
|
|
||||||
<configuration>
|
|
||||||
<instructions>
|
|
||||||
<Import-Package>
|
|
||||||
!net.schmizz.*,
|
|
||||||
javax.crypto*,
|
|
||||||
com.jcraft.jzlib*;version="[1.0,2)",
|
|
||||||
org.slf4j*;version="[1.6,2)",
|
|
||||||
org.bouncycastle*;version="[1.4,2)",
|
|
||||||
*
|
|
||||||
</Import-Package>
|
|
||||||
<Export-Package>net.schmizz.*</Export-Package>
|
|
||||||
</instructions>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<distributionManagement>
|
|
||||||
<repository>
|
|
||||||
<id>sonatype-nexus-staging</id>
|
|
||||||
<name>Nexus Release Repository</name>
|
|
||||||
<url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
|
||||||
</repository>
|
|
||||||
<snapshotRepository>
|
|
||||||
<id>sonatype-nexus-snapshots</id>
|
|
||||||
<name>Sonatype Nexus Snapshots</name>
|
|
||||||
<url>http://oss.sonatype.org/content/repositories/snapshots</url>
|
|
||||||
</snapshotRepository>
|
|
||||||
</distributionManagement>
|
|
||||||
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>full-deps</id>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bouncycastle</groupId>
|
|
||||||
<artifactId>bcprov-jdk16</artifactId>
|
|
||||||
<version>1.45</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.jcraft</groupId>
|
|
||||||
<artifactId>jzlib</artifactId>
|
|
||||||
<version>1.0.7</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ch.qos.logback</groupId>
|
|
||||||
<artifactId>logback-core</artifactId>
|
|
||||||
<version>0.9.24</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ch.qos.logback</groupId>
|
|
||||||
<artifactId>logback-classic</artifactId>
|
|
||||||
<version>0.9.24</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</profile>
|
|
||||||
<profile>
|
|
||||||
<id>release-sign-artifacts</id>
|
|
||||||
<activation>
|
|
||||||
<property>
|
|
||||||
<name>performRelease</name>
|
|
||||||
<value>true</value>
|
|
||||||
</property>
|
|
||||||
</activation>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
|
||||||
<version>1.3</version>
|
|
||||||
<configuration>
|
|
||||||
<passphrase>${gpg.passphrase}</passphrase>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>sign-artifacts</id>
|
|
||||||
<phase>verify</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>sign</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
|
|
||||||
</profiles>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
1
settings.gradle
Normal file
1
settings.gradle
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = "sshj"
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
|
|
||||||
<id>examples</id>
|
|
||||||
<formats>
|
|
||||||
<format>zip</format>
|
|
||||||
</formats>
|
|
||||||
<fileSets>
|
|
||||||
<fileSet>
|
|
||||||
<directory>src/main/java/examples</directory>
|
|
||||||
<includes/>
|
|
||||||
<outputDirectory>examples</outputDirectory>
|
|
||||||
</fileSet>
|
|
||||||
</fileSets>
|
|
||||||
</assembly>
|
|
||||||
13
src/etc/license-header
Normal file
13
src/etc/license-header
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright ${project.inceptionYear} ${owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
26
src/main/java/com/hierynomus/sshj/backport/JavaVersion.java
Normal file
26
src/main/java/com/hierynomus/sshj/backport/JavaVersion.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.backport;
|
||||||
|
|
||||||
|
public class JavaVersion {
|
||||||
|
public static boolean isJava7OrEarlier() {
|
||||||
|
String property = System.getProperty("java.specification.version");
|
||||||
|
float diff = Float.parseFloat(property) - 1.7f;
|
||||||
|
|
||||||
|
return diff < 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.backport;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
public class Jdk7HttpProxySocket extends Socket {
|
||||||
|
|
||||||
|
private Proxy httpProxy = null;
|
||||||
|
|
||||||
|
public Jdk7HttpProxySocket(Proxy proxy) {
|
||||||
|
super(proxy.type() == Proxy.Type.HTTP ? Proxy.NO_PROXY : proxy);
|
||||||
|
if (proxy.type() == Proxy.Type.HTTP) {
|
||||||
|
this.httpProxy = proxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(SocketAddress endpoint, int timeout) throws IOException {
|
||||||
|
if (httpProxy != null) {
|
||||||
|
connectHttpProxy(endpoint, timeout);
|
||||||
|
} else {
|
||||||
|
super.connect(endpoint, timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectHttpProxy(SocketAddress endpoint, int timeout) throws IOException {
|
||||||
|
super.connect(httpProxy.address(), timeout);
|
||||||
|
|
||||||
|
if (!(endpoint instanceof InetSocketAddress)) {
|
||||||
|
throw new SocketException("Expected an InetSocketAddress to connect to, got: " + endpoint);
|
||||||
|
}
|
||||||
|
InetSocketAddress isa = (InetSocketAddress) endpoint;
|
||||||
|
String httpConnect = "CONNECT " + isa.getHostName() + ":" + isa.getPort() + " HTTP/1.0\n\n";
|
||||||
|
getOutputStream().write(httpConnect.getBytes(Charset.forName("UTF-8")));
|
||||||
|
checkAndFlushProxyResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAndFlushProxyResponse()throws IOException {
|
||||||
|
InputStream socketInput = getInputStream();
|
||||||
|
byte[] tmpBuffer = new byte[512];
|
||||||
|
int len = socketInput.read(tmpBuffer, 0, tmpBuffer.length);
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
throw new SocketException("Empty response from proxy");
|
||||||
|
}
|
||||||
|
|
||||||
|
String proxyResponse = new String(tmpBuffer, 0, len, "UTF-8");
|
||||||
|
|
||||||
|
// Expecting HTTP/1.x 200 OK
|
||||||
|
if (proxyResponse.contains("200")) {
|
||||||
|
// Flush any outstanding message in buffer
|
||||||
|
if (socketInput.available() > 0) {
|
||||||
|
socketInput.skip(socketInput.available());
|
||||||
|
}
|
||||||
|
// Proxy Connect Successful
|
||||||
|
} else {
|
||||||
|
throw new SocketException("Fail to create Socket\nResponse was:" + proxyResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/com/hierynomus/sshj/backport/Sockets.java
Normal file
41
src/main/java/com/hierynomus/sshj/backport/Sockets.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.backport;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
public class Sockets {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java 7 and up have Socket implemented as Closeable, whereas Java6 did not have this inheritance.
|
||||||
|
* @param socket The socket to wrap as Closeable
|
||||||
|
* @return The (potentially wrapped) Socket as a Closeable.
|
||||||
|
*/
|
||||||
|
public static Closeable asCloseable(final Socket socket) {
|
||||||
|
if (Closeable.class.isAssignableFrom(socket.getClass())) {
|
||||||
|
return Closeable.class.cast(socket);
|
||||||
|
} else {
|
||||||
|
return new Closeable() {
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/main/java/com/hierynomus/sshj/secg/SecgUtils.java
Normal file
70
src/main/java/com/hierynomus/sshj/secg/SecgUtils.java
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.secg;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.SSHRuntimeException;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.spec.ECPoint;
|
||||||
|
import java.security.spec.EllipticCurve;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class SecgUtils {
|
||||||
|
/**
|
||||||
|
* SECG 2.3.4 Octet String to ECPoint
|
||||||
|
*/
|
||||||
|
public static ECPoint getDecoded(byte[] M, EllipticCurve curve) {
|
||||||
|
int elementSize = getElementSize(curve);
|
||||||
|
if (M.length != 2 * elementSize + 1 || M[0] != 0x04) {
|
||||||
|
throw new SSHRuntimeException("Invalid 'f' for Elliptic Curve " + curve.toString());
|
||||||
|
}
|
||||||
|
byte[] xBytes = new byte[elementSize];
|
||||||
|
byte[] yBytes = new byte[elementSize];
|
||||||
|
System.arraycopy(M, 1, xBytes, 0, elementSize);
|
||||||
|
System.arraycopy(M, 1 + elementSize, yBytes, 0, elementSize);
|
||||||
|
return new ECPoint(new BigInteger(1, xBytes), new BigInteger(1, yBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECG 2.3.3 ECPoint to Octet String
|
||||||
|
*/
|
||||||
|
public static byte[] getEncoded(ECPoint point, EllipticCurve curve) {
|
||||||
|
int elementSize = getElementSize(curve);
|
||||||
|
byte[] M = new byte[2 * elementSize + 1];
|
||||||
|
M[0] = 0x04;
|
||||||
|
|
||||||
|
byte[] xBytes = stripLeadingZeroes(point.getAffineX().toByteArray());
|
||||||
|
byte[] yBytes = stripLeadingZeroes(point.getAffineY().toByteArray());
|
||||||
|
System.arraycopy(xBytes, 0, M, 1 + elementSize - xBytes.length, xBytes.length);
|
||||||
|
System.arraycopy(yBytes, 0, M, 1 + 2 * elementSize - yBytes.length, yBytes.length);
|
||||||
|
return M;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] stripLeadingZeroes(byte[] bytes) {
|
||||||
|
int start = 0;
|
||||||
|
while (bytes[start] == 0x0) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Arrays.copyOfRange(bytes, start, bytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getElementSize(EllipticCurve curve) {
|
||||||
|
int fieldSize = curve.getField().getFieldSize();
|
||||||
|
return (fieldSize + 7) / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.signature;
|
||||||
|
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||||
|
import net.schmizz.sshj.common.SSHRuntimeException;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable.CURVE_ED25519_SHA512;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our own extension of the EdDSAPublicKey that comes from ECC-25519, as that class does not implement equality.
|
||||||
|
* The code uses the equality of the keys as an indicator whether they're the same during host key verification.
|
||||||
|
*/
|
||||||
|
public class Ed25519PublicKey extends EdDSAPublicKey {
|
||||||
|
|
||||||
|
public Ed25519PublicKey(EdDSAPublicKeySpec spec) {
|
||||||
|
super(spec);
|
||||||
|
|
||||||
|
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(CURVE_ED25519_SHA512);
|
||||||
|
if (!spec.getParams().getCurve().equals(ed25519.getCurve())) {
|
||||||
|
throw new SSHRuntimeException("Cannot create Ed25519 Public Key from wrong spec");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (!(other instanceof Ed25519PublicKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ed25519PublicKey otherKey = (Ed25519PublicKey) other;
|
||||||
|
return Arrays.equals(getAbyte(), otherKey.getAbyte());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getA().hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
109
src/main/java/com/hierynomus/sshj/signature/SignatureEdDSA.java
Normal file
109
src/main/java/com/hierynomus/sshj/signature/SignatureEdDSA.java
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.signature;
|
||||||
|
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAEngine;
|
||||||
|
import net.schmizz.sshj.common.Buffer;
|
||||||
|
import net.schmizz.sshj.common.KeyType;
|
||||||
|
import net.schmizz.sshj.common.SSHRuntimeException;
|
||||||
|
import net.schmizz.sshj.signature.Signature;
|
||||||
|
|
||||||
|
import java.security.*;
|
||||||
|
|
||||||
|
public class SignatureEdDSA implements Signature {
|
||||||
|
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Signature> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return KeyType.ED25519.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Signature create() {
|
||||||
|
return new SignatureEdDSA();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final EdDSAEngine engine;
|
||||||
|
|
||||||
|
protected SignatureEdDSA() {
|
||||||
|
try {
|
||||||
|
engine = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(PublicKey pubkey, PrivateKey prvkey) {
|
||||||
|
try {
|
||||||
|
if (pubkey != null) {
|
||||||
|
engine.initVerify(pubkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prvkey != null) {
|
||||||
|
engine.initSign(prvkey);
|
||||||
|
}
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte[] H) {
|
||||||
|
update(H, 0, H.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(byte[] H, int off, int len) {
|
||||||
|
try {
|
||||||
|
engine.update(H, off, len);
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] sign() {
|
||||||
|
try {
|
||||||
|
return engine.sign();
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encode(byte[] signature) {
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verify(byte[] sig) {
|
||||||
|
try {
|
||||||
|
Buffer.PlainBuffer plainBuffer = new Buffer.PlainBuffer(sig);
|
||||||
|
String algo = plainBuffer.readString();
|
||||||
|
if (!"ssh-ed25519".equals(algo)) {
|
||||||
|
throw new SSHRuntimeException("Expected 'ssh-ed25519' key algorithm, but was: " + algo);
|
||||||
|
}
|
||||||
|
byte[] bytes = plainBuffer.readBytes();
|
||||||
|
return engine.verify(bytes);
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
} catch (Buffer.BufferException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.transport;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.Buffer;
|
||||||
|
import net.schmizz.sshj.common.ByteArrayUtils;
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class IdentificationStringParser {
|
||||||
|
private final Logger log;
|
||||||
|
private final Buffer.PlainBuffer buffer;
|
||||||
|
|
||||||
|
private byte[] EXPECTED_START_BYTES = new byte[] {'S', 'S', 'H', '-'};
|
||||||
|
|
||||||
|
public IdentificationStringParser(Buffer.PlainBuffer buffer) {
|
||||||
|
this(buffer, LoggerFactory.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdentificationStringParser(Buffer.PlainBuffer buffer, LoggerFactory loggerFactory) {
|
||||||
|
this.log = loggerFactory.getLogger(IdentificationStringParser.class);
|
||||||
|
this.buffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String parseIdentificationString() throws IOException {
|
||||||
|
for (;;) {
|
||||||
|
Buffer.PlainBuffer lineBuffer = new Buffer.PlainBuffer();
|
||||||
|
int lineStartPos = buffer.rpos();
|
||||||
|
for (;;) {
|
||||||
|
if (buffer.available() == 0) {
|
||||||
|
buffer.rpos(lineStartPos);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
byte b = buffer.readByte();
|
||||||
|
lineBuffer.putByte(b);
|
||||||
|
if (b == '\n') {
|
||||||
|
if (checkForIdentification(lineBuffer)) {
|
||||||
|
return readIdentification(lineBuffer);
|
||||||
|
} else {
|
||||||
|
logHeaderLine(lineBuffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logHeaderLine(Buffer.PlainBuffer lineBuffer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readIdentification(Buffer.PlainBuffer lineBuffer) throws Buffer.BufferException, TransportException {
|
||||||
|
byte[] bytes = new byte[lineBuffer.available()];
|
||||||
|
lineBuffer.readRawBytes(bytes);
|
||||||
|
if (bytes.length > 255) {
|
||||||
|
log.error("Incorrect identification String received, line was longer than expected: {}", new String(bytes));
|
||||||
|
log.error("Just for good measure, bytes were: {}", ByteArrayUtils.printHex(bytes, 0, bytes.length));
|
||||||
|
throw new TransportException("Incorrect identification: line too long: " + ByteArrayUtils.printHex(bytes, 0, bytes.length));
|
||||||
|
}
|
||||||
|
if (bytes[bytes.length - 2] != '\r') {
|
||||||
|
String ident = new String(bytes, 0, bytes.length - 1);
|
||||||
|
log.warn("Server identification has bad line ending, was expecting a '\\r\\n' however got: '{}' (hex: {})", (char) (bytes[bytes.length - 2] & 0xFF), Integer.toHexString(bytes[bytes.length - 2] & 0xFF));
|
||||||
|
log.warn("Will treat the identification of this server '{}' leniently", ident);
|
||||||
|
return ident;
|
||||||
|
// log.error("Data received up til here was: {}", new String(bytes));
|
||||||
|
// throw new TransportException("Incorrect identification: bad line ending: " + ByteArrayUtils.toHex(bytes, 0, bytes.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip off the \r\n
|
||||||
|
return new String(bytes, 0, bytes.length - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkForIdentification(Buffer.PlainBuffer lineBuffer) throws Buffer.BufferException {
|
||||||
|
if (lineBuffer.available() < 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
byte[] buf = new byte[4];
|
||||||
|
lineBuffer.readRawBytes(buf);
|
||||||
|
// Reset
|
||||||
|
lineBuffer.rpos(0);
|
||||||
|
return Arrays.equals(EXPECTED_START_BYTES, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.transport.cipher;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.transport.cipher.BlockCipher;
|
||||||
|
import net.schmizz.sshj.transport.cipher.Cipher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All BlockCiphers supported by SSH according to the following RFCs
|
||||||
|
*
|
||||||
|
* - https://tools.ietf.org/html/rfc4344#section-3.1
|
||||||
|
* - https://tools.ietf.org/html/rfc4253#section-6.3
|
||||||
|
*
|
||||||
|
* TODO: https://tools.ietf.org/html/rfc5647
|
||||||
|
*
|
||||||
|
* Some of the Ciphers are still implemented in net.schmizz.sshj.transport.cipher.*. These are scheduled to be migrated to here.
|
||||||
|
*/
|
||||||
|
public class BlockCiphers {
|
||||||
|
|
||||||
|
public static final String COUNTER_MODE = "CTR";
|
||||||
|
public static final String CIPHER_BLOCK_CHAINING_MODE = "CBC";
|
||||||
|
|
||||||
|
public static Factory BlowfishCTR() {
|
||||||
|
return new Factory(8, 256, "blowfish-ctr", "Blowfish", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Twofish128CTR() {
|
||||||
|
return new Factory(16, 128, "twofish128-ctr", "Twofish", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Twofish192CTR() {
|
||||||
|
return new Factory(16, 192, "twofish192-ctr", "Twofish", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Twofish256CTR() {
|
||||||
|
return new Factory(16, 256, "twofish256-ctr", "Twofish", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Twofish128CBC() {
|
||||||
|
return new Factory(16, 128, "twofish128-cbc", "Twofish", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Twofish192CBC() {
|
||||||
|
return new Factory(16, 192, "twofish192-cbc", "Twofish", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Twofish256CBC() {
|
||||||
|
return new Factory(16, 256, "twofish256-cbc", "Twofish", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static Factory TwofishCBC() {
|
||||||
|
return new Factory(16, 256, "twofish-cbc", "Twofish", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Serpent128CTR() {
|
||||||
|
return new Factory(16, 128, "serpent128-ctr", "Serpent", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Serpent192CTR() {
|
||||||
|
return new Factory(16, 192, "serpent192-ctr", "Serpent", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Serpent256CTR() {
|
||||||
|
return new Factory(16, 256, "serpent256-ctr", "Serpent", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Serpent128CBC() {
|
||||||
|
return new Factory(16, 128, "serpent128-cbc", "Serpent", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Serpent192CBC() {
|
||||||
|
return new Factory(16, 192, "serpent192-cbc", "Serpent", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Serpent256CBC() {
|
||||||
|
return new Factory(16, 256, "serpent256-cbc", "Serpent", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static Factory IDEACTR() {
|
||||||
|
return new Factory(8, 128, "idea-ctr", "IDEA", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static Factory IDEACBC() {
|
||||||
|
return new Factory(8, 128, "idea-cbc", "IDEA", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Cast128CTR() {
|
||||||
|
return new Factory(8, 128, "cast128-ctr", "CAST5", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static Factory Cast128CBC() {
|
||||||
|
return new Factory(8, 128, "cast128-cbc", "CAST5", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static Factory TripleDESCTR() {
|
||||||
|
return new Factory(8, 192, "3des-ctr", "DESede", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Named factory for BlockCipher */
|
||||||
|
public static class Factory
|
||||||
|
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
|
||||||
|
|
||||||
|
private int keysize;
|
||||||
|
private String cipher;
|
||||||
|
private String mode;
|
||||||
|
private String name;
|
||||||
|
private int ivsize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ivsize
|
||||||
|
* @param keysize The keysize used in bits.
|
||||||
|
* @param name
|
||||||
|
* @param cipher
|
||||||
|
* @param mode
|
||||||
|
*/
|
||||||
|
public Factory(int ivsize, int keysize, String name, String cipher, String mode) {
|
||||||
|
this.name = name;
|
||||||
|
this.keysize = keysize;
|
||||||
|
this.cipher = cipher;
|
||||||
|
this.mode = mode;
|
||||||
|
this.ivsize = ivsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cipher create() {
|
||||||
|
return new BlockCipher(ivsize, keysize / 8, cipher, cipher + "/" + mode + "/NoPadding");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.transport.cipher;
|
||||||
|
|
||||||
|
import static com.hierynomus.sshj.transport.cipher.BlockCiphers.CIPHER_BLOCK_CHAINING_MODE;
|
||||||
|
import static com.hierynomus.sshj.transport.cipher.BlockCiphers.COUNTER_MODE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of Block Ciphers that are (not yet) part of any of the official RFCs for SSH, but
|
||||||
|
* that are either supported by other SSH implementations, or are being pushed for to be
|
||||||
|
* included in a new RFC.
|
||||||
|
*
|
||||||
|
* - http://tools.ietf.org/id/draft-kanno-secsh-camellia-01.txt
|
||||||
|
*/
|
||||||
|
public class ExtendedBlockCiphers {
|
||||||
|
public static BlockCiphers.Factory Camellia128CTR() {
|
||||||
|
return new BlockCiphers.Factory(16, 128, "camellia128-ctr", "Camellia", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia128CTROpenSSHOrg() {
|
||||||
|
return new BlockCiphers.Factory(16, 128, "camellia128-ctr@openssh.org", "Camellia", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia192CTR() {
|
||||||
|
return new BlockCiphers.Factory(16, 192, "camellia192-ctr", "Camellia", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia192CTROpenSSHOrg() {
|
||||||
|
return new BlockCiphers.Factory(16, 192, "camellia192-ctr@openssh.org", "Camellia", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia256CTR() {
|
||||||
|
return new BlockCiphers.Factory(16, 256, "camellia256-ctr", "Camellia", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia256CTROpenSSHOrg() {
|
||||||
|
return new BlockCiphers.Factory(16, 256, "camellia256-ctr@openssh.org", "Camellia", COUNTER_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia128CBC() {
|
||||||
|
return new BlockCiphers.Factory(16, 128, "camellia128-cbc", "Camellia", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia128CBCOpenSSHOrg() {
|
||||||
|
return new BlockCiphers.Factory(16, 128, "camellia128-cbc@openssh.org", "Camellia", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia192CBC() {
|
||||||
|
return new BlockCiphers.Factory(16, 192, "camellia192-cbc", "Camellia", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia192CBCOpenSSHOrg() {
|
||||||
|
return new BlockCiphers.Factory(16, 192, "camellia192-cbc@openssh.org", "Camellia", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia256CBC() {
|
||||||
|
return new BlockCiphers.Factory(16, 256, "camellia256-cbc", "Camellia", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
public static BlockCiphers.Factory Camellia256CBCOpenSSHOrg() {
|
||||||
|
return new BlockCiphers.Factory(16, 256, "camellia256-cbc@openssh.org", "Camellia", CIPHER_BLOCK_CHAINING_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.transport.cipher;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.transport.cipher.BaseCipher;
|
||||||
|
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
public class StreamCipher extends BaseCipher {
|
||||||
|
|
||||||
|
public StreamCipher(int bsize, String algorithm, String transformation) {
|
||||||
|
super(0, bsize, algorithm, transformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initCipher(javax.crypto.Cipher cipher, Mode mode, byte[] key, byte[] iv) throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||||
|
cipher.init(getMode(mode), getKeySpec(key), new SecureRandom());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.transport.cipher;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.transport.cipher.Cipher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementations of the Stream Ciphers that are defined in the RFCs
|
||||||
|
*
|
||||||
|
* - https://tools.ietf.org/html/rfc4253#section-6.3
|
||||||
|
* - https://tools.ietf.org/html/rfc4345
|
||||||
|
*/
|
||||||
|
public class StreamCiphers {
|
||||||
|
|
||||||
|
public static Factory Arcfour() {
|
||||||
|
return new Factory(128, "arcfour", "ARCFOUR", "ECB");
|
||||||
|
}
|
||||||
|
public static Factory Arcfour128() {
|
||||||
|
return new Factory(128, "arcfour128", "RC4", "ECB");
|
||||||
|
}
|
||||||
|
public static Factory Arcfour256() {
|
||||||
|
return new Factory(256, "arcfour256", "RC4", "ECB");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Named factory for BlockCipher */
|
||||||
|
public static class Factory
|
||||||
|
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
|
||||||
|
|
||||||
|
private int keysize;
|
||||||
|
private String cipher;
|
||||||
|
private String mode;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param keysize The keysize used in bits.
|
||||||
|
* @param name
|
||||||
|
* @param cipher
|
||||||
|
* @param mode
|
||||||
|
*/
|
||||||
|
public Factory(int keysize, String name, String cipher, String mode) {
|
||||||
|
this.name = name;
|
||||||
|
this.keysize = keysize;
|
||||||
|
this.cipher = cipher;
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cipher create() {
|
||||||
|
return new StreamCipher(keysize / 8, cipher, cipher + "/" + mode + "/NoPadding");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.hierynomus.sshj.userauth.keyprovider;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
||||||
|
import net.schmizz.sshj.common.*;
|
||||||
|
import net.schmizz.sshj.common.Buffer.PlainBuffer;
|
||||||
|
import net.schmizz.sshj.userauth.keyprovider.BaseFileKeyProvider;
|
||||||
|
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
|
||||||
|
import net.schmizz.sshj.userauth.keyprovider.KeyFormat;
|
||||||
|
|
||||||
|
import static net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable.CURVE_ED25519_SHA512;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a key file in the new OpenSSH format.
|
||||||
|
* The format is described in the following document: https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
|
||||||
|
*/
|
||||||
|
public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(OpenSSHKeyV1KeyFile.class);
|
||||||
|
private static final String BEGIN = "-----BEGIN ";
|
||||||
|
private static final String END = "-----END ";
|
||||||
|
private static final byte[] AUTH_MAGIC = "openssh-key-v1\0".getBytes();
|
||||||
|
public static final String OPENSSH_PRIVATE_KEY = "OPENSSH PRIVATE KEY-----";
|
||||||
|
|
||||||
|
public static class Factory
|
||||||
|
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileKeyProvider create() {
|
||||||
|
return new OpenSSHKeyV1KeyFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return KeyFormat.OpenSSHv1.name();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KeyPair readKeyPair() throws IOException {
|
||||||
|
BufferedReader reader = new BufferedReader(resource.getReader());
|
||||||
|
try {
|
||||||
|
if (!checkHeader(reader)) {
|
||||||
|
throw new IOException("This key is not in 'openssh-key-v1' format");
|
||||||
|
}
|
||||||
|
|
||||||
|
String keyFile = readKeyFile(reader);
|
||||||
|
byte[] decode = Base64.decode(keyFile);
|
||||||
|
PlainBuffer keyBuffer = new PlainBuffer(decode);
|
||||||
|
return readDecodedKeyPair(keyBuffer);
|
||||||
|
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeyPair readDecodedKeyPair(final PlainBuffer keyBuffer) throws IOException, GeneralSecurityException {
|
||||||
|
byte[] bytes = new byte[AUTH_MAGIC.length];
|
||||||
|
keyBuffer.readRawBytes(bytes); // byte[] AUTH_MAGIC
|
||||||
|
if (!ByteArrayUtils.equals(bytes, 0, AUTH_MAGIC, 0, AUTH_MAGIC.length)) {
|
||||||
|
throw new IOException("This key does not contain the 'openssh-key-v1' format magic header");
|
||||||
|
}
|
||||||
|
|
||||||
|
String cipherName = keyBuffer.readString(); // string ciphername
|
||||||
|
String kdfName = keyBuffer.readString(); // string kdfname
|
||||||
|
String kdfOptions = keyBuffer.readString(); // string kdfoptions
|
||||||
|
|
||||||
|
int nrKeys = keyBuffer.readUInt32AsInt(); // int number of keys N; Should be 1
|
||||||
|
if (nrKeys != 1) {
|
||||||
|
throw new IOException("We don't support having more than 1 key in the file (yet).");
|
||||||
|
}
|
||||||
|
PublicKey publicKey = readPublicKey(new PlainBuffer(keyBuffer.readBytes())); // string publickey1
|
||||||
|
PlainBuffer privateKeyBuffer = new PlainBuffer(keyBuffer.readBytes()); // string (possibly) encrypted, padded list of private keys
|
||||||
|
if ("none".equals(cipherName)) {
|
||||||
|
logger.debug("Reading unencrypted keypair");
|
||||||
|
return readUnencrypted(privateKeyBuffer, publicKey);
|
||||||
|
} else {
|
||||||
|
logger.info("Keypair is encrypted with: " + cipherName + ", " + kdfName + ", " + kdfOptions);
|
||||||
|
throw new IOException("Cannot read encrypted keypair with " + cipherName + " yet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PublicKey readPublicKey(final PlainBuffer plainBuffer) throws Buffer.BufferException, GeneralSecurityException {
|
||||||
|
return KeyType.fromString(plainBuffer.readString()).readPubKeyFromBuffer(plainBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readKeyFile(final BufferedReader reader) throws IOException {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String line = reader.readLine();
|
||||||
|
while (!line.startsWith(END)) {
|
||||||
|
sb.append(line);
|
||||||
|
line = reader.readLine();
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkHeader(final BufferedReader reader) throws IOException {
|
||||||
|
String line = reader.readLine();
|
||||||
|
while (line != null && !line.startsWith(BEGIN)) {
|
||||||
|
line = reader.readLine();
|
||||||
|
}
|
||||||
|
line = line.substring(BEGIN.length());
|
||||||
|
return line.startsWith(OPENSSH_PRIVATE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeyPair readUnencrypted(final PlainBuffer keyBuffer, final PublicKey publicKey) throws IOException, GeneralSecurityException {
|
||||||
|
int privKeyListSize = keyBuffer.available();
|
||||||
|
if (privKeyListSize % 8 != 0) {
|
||||||
|
throw new IOException("The private key section must be a multiple of the block size (8)");
|
||||||
|
}
|
||||||
|
int checkInt1 = keyBuffer.readUInt32AsInt(); // uint32 checkint1
|
||||||
|
int checkInt2 = keyBuffer.readUInt32AsInt(); // uint32 checkint2
|
||||||
|
if (checkInt1 != checkInt2) {
|
||||||
|
throw new IOException("The checkInts differed, the key was not correctly decoded.");
|
||||||
|
}
|
||||||
|
// The private key section contains both the public key and the private key
|
||||||
|
String keyType = keyBuffer.readString(); // string keytype
|
||||||
|
logger.info("Read key type: {}", keyType);
|
||||||
|
|
||||||
|
byte[] pubKey = keyBuffer.readBytes(); // string publickey (again...)
|
||||||
|
keyBuffer.readUInt32();
|
||||||
|
byte[] privKey = new byte[32];
|
||||||
|
keyBuffer.readRawBytes(privKey); // string privatekey
|
||||||
|
keyBuffer.readRawBytes(new byte[32]); // string publickey (again...)
|
||||||
|
String comment = keyBuffer.readString(); // string comment
|
||||||
|
byte[] padding = new byte[keyBuffer.available()];
|
||||||
|
keyBuffer.readRawBytes(padding); // char[] padding
|
||||||
|
for (int i = 0; i < padding.length; i++) {
|
||||||
|
if ((int) padding[i] != i + 1) {
|
||||||
|
throw new IOException("Padding of key format contained wrong byte at position: " + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new KeyPair(publicKey, new EdDSAPrivateKey(new EdDSAPrivateKeySpec(privKey, EdDSANamedCurveTable.getByName(CURVE_ED25519_SHA512))));
|
||||||
|
}
|
||||||
|
}
|
||||||
918
src/main/java/djb/Curve25519.java
Normal file
918
src/main/java/djb/Curve25519.java
Normal file
@@ -0,0 +1,918 @@
|
|||||||
|
/* Ported from C to Java by Dmitry Skiba [sahn0], 23/02/08.
|
||||||
|
* Original: http://cds.xs4all.nl:8081/ecdh/
|
||||||
|
*/
|
||||||
|
/* Generic 64-bit integer implementation of Curve25519 ECDH
|
||||||
|
* Written by Matthijs van Duin, 200608242056
|
||||||
|
* Public domain.
|
||||||
|
*
|
||||||
|
* Based on work by Daniel J Bernstein, http://cr.yp.to/ecdh.html
|
||||||
|
*/
|
||||||
|
package djb;
|
||||||
|
|
||||||
|
public class Curve25519 {
|
||||||
|
|
||||||
|
/* key size */
|
||||||
|
public static final int KEY_SIZE = 32;
|
||||||
|
|
||||||
|
/* 0 */
|
||||||
|
public static final byte[] ZERO = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* the prime 2^255-19 */
|
||||||
|
public static final byte[] PRIME = {
|
||||||
|
(byte)237, (byte)255, (byte)255, (byte)255,
|
||||||
|
(byte)255, (byte)255, (byte)255, (byte)255,
|
||||||
|
(byte)255, (byte)255, (byte)255, (byte)255,
|
||||||
|
(byte)255, (byte)255, (byte)255, (byte)255,
|
||||||
|
(byte)255, (byte)255, (byte)255, (byte)255,
|
||||||
|
(byte)255, (byte)255, (byte)255, (byte)255,
|
||||||
|
(byte)255, (byte)255, (byte)255, (byte)255,
|
||||||
|
(byte)255, (byte)255, (byte)255, (byte)127
|
||||||
|
};
|
||||||
|
|
||||||
|
/* group order (a prime near 2^252+2^124) */
|
||||||
|
public static final byte[] ORDER = {
|
||||||
|
(byte)237, (byte)211, (byte)245, (byte)92,
|
||||||
|
(byte)26, (byte)99, (byte)18, (byte)88,
|
||||||
|
(byte)214, (byte)156, (byte)247, (byte)162,
|
||||||
|
(byte)222, (byte)249, (byte)222, (byte)20,
|
||||||
|
(byte)0, (byte)0, (byte)0, (byte)0,
|
||||||
|
(byte)0, (byte)0, (byte)0, (byte)0,
|
||||||
|
(byte)0, (byte)0, (byte)0, (byte)0,
|
||||||
|
(byte)0, (byte)0, (byte)0, (byte)16
|
||||||
|
};
|
||||||
|
|
||||||
|
/********* KEY AGREEMENT *********/
|
||||||
|
|
||||||
|
/* Private key clamping
|
||||||
|
* k [out] your private key for key agreement
|
||||||
|
* k [in] 32 random bytes
|
||||||
|
*/
|
||||||
|
public static final void clamp(byte[] k) {
|
||||||
|
k[31] &= 0x7F;
|
||||||
|
k[31] |= 0x40;
|
||||||
|
k[ 0] &= 0xF8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Key-pair generation
|
||||||
|
* P [out] your public key
|
||||||
|
* s [out] your private key for signing
|
||||||
|
* k [out] your private key for key agreement
|
||||||
|
* k [in] 32 random bytes
|
||||||
|
* s may be NULL if you don't care
|
||||||
|
*
|
||||||
|
* WARNING: if s is not NULL, this function has data-dependent timing */
|
||||||
|
public static final void keygen(byte[] P, byte[] s, byte[] k) {
|
||||||
|
clamp(k);
|
||||||
|
core(P, s, k, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Key agreement
|
||||||
|
* Z [out] shared secret (needs hashing before use)
|
||||||
|
* k [in] your private key for key agreement
|
||||||
|
* P [in] peer's public key
|
||||||
|
*/
|
||||||
|
public static final void curve(byte[] Z, byte[] k, byte[] P) {
|
||||||
|
core(Z, null, k, P);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********* DIGITAL SIGNATURES *********/
|
||||||
|
|
||||||
|
/* deterministic EC-KCDSA
|
||||||
|
*
|
||||||
|
* s is the private key for signing
|
||||||
|
* P is the corresponding public key
|
||||||
|
* Z is the context data (signer public key or certificate, etc)
|
||||||
|
*
|
||||||
|
* signing:
|
||||||
|
*
|
||||||
|
* m = hash(Z, message)
|
||||||
|
* x = hash(m, s)
|
||||||
|
* keygen25519(Y, NULL, x);
|
||||||
|
* r = hash(Y);
|
||||||
|
* h = m XOR r
|
||||||
|
* sign25519(v, h, x, s);
|
||||||
|
*
|
||||||
|
* output (v,r) as the signature
|
||||||
|
*
|
||||||
|
* verification:
|
||||||
|
*
|
||||||
|
* m = hash(Z, message);
|
||||||
|
* h = m XOR r
|
||||||
|
* verify25519(Y, v, h, P)
|
||||||
|
*
|
||||||
|
* confirm r == hash(Y)
|
||||||
|
*
|
||||||
|
* It would seem to me that it would be simpler to have the signer directly do
|
||||||
|
* h = hash(m, Y) and send that to the recipient instead of r, who can verify
|
||||||
|
* the signature by checking h == hash(m, Y). If there are any problems with
|
||||||
|
* such a scheme, please let me know.
|
||||||
|
*
|
||||||
|
* Also, EC-KCDSA (like most DS algorithms) picks x random, which is a waste of
|
||||||
|
* perfectly good entropy, but does allow Y to be calculated in advance of (or
|
||||||
|
* parallel to) hashing the message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Signature generation primitive, calculates (x-h)s mod q
|
||||||
|
* v [out] signature value
|
||||||
|
* h [in] signature hash (of message, signature pub key, and context data)
|
||||||
|
* x [in] signature private key
|
||||||
|
* s [in] private key for signing
|
||||||
|
* returns true on success, false on failure (use different x or h)
|
||||||
|
*/
|
||||||
|
public static final boolean sign(byte[] v, byte[] h, byte[] x, byte[] s) {
|
||||||
|
// v = (x - h) s mod q
|
||||||
|
int w, i;
|
||||||
|
byte[] h1 = new byte[32], x1 = new byte[32];
|
||||||
|
byte[] tmp1 = new byte[64];
|
||||||
|
byte[] tmp2 = new byte[64];
|
||||||
|
|
||||||
|
// Don't clobber the arguments, be nice!
|
||||||
|
cpy32(h1, h);
|
||||||
|
cpy32(x1, x);
|
||||||
|
|
||||||
|
// Reduce modulo group order
|
||||||
|
byte[] tmp3=new byte[32];
|
||||||
|
divmod(tmp3, h1, 32, ORDER, 32);
|
||||||
|
divmod(tmp3, x1, 32, ORDER, 32);
|
||||||
|
|
||||||
|
// v = x1 - h1
|
||||||
|
// If v is negative, add the group order to it to become positive.
|
||||||
|
// If v was already positive we don't have to worry about overflow
|
||||||
|
// when adding the order because v < ORDER and 2*ORDER < 2^256
|
||||||
|
mula_small(v, x1, 0, h1, 32, -1);
|
||||||
|
mula_small(v, v , 0, ORDER, 32, 1);
|
||||||
|
|
||||||
|
// tmp1 = (x-h)*s mod q
|
||||||
|
mula32(tmp1, v, s, 32, 1);
|
||||||
|
divmod(tmp2, tmp1, 64, ORDER, 32);
|
||||||
|
|
||||||
|
for (w = 0, i = 0; i < 32; i++)
|
||||||
|
w |= v[i] = tmp1[i];
|
||||||
|
return w != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Signature verification primitive, calculates Y = vP + hG
|
||||||
|
* Y [out] signature public key
|
||||||
|
* v [in] signature value
|
||||||
|
* h [in] signature hash
|
||||||
|
* P [in] public key
|
||||||
|
*/
|
||||||
|
public static final void verify(byte[] Y, byte[] v, byte[] h, byte[] P) {
|
||||||
|
/* Y = v abs(P) + h G */
|
||||||
|
byte[] d=new byte[32];
|
||||||
|
long10[]
|
||||||
|
p=new long10[]{new long10(),new long10()},
|
||||||
|
s=new long10[]{new long10(),new long10()},
|
||||||
|
yx=new long10[]{new long10(),new long10(),new long10()},
|
||||||
|
yz=new long10[]{new long10(),new long10(),new long10()},
|
||||||
|
t1=new long10[]{new long10(),new long10(),new long10()},
|
||||||
|
t2=new long10[]{new long10(),new long10(),new long10()};
|
||||||
|
|
||||||
|
int vi = 0, hi = 0, di = 0, nvh=0, i, j, k;
|
||||||
|
|
||||||
|
/* set p[0] to G and p[1] to P */
|
||||||
|
|
||||||
|
set(p[0], 9);
|
||||||
|
unpack(p[1], P);
|
||||||
|
|
||||||
|
/* set s[0] to P+G and s[1] to P-G */
|
||||||
|
|
||||||
|
/* s[0] = (Py^2 + Gy^2 - 2 Py Gy)/(Px - Gx)^2 - Px - Gx - 486662 */
|
||||||
|
/* s[1] = (Py^2 + Gy^2 + 2 Py Gy)/(Px - Gx)^2 - Px - Gx - 486662 */
|
||||||
|
|
||||||
|
x_to_y2(t1[0], t2[0], p[1]); /* t2[0] = Py^2 */
|
||||||
|
sqrt(t1[0], t2[0]); /* t1[0] = Py or -Py */
|
||||||
|
j = is_negative(t1[0]); /* ... check which */
|
||||||
|
t2[0]._0 += 39420360; /* t2[0] = Py^2 + Gy^2 */
|
||||||
|
mul(t2[1], BASE_2Y, t1[0]);/* t2[1] = 2 Py Gy or -2 Py Gy */
|
||||||
|
sub(t1[j], t2[0], t2[1]); /* t1[0] = Py^2 + Gy^2 - 2 Py Gy */
|
||||||
|
add(t1[1-j], t2[0], t2[1]);/* t1[1] = Py^2 + Gy^2 + 2 Py Gy */
|
||||||
|
cpy(t2[0], p[1]); /* t2[0] = Px */
|
||||||
|
t2[0]._0 -= 9; /* t2[0] = Px - Gx */
|
||||||
|
sqr(t2[1], t2[0]); /* t2[1] = (Px - Gx)^2 */
|
||||||
|
recip(t2[0], t2[1], 0); /* t2[0] = 1/(Px - Gx)^2 */
|
||||||
|
mul(s[0], t1[0], t2[0]); /* s[0] = t1[0]/(Px - Gx)^2 */
|
||||||
|
sub(s[0], s[0], p[1]); /* s[0] = t1[0]/(Px - Gx)^2 - Px */
|
||||||
|
s[0]._0 -= 9 + 486662; /* s[0] = X(P+G) */
|
||||||
|
mul(s[1], t1[1], t2[0]); /* s[1] = t1[1]/(Px - Gx)^2 */
|
||||||
|
sub(s[1], s[1], p[1]); /* s[1] = t1[1]/(Px - Gx)^2 - Px */
|
||||||
|
s[1]._0 -= 9 + 486662; /* s[1] = X(P-G) */
|
||||||
|
mul_small(s[0], s[0], 1); /* reduce s[0] */
|
||||||
|
mul_small(s[1], s[1], 1); /* reduce s[1] */
|
||||||
|
|
||||||
|
|
||||||
|
/* prepare the chain */
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
vi = (vi >> 8) ^ (v[i] & 0xFF) ^ ((v[i] & 0xFF) << 1);
|
||||||
|
hi = (hi >> 8) ^ (h[i] & 0xFF) ^ ((h[i] & 0xFF) << 1);
|
||||||
|
nvh = ~(vi ^ hi);
|
||||||
|
di = (nvh & (di & 0x80) >> 7) ^ vi;
|
||||||
|
di ^= nvh & (di & 0x01) << 1;
|
||||||
|
di ^= nvh & (di & 0x02) << 1;
|
||||||
|
di ^= nvh & (di & 0x04) << 1;
|
||||||
|
di ^= nvh & (di & 0x08) << 1;
|
||||||
|
di ^= nvh & (di & 0x10) << 1;
|
||||||
|
di ^= nvh & (di & 0x20) << 1;
|
||||||
|
di ^= nvh & (di & 0x40) << 1;
|
||||||
|
d[i] = (byte)di;
|
||||||
|
}
|
||||||
|
|
||||||
|
di = ((nvh & (di & 0x80) << 1) ^ vi) >> 8;
|
||||||
|
|
||||||
|
/* initialize state */
|
||||||
|
set(yx[0], 1);
|
||||||
|
cpy(yx[1], p[di]);
|
||||||
|
cpy(yx[2], s[0]);
|
||||||
|
set(yz[0], 0);
|
||||||
|
set(yz[1], 1);
|
||||||
|
set(yz[2], 1);
|
||||||
|
|
||||||
|
/* y[0] is (even)P + (even)G
|
||||||
|
* y[1] is (even)P + (odd)G if current d-bit is 0
|
||||||
|
* y[1] is (odd)P + (even)G if current d-bit is 1
|
||||||
|
* y[2] is (odd)P + (odd)G
|
||||||
|
*/
|
||||||
|
|
||||||
|
vi = 0;
|
||||||
|
hi = 0;
|
||||||
|
|
||||||
|
/* and go for it! */
|
||||||
|
for (i = 32; i--!=0; ) {
|
||||||
|
vi = (vi << 8) | (v[i] & 0xFF);
|
||||||
|
hi = (hi << 8) | (h[i] & 0xFF);
|
||||||
|
di = (di << 8) | (d[i] & 0xFF);
|
||||||
|
|
||||||
|
for (j = 8; j--!=0; ) {
|
||||||
|
mont_prep(t1[0], t2[0], yx[0], yz[0]);
|
||||||
|
mont_prep(t1[1], t2[1], yx[1], yz[1]);
|
||||||
|
mont_prep(t1[2], t2[2], yx[2], yz[2]);
|
||||||
|
|
||||||
|
k = ((vi ^ vi >> 1) >> j & 1)
|
||||||
|
+ ((hi ^ hi >> 1) >> j & 1);
|
||||||
|
mont_dbl(yx[2], yz[2], t1[k], t2[k], yx[0], yz[0]);
|
||||||
|
|
||||||
|
k = (di >> j & 2) ^ ((di >> j & 1) << 1);
|
||||||
|
mont_add(t1[1], t2[1], t1[k], t2[k], yx[1], yz[1],
|
||||||
|
p[di >> j & 1]);
|
||||||
|
|
||||||
|
mont_add(t1[2], t2[2], t1[0], t2[0], yx[2], yz[2],
|
||||||
|
s[((vi ^ hi) >> j & 2) >> 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
k = (vi & 1) + (hi & 1);
|
||||||
|
recip(t1[0], yz[k], 0);
|
||||||
|
mul(t1[1], yx[k], t1[0]);
|
||||||
|
|
||||||
|
pack(t1[1], Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/* sahn0:
|
||||||
|
* Using this class instead of long[10] to avoid bounds checks. */
|
||||||
|
private static final class long10 {
|
||||||
|
public long10() {}
|
||||||
|
public long10(
|
||||||
|
long _0, long _1, long _2, long _3, long _4,
|
||||||
|
long _5, long _6, long _7, long _8, long _9)
|
||||||
|
{
|
||||||
|
this._0=_0; this._1=_1; this._2=_2;
|
||||||
|
this._3=_3; this._4=_4; this._5=_5;
|
||||||
|
this._6=_6; this._7=_7; this._8=_8;
|
||||||
|
this._9=_9;
|
||||||
|
}
|
||||||
|
public long _0,_1,_2,_3,_4,_5,_6,_7,_8,_9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************* radix 2^8 math *********************/
|
||||||
|
|
||||||
|
private static final void cpy32(byte[] d, byte[] s) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 32; i++)
|
||||||
|
d[i] = s[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* p[m..n+m-1] = q[m..n+m-1] + z * x */
|
||||||
|
/* n is the size of x */
|
||||||
|
/* n+m is the size of p and q */
|
||||||
|
private static final int mula_small(byte[] p,byte[] q,int m,byte[] x,int n,int z) {
|
||||||
|
int v=0;
|
||||||
|
for (int i=0;i<n;++i) {
|
||||||
|
v+=(q[i+m] & 0xFF)+z*(x[i] & 0xFF);
|
||||||
|
p[i+m]=(byte)v;
|
||||||
|
v>>=8;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* p += x * y * z where z is a small integer
|
||||||
|
* x is size 32, y is size t, p is size 32+t
|
||||||
|
* y is allowed to overlap with p+32 if you don't care about the upper half */
|
||||||
|
private static final int mula32(byte[] p, byte[] x, byte[] y, int t, int z) {
|
||||||
|
final int n = 31;
|
||||||
|
int w = 0;
|
||||||
|
int i = 0;
|
||||||
|
for (; i < t; i++) {
|
||||||
|
int zy = z * (y[i] & 0xFF);
|
||||||
|
w += mula_small(p, p, i, x, n, zy) +
|
||||||
|
(p[i+n] & 0xFF) + zy * (x[n] & 0xFF);
|
||||||
|
p[i+n] = (byte)w;
|
||||||
|
w >>= 8;
|
||||||
|
}
|
||||||
|
p[i+n] = (byte)(w + (p[i+n] & 0xFF));
|
||||||
|
return w >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* divide r (size n) by d (size t), returning quotient q and remainder r
|
||||||
|
* quotient is size n-t+1, remainder is size t
|
||||||
|
* requires t > 0 && d[t-1] != 0
|
||||||
|
* requires that r[-1] and d[-1] are valid memory locations
|
||||||
|
* q may overlap with r+t */
|
||||||
|
private static final void divmod(byte[] q, byte[] r, int n, byte[] d, int t) {
|
||||||
|
int rn = 0;
|
||||||
|
int dt = ((d[t-1] & 0xFF) << 8);
|
||||||
|
if (t>1) {
|
||||||
|
dt |= (d[t-2] & 0xFF);
|
||||||
|
}
|
||||||
|
while (n-- >= t) {
|
||||||
|
int z = (rn << 16) | ((r[n] & 0xFF) << 8);
|
||||||
|
if (n>0) {
|
||||||
|
z |= (r[n-1] & 0xFF);
|
||||||
|
}
|
||||||
|
z/=dt;
|
||||||
|
rn += mula_small(r,r, n-t+1, d, t, -z);
|
||||||
|
q[n-t+1] = (byte)((z + rn) & 0xFF); /* rn is 0 or -1 (underflow) */
|
||||||
|
mula_small(r,r, n-t+1, d, t, -rn);
|
||||||
|
rn = (r[n] & 0xFF);
|
||||||
|
r[n] = 0;
|
||||||
|
}
|
||||||
|
r[t-1] = (byte)rn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int numsize(byte[] x,int n) {
|
||||||
|
while (n--!=0 && x[n]==0)
|
||||||
|
;
|
||||||
|
return n+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns x if a contains the gcd, y if b.
|
||||||
|
* Also, the returned buffer contains the inverse of a mod b,
|
||||||
|
* as 32-byte signed.
|
||||||
|
* x and y must have 64 bytes space for temporary use.
|
||||||
|
* requires that a[-1] and b[-1] are valid memory locations */
|
||||||
|
private static final byte[] egcd32(byte[] x,byte[] y,byte[] a,byte[] b) {
|
||||||
|
int an, bn = 32, qn, i;
|
||||||
|
for (i = 0; i < 32; i++)
|
||||||
|
x[i] = y[i] = 0;
|
||||||
|
x[0] = 1;
|
||||||
|
an = numsize(a, 32);
|
||||||
|
if (an==0)
|
||||||
|
return y; /* division by zero */
|
||||||
|
byte[] temp=new byte[32];
|
||||||
|
while (true) {
|
||||||
|
qn = bn - an + 1;
|
||||||
|
divmod(temp, b, bn, a, an);
|
||||||
|
bn = numsize(b, bn);
|
||||||
|
if (bn==0)
|
||||||
|
return x;
|
||||||
|
mula32(y, x, temp, qn, -1);
|
||||||
|
|
||||||
|
qn = an - bn + 1;
|
||||||
|
divmod(temp, a, an, b, bn);
|
||||||
|
an = numsize(a, an);
|
||||||
|
if (an==0)
|
||||||
|
return y;
|
||||||
|
mula32(x, y, temp, qn, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************* radix 2^25.5 GF(2^255-19) math *********************/
|
||||||
|
|
||||||
|
private static final int P25=33554431; /* (1 << 25) - 1 */
|
||||||
|
private static final int P26=67108863; /* (1 << 26) - 1 */
|
||||||
|
|
||||||
|
/* Convert to internal format from little-endian byte format */
|
||||||
|
private static final void unpack(long10 x,byte[] m) {
|
||||||
|
x._0 = ((m[0] & 0xFF)) | ((m[1] & 0xFF))<<8 |
|
||||||
|
(m[2] & 0xFF)<<16 | ((m[3] & 0xFF)& 3)<<24;
|
||||||
|
x._1 = ((m[3] & 0xFF)&~ 3)>>2 | (m[4] & 0xFF)<<6 |
|
||||||
|
(m[5] & 0xFF)<<14 | ((m[6] & 0xFF)& 7)<<22;
|
||||||
|
x._2 = ((m[6] & 0xFF)&~ 7)>>3 | (m[7] & 0xFF)<<5 |
|
||||||
|
(m[8] & 0xFF)<<13 | ((m[9] & 0xFF)&31)<<21;
|
||||||
|
x._3 = ((m[9] & 0xFF)&~31)>>5 | (m[10] & 0xFF)<<3 |
|
||||||
|
(m[11] & 0xFF)<<11 | ((m[12] & 0xFF)&63)<<19;
|
||||||
|
x._4 = ((m[12] & 0xFF)&~63)>>6 | (m[13] & 0xFF)<<2 |
|
||||||
|
(m[14] & 0xFF)<<10 | (m[15] & 0xFF) <<18;
|
||||||
|
x._5 = (m[16] & 0xFF) | (m[17] & 0xFF)<<8 |
|
||||||
|
(m[18] & 0xFF)<<16 | ((m[19] & 0xFF)& 1)<<24;
|
||||||
|
x._6 = ((m[19] & 0xFF)&~ 1)>>1 | (m[20] & 0xFF)<<7 |
|
||||||
|
(m[21] & 0xFF)<<15 | ((m[22] & 0xFF)& 7)<<23;
|
||||||
|
x._7 = ((m[22] & 0xFF)&~ 7)>>3 | (m[23] & 0xFF)<<5 |
|
||||||
|
(m[24] & 0xFF)<<13 | ((m[25] & 0xFF)&15)<<21;
|
||||||
|
x._8 = ((m[25] & 0xFF)&~15)>>4 | (m[26] & 0xFF)<<4 |
|
||||||
|
(m[27] & 0xFF)<<12 | ((m[28] & 0xFF)&63)<<20;
|
||||||
|
x._9 = ((m[28] & 0xFF)&~63)>>6 | (m[29] & 0xFF)<<2 |
|
||||||
|
(m[30] & 0xFF)<<10 | (m[31] & 0xFF) <<18;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if reduced-form input >= 2^255-19 */
|
||||||
|
private static final boolean is_overflow(long10 x) {
|
||||||
|
return (
|
||||||
|
((x._0 > P26-19)) &&
|
||||||
|
((x._1 & x._3 & x._5 & x._7 & x._9) == P25) &&
|
||||||
|
((x._2 & x._4 & x._6 & x._8) == P26)
|
||||||
|
) || (x._9 > P25);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert from internal format to little-endian byte format. The
|
||||||
|
* number must be in a reduced form which is output by the following ops:
|
||||||
|
* unpack, mul, sqr
|
||||||
|
* set -- if input in range 0 .. P25
|
||||||
|
* If you're unsure if the number is reduced, first multiply it by 1. */
|
||||||
|
private static final void pack(long10 x,byte[] m) {
|
||||||
|
int ld = 0, ud = 0;
|
||||||
|
long t;
|
||||||
|
ld = (is_overflow(x)?1:0) - ((x._9 < 0)?1:0);
|
||||||
|
ud = ld * -(P25+1);
|
||||||
|
ld *= 19;
|
||||||
|
t = ld + x._0 + (x._1 << 26);
|
||||||
|
m[ 0] = (byte)t;
|
||||||
|
m[ 1] = (byte)(t >> 8);
|
||||||
|
m[ 2] = (byte)(t >> 16);
|
||||||
|
m[ 3] = (byte)(t >> 24);
|
||||||
|
t = (t >> 32) + (x._2 << 19);
|
||||||
|
m[ 4] = (byte)t;
|
||||||
|
m[ 5] = (byte)(t >> 8);
|
||||||
|
m[ 6] = (byte)(t >> 16);
|
||||||
|
m[ 7] = (byte)(t >> 24);
|
||||||
|
t = (t >> 32) + (x._3 << 13);
|
||||||
|
m[ 8] = (byte)t;
|
||||||
|
m[ 9] = (byte)(t >> 8);
|
||||||
|
m[10] = (byte)(t >> 16);
|
||||||
|
m[11] = (byte)(t >> 24);
|
||||||
|
t = (t >> 32) + (x._4 << 6);
|
||||||
|
m[12] = (byte)t;
|
||||||
|
m[13] = (byte)(t >> 8);
|
||||||
|
m[14] = (byte)(t >> 16);
|
||||||
|
m[15] = (byte)(t >> 24);
|
||||||
|
t = (t >> 32) + x._5 + (x._6 << 25);
|
||||||
|
m[16] = (byte)t;
|
||||||
|
m[17] = (byte)(t >> 8);
|
||||||
|
m[18] = (byte)(t >> 16);
|
||||||
|
m[19] = (byte)(t >> 24);
|
||||||
|
t = (t >> 32) + (x._7 << 19);
|
||||||
|
m[20] = (byte)t;
|
||||||
|
m[21] = (byte)(t >> 8);
|
||||||
|
m[22] = (byte)(t >> 16);
|
||||||
|
m[23] = (byte)(t >> 24);
|
||||||
|
t = (t >> 32) + (x._8 << 12);
|
||||||
|
m[24] = (byte)t;
|
||||||
|
m[25] = (byte)(t >> 8);
|
||||||
|
m[26] = (byte)(t >> 16);
|
||||||
|
m[27] = (byte)(t >> 24);
|
||||||
|
t = (t >> 32) + ((x._9 + ud) << 6);
|
||||||
|
m[28] = (byte)t;
|
||||||
|
m[29] = (byte)(t >> 8);
|
||||||
|
m[30] = (byte)(t >> 16);
|
||||||
|
m[31] = (byte)(t >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy a number */
|
||||||
|
private static final void cpy(long10 out, long10 in) {
|
||||||
|
out._0=in._0; out._1=in._1;
|
||||||
|
out._2=in._2; out._3=in._3;
|
||||||
|
out._4=in._4; out._5=in._5;
|
||||||
|
out._6=in._6; out._7=in._7;
|
||||||
|
out._8=in._8; out._9=in._9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set a number to value, which must be in range -185861411 .. 185861411 */
|
||||||
|
private static final void set(long10 out, int in) {
|
||||||
|
out._0=in; out._1=0;
|
||||||
|
out._2=0; out._3=0;
|
||||||
|
out._4=0; out._5=0;
|
||||||
|
out._6=0; out._7=0;
|
||||||
|
out._8=0; out._9=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add/subtract two numbers. The inputs must be in reduced form, and the
|
||||||
|
* output isn't, so to do another addition or subtraction on the output,
|
||||||
|
* first multiply it by one to reduce it. */
|
||||||
|
private static final void add(long10 xy, long10 x, long10 y) {
|
||||||
|
xy._0 = x._0 + y._0; xy._1 = x._1 + y._1;
|
||||||
|
xy._2 = x._2 + y._2; xy._3 = x._3 + y._3;
|
||||||
|
xy._4 = x._4 + y._4; xy._5 = x._5 + y._5;
|
||||||
|
xy._6 = x._6 + y._6; xy._7 = x._7 + y._7;
|
||||||
|
xy._8 = x._8 + y._8; xy._9 = x._9 + y._9;
|
||||||
|
}
|
||||||
|
private static final void sub(long10 xy, long10 x, long10 y) {
|
||||||
|
xy._0 = x._0 - y._0; xy._1 = x._1 - y._1;
|
||||||
|
xy._2 = x._2 - y._2; xy._3 = x._3 - y._3;
|
||||||
|
xy._4 = x._4 - y._4; xy._5 = x._5 - y._5;
|
||||||
|
xy._6 = x._6 - y._6; xy._7 = x._7 - y._7;
|
||||||
|
xy._8 = x._8 - y._8; xy._9 = x._9 - y._9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multiply a number by a small integer in range -185861411 .. 185861411.
|
||||||
|
* The output is in reduced form, the input x need not be. x and xy may point
|
||||||
|
* to the same buffer. */
|
||||||
|
private static final long10 mul_small(long10 xy, long10 x, long y) {
|
||||||
|
long t;
|
||||||
|
t = (x._8*y);
|
||||||
|
xy._8 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x._9*y);
|
||||||
|
xy._9 = (t & ((1 << 25) - 1));
|
||||||
|
t = 19 * (t >> 25) + (x._0*y);
|
||||||
|
xy._0 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x._1*y);
|
||||||
|
xy._1 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + (x._2*y);
|
||||||
|
xy._2 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x._3*y);
|
||||||
|
xy._3 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + (x._4*y);
|
||||||
|
xy._4 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x._5*y);
|
||||||
|
xy._5 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + (x._6*y);
|
||||||
|
xy._6 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x._7*y);
|
||||||
|
xy._7 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + xy._8;
|
||||||
|
xy._8 = (t & ((1 << 26) - 1));
|
||||||
|
xy._9 += (t >> 26);
|
||||||
|
return xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Multiply two numbers. The output is in reduced form, the inputs need not
|
||||||
|
* be. */
|
||||||
|
private static final long10 mul(long10 xy, long10 x, long10 y) {
|
||||||
|
/* sahn0:
|
||||||
|
* Using local variables to avoid class access.
|
||||||
|
* This seem to improve performance a bit...
|
||||||
|
*/
|
||||||
|
long
|
||||||
|
x_0=x._0,x_1=x._1,x_2=x._2,x_3=x._3,x_4=x._4,
|
||||||
|
x_5=x._5,x_6=x._6,x_7=x._7,x_8=x._8,x_9=x._9;
|
||||||
|
long
|
||||||
|
y_0=y._0,y_1=y._1,y_2=y._2,y_3=y._3,y_4=y._4,
|
||||||
|
y_5=y._5,y_6=y._6,y_7=y._7,y_8=y._8,y_9=y._9;
|
||||||
|
long t;
|
||||||
|
t = (x_0*y_8) + (x_2*y_6) + (x_4*y_4) + (x_6*y_2) +
|
||||||
|
(x_8*y_0) + 2 * ((x_1*y_7) + (x_3*y_5) +
|
||||||
|
(x_5*y_3) + (x_7*y_1)) + 38 *
|
||||||
|
(x_9*y_9);
|
||||||
|
xy._8 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x_0*y_9) + (x_1*y_8) + (x_2*y_7) +
|
||||||
|
(x_3*y_6) + (x_4*y_5) + (x_5*y_4) +
|
||||||
|
(x_6*y_3) + (x_7*y_2) + (x_8*y_1) +
|
||||||
|
(x_9*y_0);
|
||||||
|
xy._9 = (t & ((1 << 25) - 1));
|
||||||
|
t = (x_0*y_0) + 19 * ((t >> 25) + (x_2*y_8) + (x_4*y_6)
|
||||||
|
+ (x_6*y_4) + (x_8*y_2)) + 38 *
|
||||||
|
((x_1*y_9) + (x_3*y_7) + (x_5*y_5) +
|
||||||
|
(x_7*y_3) + (x_9*y_1));
|
||||||
|
xy._0 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x_0*y_1) + (x_1*y_0) + 19 * ((x_2*y_9)
|
||||||
|
+ (x_3*y_8) + (x_4*y_7) + (x_5*y_6) +
|
||||||
|
(x_6*y_5) + (x_7*y_4) + (x_8*y_3) +
|
||||||
|
(x_9*y_2));
|
||||||
|
xy._1 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + (x_0*y_2) + (x_2*y_0) + 19 * ((x_4*y_8)
|
||||||
|
+ (x_6*y_6) + (x_8*y_4)) + 2 * (x_1*y_1)
|
||||||
|
+ 38 * ((x_3*y_9) + (x_5*y_7) +
|
||||||
|
(x_7*y_5) + (x_9*y_3));
|
||||||
|
xy._2 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x_0*y_3) + (x_1*y_2) + (x_2*y_1) +
|
||||||
|
(x_3*y_0) + 19 * ((x_4*y_9) + (x_5*y_8) +
|
||||||
|
(x_6*y_7) + (x_7*y_6) +
|
||||||
|
(x_8*y_5) + (x_9*y_4));
|
||||||
|
xy._3 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + (x_0*y_4) + (x_2*y_2) + (x_4*y_0) + 19 *
|
||||||
|
((x_6*y_8) + (x_8*y_6)) + 2 * ((x_1*y_3) +
|
||||||
|
(x_3*y_1)) + 38 *
|
||||||
|
((x_5*y_9) + (x_7*y_7) + (x_9*y_5));
|
||||||
|
xy._4 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x_0*y_5) + (x_1*y_4) + (x_2*y_3) +
|
||||||
|
(x_3*y_2) + (x_4*y_1) + (x_5*y_0) + 19 *
|
||||||
|
((x_6*y_9) + (x_7*y_8) + (x_8*y_7) +
|
||||||
|
(x_9*y_6));
|
||||||
|
xy._5 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + (x_0*y_6) + (x_2*y_4) + (x_4*y_2) +
|
||||||
|
(x_6*y_0) + 19 * (x_8*y_8) + 2 * ((x_1*y_5) +
|
||||||
|
(x_3*y_3) + (x_5*y_1)) + 38 *
|
||||||
|
((x_7*y_9) + (x_9*y_7));
|
||||||
|
xy._6 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + (x_0*y_7) + (x_1*y_6) + (x_2*y_5) +
|
||||||
|
(x_3*y_4) + (x_4*y_3) + (x_5*y_2) +
|
||||||
|
(x_6*y_1) + (x_7*y_0) + 19 * ((x_8*y_9) +
|
||||||
|
(x_9*y_8));
|
||||||
|
xy._7 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + xy._8;
|
||||||
|
xy._8 = (t & ((1 << 26) - 1));
|
||||||
|
xy._9 += (t >> 26);
|
||||||
|
return xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Square a number. Optimization of mul25519(x2, x, x) */
|
||||||
|
private static final long10 sqr(long10 x2, long10 x) {
|
||||||
|
long
|
||||||
|
x_0=x._0,x_1=x._1,x_2=x._2,x_3=x._3,x_4=x._4,
|
||||||
|
x_5=x._5,x_6=x._6,x_7=x._7,x_8=x._8,x_9=x._9;
|
||||||
|
long t;
|
||||||
|
t = (x_4*x_4) + 2 * ((x_0*x_8) + (x_2*x_6)) + 38 *
|
||||||
|
(x_9*x_9) + 4 * ((x_1*x_7) + (x_3*x_5));
|
||||||
|
x2._8 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + 2 * ((x_0*x_9) + (x_1*x_8) + (x_2*x_7) +
|
||||||
|
(x_3*x_6) + (x_4*x_5));
|
||||||
|
x2._9 = (t & ((1 << 25) - 1));
|
||||||
|
t = 19 * (t >> 25) + (x_0*x_0) + 38 * ((x_2*x_8) +
|
||||||
|
(x_4*x_6) + (x_5*x_5)) + 76 * ((x_1*x_9)
|
||||||
|
+ (x_3*x_7));
|
||||||
|
x2._0 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + 2 * (x_0*x_1) + 38 * ((x_2*x_9) +
|
||||||
|
(x_3*x_8) + (x_4*x_7) + (x_5*x_6));
|
||||||
|
x2._1 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + 19 * (x_6*x_6) + 2 * ((x_0*x_2) +
|
||||||
|
(x_1*x_1)) + 38 * (x_4*x_8) + 76 *
|
||||||
|
((x_3*x_9) + (x_5*x_7));
|
||||||
|
x2._2 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + 2 * ((x_0*x_3) + (x_1*x_2)) + 38 *
|
||||||
|
((x_4*x_9) + (x_5*x_8) + (x_6*x_7));
|
||||||
|
x2._3 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + (x_2*x_2) + 2 * (x_0*x_4) + 38 *
|
||||||
|
((x_6*x_8) + (x_7*x_7)) + 4 * (x_1*x_3) + 76 *
|
||||||
|
(x_5*x_9);
|
||||||
|
x2._4 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + 2 * ((x_0*x_5) + (x_1*x_4) + (x_2*x_3))
|
||||||
|
+ 38 * ((x_6*x_9) + (x_7*x_8));
|
||||||
|
x2._5 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + 19 * (x_8*x_8) + 2 * ((x_0*x_6) +
|
||||||
|
(x_2*x_4) + (x_3*x_3)) + 4 * (x_1*x_5) +
|
||||||
|
76 * (x_7*x_9);
|
||||||
|
x2._6 = (t & ((1 << 26) - 1));
|
||||||
|
t = (t >> 26) + 2 * ((x_0*x_7) + (x_1*x_6) + (x_2*x_5) +
|
||||||
|
(x_3*x_4)) + 38 * (x_8*x_9);
|
||||||
|
x2._7 = (t & ((1 << 25) - 1));
|
||||||
|
t = (t >> 25) + x2._8;
|
||||||
|
x2._8 = (t & ((1 << 26) - 1));
|
||||||
|
x2._9 += (t >> 26);
|
||||||
|
return x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculates a reciprocal. The output is in reduced form, the inputs need not
|
||||||
|
* be. Simply calculates y = x^(p-2) so it's not too fast. */
|
||||||
|
/* When sqrtassist is true, it instead calculates y = x^((p-5)/8) */
|
||||||
|
private static final void recip(long10 y, long10 x, int sqrtassist) {
|
||||||
|
long10
|
||||||
|
t0=new long10(),
|
||||||
|
t1=new long10(),
|
||||||
|
t2=new long10(),
|
||||||
|
t3=new long10(),
|
||||||
|
t4=new long10();
|
||||||
|
int i;
|
||||||
|
/* the chain for x^(2^255-21) is straight from djb's implementation */
|
||||||
|
sqr(t1, x); /* 2 == 2 * 1 */
|
||||||
|
sqr(t2, t1); /* 4 == 2 * 2 */
|
||||||
|
sqr(t0, t2); /* 8 == 2 * 4 */
|
||||||
|
mul(t2, t0, x); /* 9 == 8 + 1 */
|
||||||
|
mul(t0, t2, t1); /* 11 == 9 + 2 */
|
||||||
|
sqr(t1, t0); /* 22 == 2 * 11 */
|
||||||
|
mul(t3, t1, t2); /* 31 == 22 + 9
|
||||||
|
== 2^5 - 2^0 */
|
||||||
|
sqr(t1, t3); /* 2^6 - 2^1 */
|
||||||
|
sqr(t2, t1); /* 2^7 - 2^2 */
|
||||||
|
sqr(t1, t2); /* 2^8 - 2^3 */
|
||||||
|
sqr(t2, t1); /* 2^9 - 2^4 */
|
||||||
|
sqr(t1, t2); /* 2^10 - 2^5 */
|
||||||
|
mul(t2, t1, t3); /* 2^10 - 2^0 */
|
||||||
|
sqr(t1, t2); /* 2^11 - 2^1 */
|
||||||
|
sqr(t3, t1); /* 2^12 - 2^2 */
|
||||||
|
for (i = 1; i < 5; i++) {
|
||||||
|
sqr(t1, t3);
|
||||||
|
sqr(t3, t1);
|
||||||
|
} /* t3 */ /* 2^20 - 2^10 */
|
||||||
|
mul(t1, t3, t2); /* 2^20 - 2^0 */
|
||||||
|
sqr(t3, t1); /* 2^21 - 2^1 */
|
||||||
|
sqr(t4, t3); /* 2^22 - 2^2 */
|
||||||
|
for (i = 1; i < 10; i++) {
|
||||||
|
sqr(t3, t4);
|
||||||
|
sqr(t4, t3);
|
||||||
|
} /* t4 */ /* 2^40 - 2^20 */
|
||||||
|
mul(t3, t4, t1); /* 2^40 - 2^0 */
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
sqr(t1, t3);
|
||||||
|
sqr(t3, t1);
|
||||||
|
} /* t3 */ /* 2^50 - 2^10 */
|
||||||
|
mul(t1, t3, t2); /* 2^50 - 2^0 */
|
||||||
|
sqr(t2, t1); /* 2^51 - 2^1 */
|
||||||
|
sqr(t3, t2); /* 2^52 - 2^2 */
|
||||||
|
for (i = 1; i < 25; i++) {
|
||||||
|
sqr(t2, t3);
|
||||||
|
sqr(t3, t2);
|
||||||
|
} /* t3 */ /* 2^100 - 2^50 */
|
||||||
|
mul(t2, t3, t1); /* 2^100 - 2^0 */
|
||||||
|
sqr(t3, t2); /* 2^101 - 2^1 */
|
||||||
|
sqr(t4, t3); /* 2^102 - 2^2 */
|
||||||
|
for (i = 1; i < 50; i++) {
|
||||||
|
sqr(t3, t4);
|
||||||
|
sqr(t4, t3);
|
||||||
|
} /* t4 */ /* 2^200 - 2^100 */
|
||||||
|
mul(t3, t4, t2); /* 2^200 - 2^0 */
|
||||||
|
for (i = 0; i < 25; i++) {
|
||||||
|
sqr(t4, t3);
|
||||||
|
sqr(t3, t4);
|
||||||
|
} /* t3 */ /* 2^250 - 2^50 */
|
||||||
|
mul(t2, t3, t1); /* 2^250 - 2^0 */
|
||||||
|
sqr(t1, t2); /* 2^251 - 2^1 */
|
||||||
|
sqr(t2, t1); /* 2^252 - 2^2 */
|
||||||
|
if (sqrtassist!=0) {
|
||||||
|
mul(y, x, t2); /* 2^252 - 3 */
|
||||||
|
} else {
|
||||||
|
sqr(t1, t2); /* 2^253 - 2^3 */
|
||||||
|
sqr(t2, t1); /* 2^254 - 2^4 */
|
||||||
|
sqr(t1, t2); /* 2^255 - 2^5 */
|
||||||
|
mul(y, t1, t0); /* 2^255 - 21 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* checks if x is "negative", requires reduced input */
|
||||||
|
private static final int is_negative(long10 x) {
|
||||||
|
return (int)(((is_overflow(x) || (x._9 < 0))?1:0) ^ (x._0 & 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a square root */
|
||||||
|
private static final void sqrt(long10 x, long10 u) {
|
||||||
|
long10 v=new long10(), t1=new long10(), t2=new long10();
|
||||||
|
add(t1, u, u); /* t1 = 2u */
|
||||||
|
recip(v, t1, 1); /* v = (2u)^((p-5)/8) */
|
||||||
|
sqr(x, v); /* x = v^2 */
|
||||||
|
mul(t2, t1, x); /* t2 = 2uv^2 */
|
||||||
|
t2._0--; /* t2 = 2uv^2-1 */
|
||||||
|
mul(t1, v, t2); /* t1 = v(2uv^2-1) */
|
||||||
|
mul(x, u, t1); /* x = uv(2uv^2-1) */
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************* Elliptic curve *********************/
|
||||||
|
|
||||||
|
/* y^2 = x^3 + 486662 x^2 + x over GF(2^255-19) */
|
||||||
|
|
||||||
|
/* t1 = ax + az
|
||||||
|
* t2 = ax - az */
|
||||||
|
private static final void mont_prep(long10 t1, long10 t2, long10 ax, long10 az) {
|
||||||
|
add(t1, ax, az);
|
||||||
|
sub(t2, ax, az);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A = P + Q where
|
||||||
|
* X(A) = ax/az
|
||||||
|
* X(P) = (t1+t2)/(t1-t2)
|
||||||
|
* X(Q) = (t3+t4)/(t3-t4)
|
||||||
|
* X(P-Q) = dx
|
||||||
|
* clobbers t1 and t2, preserves t3 and t4 */
|
||||||
|
private static final void mont_add(long10 t1, long10 t2, long10 t3, long10 t4,long10 ax, long10 az, long10 dx) {
|
||||||
|
mul(ax, t2, t3);
|
||||||
|
mul(az, t1, t4);
|
||||||
|
add(t1, ax, az);
|
||||||
|
sub(t2, ax, az);
|
||||||
|
sqr(ax, t1);
|
||||||
|
sqr(t1, t2);
|
||||||
|
mul(az, t1, dx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* B = 2 * Q where
|
||||||
|
* X(B) = bx/bz
|
||||||
|
* X(Q) = (t3+t4)/(t3-t4)
|
||||||
|
* clobbers t1 and t2, preserves t3 and t4 */
|
||||||
|
private static final void mont_dbl(long10 t1, long10 t2, long10 t3, long10 t4,long10 bx, long10 bz) {
|
||||||
|
sqr(t1, t3);
|
||||||
|
sqr(t2, t4);
|
||||||
|
mul(bx, t1, t2);
|
||||||
|
sub(t2, t1, t2);
|
||||||
|
mul_small(bz, t2, 121665);
|
||||||
|
add(t1, t1, bz);
|
||||||
|
mul(bz, t1, t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Y^2 = X^3 + 486662 X^2 + X
|
||||||
|
* t is a temporary */
|
||||||
|
private static final void x_to_y2(long10 t, long10 y2, long10 x) {
|
||||||
|
sqr(t, x);
|
||||||
|
mul_small(y2, x, 486662);
|
||||||
|
add(t, t, y2);
|
||||||
|
t._0++;
|
||||||
|
mul(y2, t, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* P = kG and s = sign(P)/k */
|
||||||
|
private static final void core(byte[] Px, byte[] s, byte[] k, byte[] Gx) {
|
||||||
|
long10
|
||||||
|
dx=new long10(),
|
||||||
|
t1=new long10(),
|
||||||
|
t2=new long10(),
|
||||||
|
t3=new long10(),
|
||||||
|
t4=new long10();
|
||||||
|
long10[]
|
||||||
|
x=new long10[]{new long10(),new long10()},
|
||||||
|
z=new long10[]{new long10(),new long10()};
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/* unpack the base */
|
||||||
|
if (Gx!=null)
|
||||||
|
unpack(dx, Gx);
|
||||||
|
else
|
||||||
|
set(dx, 9);
|
||||||
|
|
||||||
|
/* 0G = point-at-infinity */
|
||||||
|
set(x[0], 1);
|
||||||
|
set(z[0], 0);
|
||||||
|
|
||||||
|
/* 1G = G */
|
||||||
|
cpy(x[1], dx);
|
||||||
|
set(z[1], 1);
|
||||||
|
|
||||||
|
for (i = 32; i--!=0; ) {
|
||||||
|
if (i==0) {
|
||||||
|
i=0;
|
||||||
|
}
|
||||||
|
for (j = 8; j--!=0; ) {
|
||||||
|
/* swap arguments depending on bit */
|
||||||
|
int bit1 = (k[i] & 0xFF) >> j & 1;
|
||||||
|
int bit0 = ~(k[i] & 0xFF) >> j & 1;
|
||||||
|
long10 ax = x[bit0];
|
||||||
|
long10 az = z[bit0];
|
||||||
|
long10 bx = x[bit1];
|
||||||
|
long10 bz = z[bit1];
|
||||||
|
|
||||||
|
/* a' = a + b */
|
||||||
|
/* b' = 2 b */
|
||||||
|
mont_prep(t1, t2, ax, az);
|
||||||
|
mont_prep(t3, t4, bx, bz);
|
||||||
|
mont_add(t1, t2, t3, t4, ax, az, dx);
|
||||||
|
mont_dbl(t1, t2, t3, t4, bx, bz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recip(t1, z[0], 0);
|
||||||
|
mul(dx, x[0], t1);
|
||||||
|
pack(dx, Px);
|
||||||
|
|
||||||
|
/* calculate s such that s abs(P) = G .. assumes G is std base point */
|
||||||
|
if (s!=null) {
|
||||||
|
x_to_y2(t2, t1, dx); /* t1 = Py^2 */
|
||||||
|
recip(t3, z[1], 0); /* where Q=P+G ... */
|
||||||
|
mul(t2, x[1], t3); /* t2 = Qx */
|
||||||
|
add(t2, t2, dx); /* t2 = Qx + Px */
|
||||||
|
t2._0 += 9 + 486662; /* t2 = Qx + Px + Gx + 486662 */
|
||||||
|
dx._0 -= 9; /* dx = Px - Gx */
|
||||||
|
sqr(t3, dx); /* t3 = (Px - Gx)^2 */
|
||||||
|
mul(dx, t2, t3); /* dx = t2 (Px - Gx)^2 */
|
||||||
|
sub(dx, dx, t1); /* dx = t2 (Px - Gx)^2 - Py^2 */
|
||||||
|
dx._0 -= 39420360; /* dx = t2 (Px - Gx)^2 - Py^2 - Gy^2 */
|
||||||
|
mul(t1, dx, BASE_R2Y); /* t1 = -Py */
|
||||||
|
if (is_negative(t1)!=0) /* sign is 1, so just copy */
|
||||||
|
cpy32(s, k);
|
||||||
|
else /* sign is -1, so negate */
|
||||||
|
mula_small(s, ORDER_TIMES_8, 0, k, 32, -1);
|
||||||
|
|
||||||
|
/* reduce s mod q
|
||||||
|
* (is this needed? do it just in case, it's fast anyway) */
|
||||||
|
//divmod((dstptr) t1, s, 32, order25519, 32);
|
||||||
|
|
||||||
|
/* take reciprocal of s mod q */
|
||||||
|
byte[] temp1=new byte[32];
|
||||||
|
byte[] temp2=new byte[64];
|
||||||
|
byte[] temp3=new byte[64];
|
||||||
|
cpy32(temp1, ORDER);
|
||||||
|
cpy32(s, egcd32(temp2, temp3, s, temp1));
|
||||||
|
if ((s[31] & 0x80)!=0)
|
||||||
|
mula_small(s, s, 0, ORDER, 32, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* smallest multiple of the order that's >= 2^255 */
|
||||||
|
private static final byte[] ORDER_TIMES_8 = {
|
||||||
|
(byte)104, (byte)159, (byte)174, (byte)231,
|
||||||
|
(byte)210, (byte)24, (byte)147, (byte)192,
|
||||||
|
(byte)178, (byte)230, (byte)188, (byte)23,
|
||||||
|
(byte)245, (byte)206, (byte)247, (byte)166,
|
||||||
|
(byte)0, (byte)0, (byte)0, (byte)0,
|
||||||
|
(byte)0, (byte)0, (byte)0, (byte)0,
|
||||||
|
(byte)0, (byte)0, (byte)0, (byte)0,
|
||||||
|
(byte)0, (byte)0, (byte)0, (byte)128
|
||||||
|
};
|
||||||
|
|
||||||
|
/* constants 2Gy and 1/(2Gy) */
|
||||||
|
private static final long10 BASE_2Y = new long10(
|
||||||
|
39999547, 18689728, 59995525, 1648697, 57546132,
|
||||||
|
24010086, 19059592, 5425144, 63499247, 16420658
|
||||||
|
);
|
||||||
|
private static final long10 BASE_R2Y = new long10(
|
||||||
|
5744, 8160848, 4790893, 13779497, 35730846,
|
||||||
|
12541209, 49101323, 30047407, 40071253, 6226132
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -18,6 +18,8 @@ package net.schmizz.concurrent;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event can be set, cleared, or awaited, similar to Python's {@code threading.event}. The key difference is that a
|
* An event can be set, cleared, or awaited, similar to Python's {@code threading.event}. The key difference is that a
|
||||||
* waiter may be delivered an exception of parameterized type {@code T}.
|
* waiter may be delivered an exception of parameterized type {@code T}.
|
||||||
@@ -42,8 +44,8 @@ public class Event<T extends Throwable> {
|
|||||||
* @param name name of this event
|
* @param name name of this event
|
||||||
* @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
|
* @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
|
||||||
*/
|
*/
|
||||||
public Event(String name, ExceptionChainer<T> chainer) {
|
public Event(String name, ExceptionChainer<T> chainer, LoggerFactory loggerFactory) {
|
||||||
promise = new Promise<Object, T>(name, chainer);
|
promise = new Promise<Object, T>(name, chainer, loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,8 +55,8 @@ public class Event<T extends Throwable> {
|
|||||||
* @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
|
* @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
|
||||||
* @param lock lock to use
|
* @param lock lock to use
|
||||||
*/
|
*/
|
||||||
public Event(String name, ExceptionChainer<T> chainer, ReentrantLock lock) {
|
public Event(String name, ExceptionChainer<T> chainer, ReentrantLock lock, LoggerFactory loggerFactory) {
|
||||||
promise = new Promise<Object, T>(name, chainer, lock);
|
promise = new Promise<Object, T>(name, chainer, lock, loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets this event to be {@code true}. Short for {@code set(true)}. */
|
/** Sets this event to be {@code true}. Short for {@code set(true)}. */
|
||||||
@@ -143,4 +145,4 @@ public class Event<T extends Throwable> {
|
|||||||
return promise.toString();
|
return promise.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -37,4 +37,4 @@ public interface ExceptionChainer<Z extends Throwable> {
|
|||||||
|
|
||||||
Z chain(Throwable t);
|
Z chain(Throwable t);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,13 +16,14 @@
|
|||||||
package net.schmizz.concurrent;
|
package net.schmizz.concurrent;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.locks.Condition;
|
import java.util.concurrent.locks.Condition;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents promised data of the parameterized type {@code V} and allows waiting on it. An exception may also be
|
* Represents promised data of the parameterized type {@code V} and allows waiting on it. An exception may also be
|
||||||
* delivered to a waiter, and will be of the parameterized type {@code T}.
|
* delivered to a waiter, and will be of the parameterized type {@code T}.
|
||||||
@@ -32,8 +33,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
*/
|
*/
|
||||||
public class Promise<V, T extends Throwable> {
|
public class Promise<V, T extends Throwable> {
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private final Logger log;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final ExceptionChainer<T> chainer;
|
private final ExceptionChainer<T> chainer;
|
||||||
private final ReentrantLock lock;
|
private final ReentrantLock lock;
|
||||||
@@ -49,8 +49,8 @@ public class Promise<V, T extends Throwable> {
|
|||||||
* @param name name of this promise
|
* @param name name of this promise
|
||||||
* @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
|
* @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
|
||||||
*/
|
*/
|
||||||
public Promise(String name, ExceptionChainer<T> chainer) {
|
public Promise(String name, ExceptionChainer<T> chainer, LoggerFactory loggerFactory) {
|
||||||
this(name, chainer, null);
|
this(name, chainer, null, loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,10 +60,11 @@ public class Promise<V, T extends Throwable> {
|
|||||||
* @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
|
* @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
|
||||||
* @param lock lock to use
|
* @param lock lock to use
|
||||||
*/
|
*/
|
||||||
public Promise(String name, ExceptionChainer<T> chainer, ReentrantLock lock) {
|
public Promise(String name, ExceptionChainer<T> chainer, ReentrantLock lock, LoggerFactory loggerFactory) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.chainer = chainer;
|
this.chainer = chainer;
|
||||||
this.lock = lock == null ? new ReentrantLock() : lock;
|
this.lock = lock == null ? new ReentrantLock() : lock;
|
||||||
|
this.log = loggerFactory.getLogger(getClass());
|
||||||
this.cond = this.lock.newCondition();
|
this.cond = this.lock.newCondition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,11 +163,14 @@ public class Promise<V, T extends Throwable> {
|
|||||||
if (val != null)
|
if (val != null)
|
||||||
return val;
|
return val;
|
||||||
log.debug("Awaiting <<{}>>", name);
|
log.debug("Awaiting <<{}>>", name);
|
||||||
while (val == null && pendingEx == null)
|
if (timeout == 0) {
|
||||||
if (timeout == 0)
|
while (val == null && pendingEx == null) {
|
||||||
cond.await();
|
cond.await();
|
||||||
else if (!cond.await(timeout, unit))
|
}
|
||||||
|
} else {
|
||||||
|
if (!cond.await(timeout, unit))
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
if (pendingEx != null) {
|
if (pendingEx != null) {
|
||||||
log.error("<<{}>> woke to: {}", name, pendingEx.toString());
|
log.error("<<{}>> woke to: {}", name, pendingEx.toString());
|
||||||
throw pendingEx;
|
throw pendingEx;
|
||||||
@@ -199,6 +203,16 @@ public class Promise<V, T extends Throwable> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whether this promise was fulfilled with either a value or an error. */
|
||||||
|
public boolean isFulfilled() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
return pendingEx != null || val != null;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @return whether this promise has threads waiting on it. */
|
/** @return whether this promise has threads waiting on it. */
|
||||||
public boolean hasWaiters() {
|
public boolean hasWaiters() {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|||||||
34
src/main/java/net/schmizz/keepalive/Heartbeater.java
Normal file
34
src/main/java/net/schmizz/keepalive/Heartbeater.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.schmizz.keepalive;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.Message;
|
||||||
|
import net.schmizz.sshj.common.SSHPacket;
|
||||||
|
import net.schmizz.sshj.connection.ConnectionImpl;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
|
final class Heartbeater
|
||||||
|
extends KeepAlive {
|
||||||
|
|
||||||
|
Heartbeater(ConnectionImpl conn) {
|
||||||
|
super(conn, "heartbeater");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doKeepAlive() throws TransportException {
|
||||||
|
conn.getTransport().write(new SSHPacket(Message.IGNORE));
|
||||||
|
}
|
||||||
|
}
|
||||||
81
src/main/java/net/schmizz/keepalive/KeepAlive.java
Normal file
81
src/main/java/net/schmizz/keepalive/KeepAlive.java
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.schmizz.keepalive;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
|
import net.schmizz.sshj.connection.ConnectionImpl;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public abstract class KeepAlive extends Thread {
|
||||||
|
protected final Logger log;
|
||||||
|
protected final ConnectionImpl conn;
|
||||||
|
|
||||||
|
protected int keepAliveInterval = 0;
|
||||||
|
|
||||||
|
protected KeepAlive(ConnectionImpl conn, String name) {
|
||||||
|
this.conn = conn;
|
||||||
|
log = conn.getTransport().getConfig().getLoggerFactory().getLogger(getClass());
|
||||||
|
setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int getKeepAliveInterval() {
|
||||||
|
return keepAliveInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setKeepAliveInterval(int keepAliveInterval) {
|
||||||
|
this.keepAliveInterval = keepAliveInterval;
|
||||||
|
if (keepAliveInterval > 0 && getState() == State.NEW) {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized protected int getPositiveInterval()
|
||||||
|
throws InterruptedException {
|
||||||
|
while (keepAliveInterval <= 0) {
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
return keepAliveInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
log.debug("Starting {}, sending keep-alive every {} seconds", getClass().getSimpleName(), keepAliveInterval);
|
||||||
|
try {
|
||||||
|
while (!isInterrupted()) {
|
||||||
|
final int hi = getPositiveInterval();
|
||||||
|
if (conn.getTransport().isRunning()) {
|
||||||
|
log.debug("Sending keep-alive since {} seconds elapsed", hi);
|
||||||
|
doKeepAlive();
|
||||||
|
}
|
||||||
|
Thread.sleep(hi * 1000);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// If we weren't interrupted, kill the transport, then this exception was unexpected.
|
||||||
|
// Else we're in shutdown-mode already, so don't forcibly kill the transport.
|
||||||
|
if (!isInterrupted()) {
|
||||||
|
conn.getTransport().die(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Stopping {}", getClass().getSimpleName());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doKeepAlive() throws TransportException, ConnectionException;
|
||||||
|
}
|
||||||
39
src/main/java/net/schmizz/keepalive/KeepAliveProvider.java
Normal file
39
src/main/java/net/schmizz/keepalive/KeepAliveProvider.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.schmizz.keepalive;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.connection.ConnectionImpl;
|
||||||
|
|
||||||
|
public abstract class KeepAliveProvider {
|
||||||
|
|
||||||
|
public static final KeepAliveProvider HEARTBEAT = new KeepAliveProvider() {
|
||||||
|
@Override
|
||||||
|
public KeepAlive provide(ConnectionImpl connection) {
|
||||||
|
return new Heartbeater(connection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final KeepAliveProvider KEEP_ALIVE = new KeepAliveProvider() {
|
||||||
|
@Override
|
||||||
|
public KeepAlive provide(ConnectionImpl connection) {
|
||||||
|
return new KeepAliveRunner(connection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public abstract KeepAlive provide(ConnectionImpl connection);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
76
src/main/java/net/schmizz/keepalive/KeepAliveRunner.java
Normal file
76
src/main/java/net/schmizz/keepalive/KeepAliveRunner.java
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.schmizz.keepalive;
|
||||||
|
|
||||||
|
import net.schmizz.concurrent.Promise;
|
||||||
|
import net.schmizz.sshj.common.SSHPacket;
|
||||||
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
|
import net.schmizz.sshj.connection.ConnectionImpl;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
import static net.schmizz.sshj.common.DisconnectReason.CONNECTION_LOST;
|
||||||
|
|
||||||
|
public class KeepAliveRunner extends KeepAlive {
|
||||||
|
|
||||||
|
/** The max number of keep-alives that should be unanswered before killing the connection. */
|
||||||
|
private int maxAliveCount = 5;
|
||||||
|
|
||||||
|
/** The queue of promises. */
|
||||||
|
private final Queue<Promise<SSHPacket, ConnectionException>> queue =
|
||||||
|
new LinkedList<Promise<SSHPacket, ConnectionException>>();
|
||||||
|
|
||||||
|
KeepAliveRunner(ConnectionImpl conn) {
|
||||||
|
super(conn, "keep-alive");
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public int getMaxAliveCount() {
|
||||||
|
return maxAliveCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized public void setMaxAliveCount(int maxAliveCount) {
|
||||||
|
this.maxAliveCount = maxAliveCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doKeepAlive() throws TransportException, ConnectionException {
|
||||||
|
// Ensure the service is set... This means that the key exchange is done and the connection is up.
|
||||||
|
if (conn.equals(conn.getTransport().getService())) {
|
||||||
|
emptyQueue(queue);
|
||||||
|
checkMaxReached(queue);
|
||||||
|
queue.add(conn.sendGlobalRequest("keepalive@openssh.com", true, new byte[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkMaxReached(Queue<Promise<SSHPacket, ConnectionException>> queue) throws ConnectionException {
|
||||||
|
if (queue.size() >= maxAliveCount) {
|
||||||
|
throw new ConnectionException(CONNECTION_LOST,
|
||||||
|
format("Did not receive any keep-alive response for %s seconds", maxAliveCount * keepAliveInterval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void emptyQueue(Queue<Promise<SSHPacket, ConnectionException>> queue) {
|
||||||
|
Promise<SSHPacket, ConnectionException> peek = queue.peek();
|
||||||
|
while (peek != null && peek.isFulfilled()) {
|
||||||
|
log.debug("Received response from server to our keep-alive.");
|
||||||
|
queue.remove();
|
||||||
|
peek = queue.peek();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -22,26 +22,23 @@ import net.schmizz.sshj.common.SSHPacket;
|
|||||||
import net.schmizz.sshj.transport.Transport;
|
import net.schmizz.sshj.transport.Transport;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/** An abstract class for {@link Service} that implements common or default functionality. */
|
/** An abstract class for {@link Service} that implements common or default functionality. */
|
||||||
public abstract class AbstractService
|
public abstract class AbstractService
|
||||||
implements Service {
|
implements Service {
|
||||||
|
|
||||||
/** Logger */
|
/** Logger */
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log;
|
||||||
|
|
||||||
/** Assigned name of this service */
|
/** Assigned name of this service */
|
||||||
protected final String name;
|
protected final String name;
|
||||||
/** Transport layer */
|
/** Transport layer */
|
||||||
protected final Transport trans;
|
protected final Transport trans;
|
||||||
/** Timeout for blocking operations */
|
|
||||||
protected int timeout;
|
|
||||||
|
|
||||||
public AbstractService(String name, Transport trans) {
|
public AbstractService(String name, Transport trans) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.trans = trans;
|
this.trans = trans;
|
||||||
timeout = trans.getTimeout();
|
log = trans.getConfig().getLoggerFactory().getLogger(getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -77,12 +74,6 @@ public abstract class AbstractService
|
|||||||
trans.reqService(this);
|
trans.reqService(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTimeout() {
|
|
||||||
return this.timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimeout(int timeout) {
|
|
||||||
this.timeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,12 +15,24 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.SecurityUtils;
|
||||||
|
import net.schmizz.sshj.signature.SignatureDSA;
|
||||||
|
import net.schmizz.sshj.signature.SignatureRSA;
|
||||||
import net.schmizz.sshj.transport.random.JCERandom;
|
import net.schmizz.sshj.transport.random.JCERandom;
|
||||||
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
||||||
|
|
||||||
public class AndroidConfig
|
public class AndroidConfig
|
||||||
extends DefaultConfig {
|
extends DefaultConfig {
|
||||||
|
|
||||||
|
static {
|
||||||
|
SecurityUtils.registerSecurityProvider("org.spongycastle.jce.provider.BouncyCastleProvider");
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't add ECDSA
|
||||||
|
protected void initSignatureFactories() {
|
||||||
|
setSignatureFactories(new SignatureRSA.Factory(), new SignatureDSA.Factory());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initRandomFactory(boolean ignored) {
|
protected void initRandomFactory(boolean ignored) {
|
||||||
setRandomFactory(new SingletonRandomFactory(new JCERandom.Factory()));
|
setRandomFactory(new SingletonRandomFactory(new JCERandom.Factory()));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,7 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
|
import net.schmizz.keepalive.KeepAliveProvider;
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.sshj.signature.Signature;
|
import net.schmizz.sshj.signature.Signature;
|
||||||
import net.schmizz.sshj.transport.cipher.Cipher;
|
import net.schmizz.sshj.transport.cipher.Cipher;
|
||||||
import net.schmizz.sshj.transport.compression.Compression;
|
import net.schmizz.sshj.transport.compression.Compression;
|
||||||
@@ -54,16 +56,16 @@ public interface Config {
|
|||||||
List<Factory.Named<FileKeyProvider>> getFileKeyProviderFactories();
|
List<Factory.Named<FileKeyProvider>> getFileKeyProviderFactories();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the list of named factories for <code>KeyExchange</code>.
|
* Retrieve the list of named factories for {@code KeyExchange}.
|
||||||
*
|
*
|
||||||
* @return a list of named <code>KeyExchange</code> factories
|
* @return a list of named {@code KeyExchange} factories
|
||||||
*/
|
*/
|
||||||
List<Factory.Named<KeyExchange>> getKeyExchangeFactories();
|
List<Factory.Named<KeyExchange>> getKeyExchangeFactories();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the list of named factories for <code>MAC</code>.
|
* Retrieve the list of named factories for {@code MAC}.
|
||||||
*
|
*
|
||||||
* @return a list of named <code>MAC</code> factories
|
* @return a list of named {@code MAC} factories
|
||||||
*/
|
*/
|
||||||
List<Factory.Named<MAC>> getMACFactories();
|
List<Factory.Named<MAC>> getMACFactories();
|
||||||
|
|
||||||
@@ -144,4 +146,44 @@ public interface Config {
|
|||||||
*/
|
*/
|
||||||
void setVersion(String version);
|
void setVersion(String version);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The provider that creates the keep-alive implementation of choice.
|
||||||
|
*/
|
||||||
|
KeepAliveProvider getKeepAliveProvider();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the provider that provides the keep-alive implementation.
|
||||||
|
* @param keepAliveProvider keep-alive provider
|
||||||
|
*/
|
||||||
|
void setKeepAliveProvider(KeepAliveProvider keepAliveProvider);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether the client should first wait for a received server ident, before sending the client ident.
|
||||||
|
* <p/>
|
||||||
|
* <stong>NB:</stong> This is non-standard behaviour, and can potentially deadlock if the server also waits on the client ident.
|
||||||
|
*
|
||||||
|
* The default value is set to false.
|
||||||
|
*
|
||||||
|
* @return Whether to first wait for the server ident.
|
||||||
|
*/
|
||||||
|
boolean isWaitForServerIdentBeforeSendingClientIdent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the SSH client should wait for a received server ident, before sending the client ident.
|
||||||
|
* <p/>
|
||||||
|
* <stong>NB:</stong> This is non-standard behaviour, and can potentially deadlock if the server also waits on the client ident.
|
||||||
|
|
||||||
|
* @param waitForServerIdentBeforeSendingClientIdent Whether to wait for the server ident.
|
||||||
|
*/
|
||||||
|
void setWaitForServerIdentBeforeSendingClientIdent(boolean waitForServerIdentBeforeSendingClientIdent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the LoggerFactory to use.
|
||||||
|
*/
|
||||||
|
void setLoggerFactory(LoggerFactory loggerFactory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The LoggerFactory the SSHClient will use.
|
||||||
|
*/
|
||||||
|
LoggerFactory getLoggerFactory();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,29 +12,11 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
|
import net.schmizz.keepalive.KeepAliveProvider;
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
import net.schmizz.sshj.signature.Signature;
|
import net.schmizz.sshj.signature.Signature;
|
||||||
import net.schmizz.sshj.transport.cipher.Cipher;
|
import net.schmizz.sshj.transport.cipher.Cipher;
|
||||||
@@ -54,6 +36,7 @@ public class ConfigImpl
|
|||||||
private String version;
|
private String version;
|
||||||
|
|
||||||
private Factory<Random> randomFactory;
|
private Factory<Random> randomFactory;
|
||||||
|
private KeepAliveProvider keepAliveProvider;
|
||||||
|
|
||||||
private List<Factory.Named<KeyExchange>> kexFactories;
|
private List<Factory.Named<KeyExchange>> kexFactories;
|
||||||
private List<Factory.Named<Cipher>> cipherFactories;
|
private List<Factory.Named<Cipher>> cipherFactories;
|
||||||
@@ -62,6 +45,9 @@ public class ConfigImpl
|
|||||||
private List<Factory.Named<Signature>> signatureFactories;
|
private List<Factory.Named<Signature>> signatureFactories;
|
||||||
private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories;
|
private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories;
|
||||||
|
|
||||||
|
private boolean waitForServerIdentBeforeSendingClientIdent = false;
|
||||||
|
private LoggerFactory loggerFactory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Factory.Named<Cipher>> getCipherFactories() {
|
public List<Factory.Named<Cipher>> getCipherFactories() {
|
||||||
return cipherFactories;
|
return cipherFactories;
|
||||||
@@ -166,4 +152,33 @@ public class ConfigImpl
|
|||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public KeepAliveProvider getKeepAliveProvider() {
|
||||||
|
return keepAliveProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setKeepAliveProvider(KeepAliveProvider keepAliveProvider) {
|
||||||
|
this.keepAliveProvider = keepAliveProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWaitForServerIdentBeforeSendingClientIdent() {
|
||||||
|
return waitForServerIdentBeforeSendingClientIdent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWaitForServerIdentBeforeSendingClientIdent(boolean waitForServerIdentBeforeSendingClientIdent) {
|
||||||
|
this.waitForServerIdentBeforeSendingClientIdent = waitForServerIdentBeforeSendingClientIdent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoggerFactory getLoggerFactory() {
|
||||||
|
return loggerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLoggerFactory(LoggerFactory loggerFactory) {
|
||||||
|
this.loggerFactory = loggerFactory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,76 +12,53 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
|
import com.hierynomus.sshj.signature.SignatureEdDSA;
|
||||||
|
import com.hierynomus.sshj.transport.cipher.BlockCiphers;
|
||||||
|
import com.hierynomus.sshj.transport.cipher.StreamCiphers;
|
||||||
|
import net.schmizz.keepalive.KeepAliveProvider;
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.sshj.common.SecurityUtils;
|
import net.schmizz.sshj.common.SecurityUtils;
|
||||||
import net.schmizz.sshj.signature.SignatureDSA;
|
import net.schmizz.sshj.signature.SignatureDSA;
|
||||||
|
import net.schmizz.sshj.signature.SignatureECDSA;
|
||||||
import net.schmizz.sshj.signature.SignatureRSA;
|
import net.schmizz.sshj.signature.SignatureRSA;
|
||||||
import net.schmizz.sshj.transport.cipher.AES128CBC;
|
import net.schmizz.sshj.transport.cipher.*;
|
||||||
import net.schmizz.sshj.transport.cipher.AES128CTR;
|
|
||||||
import net.schmizz.sshj.transport.cipher.AES192CBC;
|
|
||||||
import net.schmizz.sshj.transport.cipher.AES192CTR;
|
|
||||||
import net.schmizz.sshj.transport.cipher.AES256CBC;
|
|
||||||
import net.schmizz.sshj.transport.cipher.AES256CTR;
|
|
||||||
import net.schmizz.sshj.transport.cipher.BlowfishCBC;
|
|
||||||
import net.schmizz.sshj.transport.cipher.Cipher;
|
|
||||||
import net.schmizz.sshj.transport.cipher.TripleDESCBC;
|
|
||||||
import net.schmizz.sshj.transport.compression.NoneCompression;
|
import net.schmizz.sshj.transport.compression.NoneCompression;
|
||||||
import net.schmizz.sshj.transport.kex.DHG1;
|
import net.schmizz.sshj.transport.kex.*;
|
||||||
import net.schmizz.sshj.transport.kex.DHG14;
|
import net.schmizz.sshj.transport.mac.*;
|
||||||
import net.schmizz.sshj.transport.mac.HMACMD5;
|
|
||||||
import net.schmizz.sshj.transport.mac.HMACMD596;
|
|
||||||
import net.schmizz.sshj.transport.mac.HMACSHA1;
|
|
||||||
import net.schmizz.sshj.transport.mac.HMACSHA196;
|
|
||||||
import net.schmizz.sshj.transport.random.BouncyCastleRandom;
|
import net.schmizz.sshj.transport.random.BouncyCastleRandom;
|
||||||
import net.schmizz.sshj.transport.random.JCERandom;
|
import net.schmizz.sshj.transport.random.JCERandom;
|
||||||
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
|
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
|
||||||
|
import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
|
import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
|
||||||
|
import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.io.IOException;
|
||||||
import java.util.Iterator;
|
import java.util.*;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Config} that is initialized as follows. Items marked with an asterisk are added to the config only if
|
* A {@link net.schmizz.sshj.Config} that is initialized as follows. Items marked with an asterisk are added to the config only if
|
||||||
* BouncyCastle is in the classpath.
|
* BouncyCastle is in the classpath.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <ul> <li>{@link ConfigImpl#setKeyExchangeFactories Key exchange}: {@link DHG14}*, {@link DHG1}</li> <li>{@link
|
* <ul>
|
||||||
* ConfigImpl#setCipherFactories Ciphers} [1]: {@link AES128CTR}, {@link AES192CTR}, {@link AES256CTR}, {@link
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setKeyExchangeFactories Key exchange}: {@link net.schmizz.sshj.transport.kex.DHG14}*, {@link net.schmizz.sshj.transport.kex.DHG1}</li>
|
||||||
* AES128CBC}, {@link AES192CBC}, {@link AES256CBC}, {@link AES192CBC}, {@link TripleDESCBC}, {@link BlowfishCBC}</li>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setCipherFactories Ciphers} [1]: {@link net.schmizz.sshj.transport.cipher.AES128CTR}, {@link net.schmizz.sshj.transport.cipher.AES192CTR}, {@link net.schmizz.sshj.transport.cipher.AES256CTR},
|
||||||
* <li>{@link ConfigImpl#setMACFactories MAC}: {@link HMACSHA1}, {@link HMACSHA196}, {@link HMACMD5}, {@link
|
* {@link
|
||||||
* HMACMD596}</li> <li>{@link ConfigImpl#setCompressionFactories Compression}: {@link NoneCompression}</li> <li>{@link
|
* net.schmizz.sshj.transport.cipher.AES128CBC}, {@link net.schmizz.sshj.transport.cipher.AES192CBC}, {@link net.schmizz.sshj.transport.cipher.AES256CBC}, {@link net.schmizz.sshj.transport.cipher.AES192CBC}, {@link net.schmizz.sshj.transport.cipher.TripleDESCBC}, {@link net.schmizz.sshj.transport.cipher.BlowfishCBC}</li>
|
||||||
* ConfigImpl#setSignatureFactories Signature}: {@link SignatureRSA}, {@link SignatureDSA}</li> <li>{@link
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setMACFactories MAC}: {@link net.schmizz.sshj.transport.mac.HMACSHA1}, {@link net.schmizz.sshj.transport.mac.HMACSHA196}, {@link net.schmizz.sshj.transport.mac.HMACMD5}, {@link
|
||||||
* ConfigImpl#setRandomFactory PRNG}: {@link BouncyCastleRandom}* or {@link JCERandom}</li> <li>{@link
|
* net.schmizz.sshj.transport.mac.HMACMD596}</li>
|
||||||
* ConfigImpl#setFileKeyProviderFactories Key file support}: {@link PKCS8KeyFile}*, {@link OpenSSHKeyFile}*</li>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setCompressionFactories Compression}: {@link net.schmizz.sshj.transport.compression.NoneCompression}</li>
|
||||||
* <li>{@link ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li> </ul>
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setSignatureFactories Signature}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}</li>
|
||||||
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setRandomFactory PRNG}: {@link net.schmizz.sshj.transport.random.BouncyCastleRandom}* or {@link net.schmizz.sshj.transport.random.JCERandom}</li>
|
||||||
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setFileKeyProviderFactories Key file support}: {@link net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile}*, {@link
|
||||||
|
* net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile}*</li>
|
||||||
|
* <li>{@link net.schmizz.sshj.ConfigImpl#setVersion Client version}: {@code "NET_3_0"}</li>
|
||||||
|
* </ul>
|
||||||
* <p/>
|
* <p/>
|
||||||
* [1] It is worth noting that Sun's JRE does not have the unlimited cryptography extension enabled by default. This
|
* [1] It is worth noting that Sun's JRE does not have the unlimited cryptography extension enabled by default. This
|
||||||
* prevents using ciphers with strength greater than 128.
|
* prevents using ciphers with strength greater than 128.
|
||||||
@@ -89,12 +66,11 @@ import java.util.List;
|
|||||||
public class DefaultConfig
|
public class DefaultConfig
|
||||||
extends ConfigImpl {
|
extends ConfigImpl {
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private Logger log;
|
||||||
|
|
||||||
private static final String VERSION = "SSHJ_0_4_1";
|
|
||||||
|
|
||||||
public DefaultConfig() {
|
public DefaultConfig() {
|
||||||
setVersion(VERSION);
|
setLoggerFactory(LoggerFactory.DEFAULT);
|
||||||
|
setVersion(readVersionFromProperties());
|
||||||
final boolean bouncyCastleRegistered = SecurityUtils.isBouncyCastleRegistered();
|
final boolean bouncyCastleRegistered = SecurityUtils.isBouncyCastleRegistered();
|
||||||
initKeyExchangeFactories(bouncyCastleRegistered);
|
initKeyExchangeFactories(bouncyCastleRegistered);
|
||||||
initRandomFactory(bouncyCastleRegistered);
|
initRandomFactory(bouncyCastleRegistered);
|
||||||
@@ -103,22 +79,50 @@ public class DefaultConfig
|
|||||||
initCompressionFactories();
|
initCompressionFactories();
|
||||||
initMACFactories();
|
initMACFactories();
|
||||||
initSignatureFactories();
|
initSignatureFactories();
|
||||||
|
setKeepAliveProvider(KeepAliveProvider.HEARTBEAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readVersionFromProperties() {
|
||||||
|
try {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("sshj.properties"));
|
||||||
|
String property = properties.getProperty("sshj.version");
|
||||||
|
return "SSHJ_" + property.replace('-', '_'); // '-' is a disallowed character, see RFC-4253#section-4.2
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Could not read the sshj.properties file, returning an 'unknown' version as fallback.");
|
||||||
|
return "SSHJ_VERSION_UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLoggerFactory(LoggerFactory loggerFactory) {
|
||||||
|
super.setLoggerFactory(loggerFactory);
|
||||||
|
log = loggerFactory.getLogger(getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) {
|
protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) {
|
||||||
if (bouncyCastleRegistered)
|
if (bouncyCastleRegistered) {
|
||||||
setKeyExchangeFactories(new DHG14.Factory(), new DHG1.Factory());
|
setKeyExchangeFactories(new Curve25519SHA256.Factory(),
|
||||||
else
|
new DHGexSHA256.Factory(),
|
||||||
setKeyExchangeFactories(new DHG1.Factory());
|
new ECDHNistP.Factory521(),
|
||||||
|
new ECDHNistP.Factory384(),
|
||||||
|
new ECDHNistP.Factory256(),
|
||||||
|
new DHGexSHA1.Factory(),
|
||||||
|
new DHG14.Factory(),
|
||||||
|
new DHG1.Factory());
|
||||||
|
} else {
|
||||||
|
setKeyExchangeFactories(new DHG1.Factory(), new DHGexSHA1.Factory());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initRandomFactory(boolean bouncyCastleRegistered) {
|
protected void initRandomFactory(boolean bouncyCastleRegistered) {
|
||||||
setRandomFactory(new SingletonRandomFactory(bouncyCastleRegistered ? new BouncyCastleRandom.Factory() : new JCERandom.Factory()));
|
setRandomFactory(new SingletonRandomFactory(bouncyCastleRegistered
|
||||||
|
? new BouncyCastleRandom.Factory() : new JCERandom.Factory()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) {
|
protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) {
|
||||||
if (bouncyCastleRegistered) {
|
if (bouncyCastleRegistered) {
|
||||||
setFileKeyProviderFactories(new PKCS8KeyFile.Factory(), new OpenSSHKeyFile.Factory());
|
setFileKeyProviderFactories(new OpenSSHKeyV1KeyFile.Factory(), new PKCS8KeyFile.Factory(), new OpenSSHKeyFile.Factory(), new PuTTYKeyFile.Factory());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +136,30 @@ public class DefaultConfig
|
|||||||
new AES192CBC.Factory(),
|
new AES192CBC.Factory(),
|
||||||
new AES256CBC.Factory(),
|
new AES256CBC.Factory(),
|
||||||
new TripleDESCBC.Factory(),
|
new TripleDESCBC.Factory(),
|
||||||
new BlowfishCBC.Factory()));
|
new BlowfishCBC.Factory(),
|
||||||
|
BlockCiphers.BlowfishCTR(),
|
||||||
|
BlockCiphers.Cast128CBC(),
|
||||||
|
BlockCiphers.Cast128CTR(),
|
||||||
|
BlockCiphers.IDEACBC(),
|
||||||
|
BlockCiphers.IDEACTR(),
|
||||||
|
BlockCiphers.Serpent128CBC(),
|
||||||
|
BlockCiphers.Serpent128CTR(),
|
||||||
|
BlockCiphers.Serpent192CBC(),
|
||||||
|
BlockCiphers.Serpent192CTR(),
|
||||||
|
BlockCiphers.Serpent256CBC(),
|
||||||
|
BlockCiphers.Serpent256CTR(),
|
||||||
|
BlockCiphers.TripleDESCTR(),
|
||||||
|
BlockCiphers.Twofish128CBC(),
|
||||||
|
BlockCiphers.Twofish128CTR(),
|
||||||
|
BlockCiphers.Twofish192CBC(),
|
||||||
|
BlockCiphers.Twofish192CTR(),
|
||||||
|
BlockCiphers.Twofish256CBC(),
|
||||||
|
BlockCiphers.Twofish256CTR(),
|
||||||
|
BlockCiphers.TwofishCBC(),
|
||||||
|
StreamCiphers.Arcfour(),
|
||||||
|
StreamCiphers.Arcfour128(),
|
||||||
|
StreamCiphers.Arcfour256())
|
||||||
|
);
|
||||||
|
|
||||||
boolean warn = false;
|
boolean warn = false;
|
||||||
// Ref. https://issues.apache.org/jira/browse/SSHD-24
|
// Ref. https://issues.apache.org/jira/browse/SSHD-24
|
||||||
@@ -146,6 +173,7 @@ public class DefaultConfig
|
|||||||
c.init(Cipher.Mode.Encrypt, key, iv);
|
c.init(Cipher.Mode.Encrypt, key, iv);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
warn = true;
|
warn = true;
|
||||||
|
log.warn(e.getCause().getMessage());
|
||||||
i.remove();
|
i.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,20 +181,30 @@ public class DefaultConfig
|
|||||||
log.warn("Disabling high-strength ciphers: cipher strengths apparently limited by JCE policy");
|
log.warn("Disabling high-strength ciphers: cipher strengths apparently limited by JCE policy");
|
||||||
|
|
||||||
setCipherFactories(avail);
|
setCipherFactories(avail);
|
||||||
|
log.debug("Available cipher factories: {}", avail);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initSignatureFactories() {
|
protected void initSignatureFactories() {
|
||||||
setSignatureFactories(new SignatureRSA.Factory(), new SignatureDSA.Factory());
|
setSignatureFactories(
|
||||||
|
new SignatureECDSA.Factory(),
|
||||||
|
new SignatureRSA.Factory(),
|
||||||
|
new SignatureDSA.Factory(),
|
||||||
|
new SignatureEdDSA.Factory()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initMACFactories() {
|
protected void initMACFactories() {
|
||||||
setMACFactories(new HMACSHA1.Factory(), new HMACSHA196.Factory(), new HMACMD5.Factory(),
|
setMACFactories(
|
||||||
new HMACMD596.Factory());
|
new HMACSHA1.Factory(),
|
||||||
|
new HMACSHA196.Factory(),
|
||||||
|
new HMACMD5.Factory(),
|
||||||
|
new HMACMD596.Factory(),
|
||||||
|
new HMACSHA2256.Factory(),
|
||||||
|
new HMACSHA2512.Factory()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initCompressionFactories() {
|
protected void initCompressionFactories() {
|
||||||
setCompressionFactories(new NoneCompression.Factory());
|
setCompressionFactories(new NoneCompression.Factory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,10 +13,10 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.sshj.common.SSHException;
|
import net.schmizz.sshj.common.SSHException;
|
||||||
import net.schmizz.sshj.common.SecurityUtils;
|
import net.schmizz.sshj.common.SecurityUtils;
|
||||||
import net.schmizz.sshj.connection.Connection;
|
import net.schmizz.sshj.connection.Connection;
|
||||||
@@ -40,36 +40,30 @@ import net.schmizz.sshj.transport.TransportImpl;
|
|||||||
import net.schmizz.sshj.transport.compression.DelayedZlibCompression;
|
import net.schmizz.sshj.transport.compression.DelayedZlibCompression;
|
||||||
import net.schmizz.sshj.transport.compression.NoneCompression;
|
import net.schmizz.sshj.transport.compression.NoneCompression;
|
||||||
import net.schmizz.sshj.transport.compression.ZlibCompression;
|
import net.schmizz.sshj.transport.compression.ZlibCompression;
|
||||||
|
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
|
||||||
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
|
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
|
||||||
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
|
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
|
||||||
import net.schmizz.sshj.userauth.UserAuth;
|
import net.schmizz.sshj.userauth.UserAuth;
|
||||||
import net.schmizz.sshj.userauth.UserAuthException;
|
import net.schmizz.sshj.userauth.UserAuthException;
|
||||||
import net.schmizz.sshj.userauth.UserAuthImpl;
|
import net.schmizz.sshj.userauth.UserAuthImpl;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
|
import net.schmizz.sshj.userauth.keyprovider.*;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.KeyPairWrapper;
|
import net.schmizz.sshj.userauth.method.*;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
|
|
||||||
import net.schmizz.sshj.userauth.keyprovider.KeyProviderUtil;
|
|
||||||
import net.schmizz.sshj.userauth.method.AuthKeyboardInteractive;
|
|
||||||
import net.schmizz.sshj.userauth.method.AuthMethod;
|
|
||||||
import net.schmizz.sshj.userauth.method.AuthPassword;
|
|
||||||
import net.schmizz.sshj.userauth.method.AuthPublickey;
|
|
||||||
import net.schmizz.sshj.userauth.method.PasswordResponseProvider;
|
|
||||||
import net.schmizz.sshj.userauth.password.PasswordFinder;
|
import net.schmizz.sshj.userauth.password.PasswordFinder;
|
||||||
|
import net.schmizz.sshj.userauth.password.PasswordUpdateProvider;
|
||||||
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
||||||
import net.schmizz.sshj.userauth.password.Resource;
|
import net.schmizz.sshj.userauth.password.Resource;
|
||||||
import net.schmizz.sshj.xfer.scp.SCPFileTransfer;
|
import net.schmizz.sshj.xfer.scp.SCPFileTransfer;
|
||||||
|
import org.ietf.jgss.Oid;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
|
import javax.security.auth.login.LoginContext;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketAddress;
|
import java.net.ServerSocket;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Secure SHell client API.
|
* Secure SHell client API.
|
||||||
@@ -92,8 +86,8 @@ import java.util.List;
|
|||||||
* <em>A simple example:</em>
|
* <em>A simple example:</em>
|
||||||
* <p/>
|
* <p/>
|
||||||
* <pre>
|
* <pre>
|
||||||
* client = new SSHClient();
|
* final SSHClient client = new SSHClient();
|
||||||
* client.initUserKnownHosts();
|
* client.loadKnownHosts();
|
||||||
* client.connect("hostname");
|
* client.connect("hostname");
|
||||||
* try {
|
* try {
|
||||||
* client.authPassword("username", "password");
|
* client.authPassword("username", "password");
|
||||||
@@ -103,8 +97,9 @@ import java.util.List;
|
|||||||
* cmd.join(1, TimeUnit.SECONDS);
|
* cmd.join(1, TimeUnit.SECONDS);
|
||||||
* } finally {
|
* } finally {
|
||||||
* session.close();
|
* session.close();
|
||||||
* } finally {
|
* }
|
||||||
* client.disconnect();
|
* } finally {
|
||||||
|
* client.disconnect();
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -119,7 +114,8 @@ public class SSHClient
|
|||||||
public static final int DEFAULT_PORT = 22;
|
public static final int DEFAULT_PORT = 22;
|
||||||
|
|
||||||
/** Logger */
|
/** Logger */
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final LoggerFactory loggerFactory;
|
||||||
|
protected final Logger log;
|
||||||
|
|
||||||
/** Transport layer */
|
/** Transport layer */
|
||||||
protected final Transport trans;
|
protected final Transport trans;
|
||||||
@@ -130,6 +126,8 @@ public class SSHClient
|
|||||||
/** {@code ssh-connection} service */
|
/** {@code ssh-connection} service */
|
||||||
protected final Connection conn;
|
protected final Connection conn;
|
||||||
|
|
||||||
|
private final List<LocalPortForwarder> forwarders = new ArrayList<LocalPortForwarder>();
|
||||||
|
|
||||||
/** Default constructor. Initializes this object using {@link DefaultConfig}. */
|
/** Default constructor. Initializes this object using {@link DefaultConfig}. */
|
||||||
public SSHClient() {
|
public SSHClient() {
|
||||||
this(new DefaultConfig());
|
this(new DefaultConfig());
|
||||||
@@ -142,19 +140,30 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public SSHClient(Config config) {
|
public SSHClient(Config config) {
|
||||||
super(DEFAULT_PORT);
|
super(DEFAULT_PORT);
|
||||||
this.trans = new TransportImpl(config);
|
loggerFactory = config.getLoggerFactory();
|
||||||
|
log = loggerFactory.getLogger(getClass());
|
||||||
|
this.trans = new TransportImpl(config, this);
|
||||||
this.auth = new UserAuthImpl(trans);
|
this.auth = new UserAuthImpl(trans);
|
||||||
this.conn = new ConnectionImpl(trans);
|
this.conn = new ConnectionImpl(trans, config.getKeepAliveProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a {@link HostKeyVerifier} which will be invoked for verifying host key during connection establishment and
|
* Add a {@link HostKeyVerifier} which will be invoked for verifying host key during connection establishment and
|
||||||
* future key exchanges.
|
* future key exchanges.
|
||||||
*
|
*
|
||||||
* @param hostKeyVerifier {@link HostKeyVerifier} instance
|
* @param verifier {@link HostKeyVerifier} instance
|
||||||
*/
|
*/
|
||||||
public void addHostKeyVerifier(HostKeyVerifier hostKeyVerifier) {
|
public void addHostKeyVerifier(HostKeyVerifier verifier) {
|
||||||
trans.addHostKeyVerifier(hostKeyVerifier);
|
trans.addHostKeyVerifier(verifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a {@link AlgorithmsVerifier} which will be invoked for verifying negotiated algorithms.
|
||||||
|
*
|
||||||
|
* @param verifier {@link AlgorithmsVerifier} instance
|
||||||
|
*/
|
||||||
|
public void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
|
||||||
|
trans.addAlgorithmsVerifier(verifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,6 +183,8 @@ public class SSHClient
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: there are way too many auth... overrides. Better API needed.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate {@code username} using the supplied {@code methods}.
|
* Authenticate {@code username} using the supplied {@code methods}.
|
||||||
*
|
*
|
||||||
@@ -185,7 +196,7 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public void auth(String username, AuthMethod... methods)
|
public void auth(String username, AuthMethod... methods)
|
||||||
throws UserAuthException, TransportException {
|
throws UserAuthException, TransportException {
|
||||||
assert isConnected();
|
checkConnected();
|
||||||
auth(username, Arrays.<AuthMethod>asList(methods));
|
auth(username, Arrays.<AuthMethod>asList(methods));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,8 +211,18 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public void auth(String username, Iterable<AuthMethod> methods)
|
public void auth(String username, Iterable<AuthMethod> methods)
|
||||||
throws UserAuthException, TransportException {
|
throws UserAuthException, TransportException {
|
||||||
assert isConnected();
|
checkConnected();
|
||||||
auth.authenticate(username, (Service) conn, methods);
|
final Deque<UserAuthException> savedEx = new LinkedList<UserAuthException>();
|
||||||
|
for (AuthMethod method: methods) {
|
||||||
|
method.setLoggerFactory(loggerFactory);
|
||||||
|
try {
|
||||||
|
if (auth.authenticate(username, (Service) conn, method, trans.getTimeoutMs()))
|
||||||
|
return;
|
||||||
|
} catch (UserAuthException e) {
|
||||||
|
savedEx.push(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new UserAuthException("Exhausted available authentication methods", savedEx.peek());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -265,6 +286,22 @@ public class SSHClient
|
|||||||
auth(username, new AuthPassword(pfinder), new AuthKeyboardInteractive(new PasswordResponseProvider(pfinder)));
|
auth(username, new AuthPassword(pfinder), new AuthKeyboardInteractive(new PasswordResponseProvider(pfinder)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate {@code username} using the {@code "password"} authentication method and as a fallback basic
|
||||||
|
* challenge-response authentication.
|
||||||
|
*
|
||||||
|
* @param username user to authenticate
|
||||||
|
* @param pfinder the {@link PasswordFinder} to use for authentication
|
||||||
|
* @param newPasswordProvider the {@link PasswordUpdateProvider} to use when a new password is being requested from the user.
|
||||||
|
*
|
||||||
|
* @throws UserAuthException in case of authentication failure
|
||||||
|
* @throws TransportException if there was a transport-layer error
|
||||||
|
*/
|
||||||
|
public void authPassword(String username, PasswordFinder pfinder, PasswordUpdateProvider newPasswordProvider)
|
||||||
|
throws UserAuthException, TransportException {
|
||||||
|
auth(username, new AuthPassword(pfinder, newPasswordProvider), new AuthKeyboardInteractive(new PasswordResponseProvider(pfinder)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate {@code username} using the {@code "publickey"} authentication method, with keys from some common
|
* Authenticate {@code username} using the {@code "publickey"} authentication method, with keys from some common
|
||||||
* locations on the file system. This method relies on {@code ~/.ssh/id_rsa} and {@code ~/.ssh/id_dsa}.
|
* locations on the file system. This method relies on {@code ~/.ssh/id_rsa} and {@code ~/.ssh/id_dsa}.
|
||||||
@@ -279,7 +316,7 @@ public class SSHClient
|
|||||||
public void authPublickey(String username)
|
public void authPublickey(String username)
|
||||||
throws UserAuthException, TransportException {
|
throws UserAuthException, TransportException {
|
||||||
final String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator;
|
final String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator;
|
||||||
authPublickey(username, base + "id_rsa", base + "id_dsa");
|
authPublickey(username, base + "id_rsa", base + "id_dsa", base + "id_ed25519", base + "id_ecdsa");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -296,8 +333,7 @@ public class SSHClient
|
|||||||
* @throws TransportException if there was a transport-layer error
|
* @throws TransportException if there was a transport-layer error
|
||||||
*/
|
*/
|
||||||
public void authPublickey(String username, Iterable<KeyProvider> keyProviders)
|
public void authPublickey(String username, Iterable<KeyProvider> keyProviders)
|
||||||
throws UserAuthException,
|
throws UserAuthException, TransportException {
|
||||||
TransportException {
|
|
||||||
final List<AuthMethod> am = new LinkedList<AuthMethod>();
|
final List<AuthMethod> am = new LinkedList<AuthMethod>();
|
||||||
for (KeyProvider kp : keyProviders)
|
for (KeyProvider kp : keyProviders)
|
||||||
am.add(new AuthPublickey(kp));
|
am.add(new AuthPublickey(kp));
|
||||||
@@ -342,16 +378,41 @@ public class SSHClient
|
|||||||
public void authPublickey(String username, String... locations)
|
public void authPublickey(String username, String... locations)
|
||||||
throws UserAuthException, TransportException {
|
throws UserAuthException, TransportException {
|
||||||
final List<KeyProvider> keyProviders = new LinkedList<KeyProvider>();
|
final List<KeyProvider> keyProviders = new LinkedList<KeyProvider>();
|
||||||
for (String loc : locations)
|
for (String loc : locations) {
|
||||||
try {
|
try {
|
||||||
log.debug("Attempting to load key from: {}", loc);
|
log.debug("Attempting to load key from: {}", loc);
|
||||||
keyProviders.add(loadKeys(loc));
|
keyProviders.add(loadKeys(loc));
|
||||||
} catch (IOException logged) {
|
} catch (IOException logged) {
|
||||||
log.warn("Could not load keys due to: {}", logged);
|
log.info("Could not load keys from {} due to: {}", loc, logged.getMessage());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
authPublickey(username, keyProviders);
|
authPublickey(username, keyProviders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate {@code username} using the {@code "gssapi-with-mic"} authentication method, given a login context
|
||||||
|
* for the peer GSS machine and a list of supported OIDs.
|
||||||
|
* <p/>
|
||||||
|
* Supported OIDs should be ordered by preference as the SSH server will choose the first OID that it also
|
||||||
|
* supports. At least one OID is required
|
||||||
|
*
|
||||||
|
* @param username user to authenticate
|
||||||
|
* @param context {@code LoginContext} for the peer GSS machine
|
||||||
|
* @param supportedOid first supported OID
|
||||||
|
* @param supportedOids other supported OIDs
|
||||||
|
*
|
||||||
|
* @throws UserAuthException in case of authentication failure
|
||||||
|
* @throws TransportException if there was a transport-layer error
|
||||||
|
*/
|
||||||
|
public void authGssApiWithMic(String username, LoginContext context, Oid supportedOid, Oid... supportedOids)
|
||||||
|
throws UserAuthException, TransportException {
|
||||||
|
// insert supportedOid to the front of the list since ordering matters
|
||||||
|
List<Oid> oids = new ArrayList<Oid>(Arrays.asList(supportedOids));
|
||||||
|
oids.add(0, supportedOid);
|
||||||
|
|
||||||
|
auth(username, new AuthGssApiWithMic(context, oids));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnects from the connected SSH server. {@code SSHClient} objects are not reusable therefore it is incorrect
|
* Disconnects from the connected SSH server. {@code SSHClient} objects are not reusable therefore it is incorrect
|
||||||
* to attempt connection after this method has been called.
|
* to attempt connection after this method has been called.
|
||||||
@@ -362,10 +423,16 @@ public class SSHClient
|
|||||||
@Override
|
@Override
|
||||||
public void disconnect()
|
public void disconnect()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
assert isConnected();
|
for (LocalPortForwarder forwarder : forwarders) {
|
||||||
|
try {
|
||||||
|
forwarder.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Error closing forwarder", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
forwarders.clear();
|
||||||
trans.disconnect();
|
trans.disconnect();
|
||||||
super.disconnect();
|
super.disconnect();
|
||||||
assert !isConnected();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the associated {@link Connection} instance. */
|
/** @return the associated {@link Connection} instance. */
|
||||||
@@ -391,8 +458,7 @@ public class SSHClient
|
|||||||
/**
|
/**
|
||||||
* @return the associated {@link UserAuth} instance. This allows access to information like the {@link
|
* @return the associated {@link UserAuth} instance. This allows access to information like the {@link
|
||||||
* UserAuth#getBanner() authentication banner}, whether authentication was at least {@link
|
* UserAuth#getBanner() authentication banner}, whether authentication was at least {@link
|
||||||
* UserAuth#hadPartialSuccess() partially successful}, and any {@link UserAuth#getSavedExceptions() saved
|
* UserAuth#hadPartialSuccess() partially successful}.
|
||||||
* exceptions} that were ignored because there were more authentication method that could be tried.
|
|
||||||
*/
|
*/
|
||||||
public UserAuth getUserAuth() {
|
public UserAuth getUserAuth() {
|
||||||
return auth;
|
return auth;
|
||||||
@@ -458,8 +524,13 @@ public class SSHClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link KeyProvider} instance from given location on the file system. Currently only PKCS8 format
|
* Creates a {@link KeyProvider} instance from given location on the file system. Currently the following private key files are supported:
|
||||||
* private key files are supported (OpenSSH uses this format).
|
* <ul>
|
||||||
|
* <li>PKCS8 (OpenSSH uses this format)</li>
|
||||||
|
* <li>PKCS5</li>
|
||||||
|
* <li>Putty keyfile</li>
|
||||||
|
* <li>openssh-key-v1 (New OpenSSH keyfile format)</li>
|
||||||
|
* </ul>
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @param location the location of the key file
|
* @param location the location of the key file
|
||||||
@@ -475,9 +546,9 @@ public class SSHClient
|
|||||||
public KeyProvider loadKeys(String location, PasswordFinder passwordFinder)
|
public KeyProvider loadKeys(String location, PasswordFinder passwordFinder)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final File loc = new File(location);
|
final File loc = new File(location);
|
||||||
final FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(loc);
|
final KeyFormat format = KeyProviderUtil.detectKeyFileFormat(loc);
|
||||||
final FileKeyProvider fkp = Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format
|
final FileKeyProvider fkp =
|
||||||
.toString());
|
Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format.toString());
|
||||||
if (fkp == null)
|
if (fkp == null)
|
||||||
throw new SSHException("No provider available for " + format + " key file");
|
throw new SSHException("No provider available for " + format + " key file");
|
||||||
fkp.init(loc, passwordFinder);
|
fkp.init(loc, passwordFinder);
|
||||||
@@ -519,9 +590,9 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public KeyProvider loadKeys(String privateKey, String publicKey, PasswordFinder passwordFinder)
|
public KeyProvider loadKeys(String privateKey, String publicKey, PasswordFinder passwordFinder)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final FileKeyProvider.Format format = KeyProviderUtil.detectKeyFileFormat(privateKey, publicKey != null);
|
final KeyFormat format = KeyProviderUtil.detectKeyFileFormat(privateKey, publicKey != null);
|
||||||
final FileKeyProvider fkp = Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format
|
final FileKeyProvider fkp =
|
||||||
.toString());
|
Factory.Named.Util.create(trans.getConfig().getFileKeyProviderFactories(), format.toString());
|
||||||
if (fkp == null)
|
if (fkp == null)
|
||||||
throw new SSHException("No provider available for " + format + " key file");
|
throw new SSHException("No provider available for " + format + " key file");
|
||||||
fkp.init(privateKey, publicKey, passwordFinder);
|
fkp.init(privateKey, publicKey, passwordFinder);
|
||||||
@@ -564,27 +635,27 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public void loadKnownHosts(File location)
|
public void loadKnownHosts(File location)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
addHostKeyVerifier(new OpenSSHKnownHosts(location));
|
addHostKeyVerifier(new OpenSSHKnownHosts(location, loggerFactory));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a {@link LocalPortForwarder} that will listen on {@code address} and forward incoming connections to the
|
* Create a {@link LocalPortForwarder} that will listen based on {@code parameters} using the bound
|
||||||
* server; which will further forward them to {@code host:port}.
|
* {@code serverSocket} and forward incoming connections to the server; which will further forward them to
|
||||||
|
* {@code host:port}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The returned forwarder's {@link LocalPortForwarder#listen() listen()} method should be called to actually start
|
* The returned forwarder's {@link LocalPortForwarder#listen() listen()} method should be called to actually start
|
||||||
* listening, this method just creates an instance.
|
* listening, this method just creates an instance.
|
||||||
*
|
*
|
||||||
* @param address defines where the {@link LocalPortForwarder} listens
|
* @param parameters parameters for the forwarding setup
|
||||||
* @param host hostname to which the server will forward
|
* @param serverSocket bound server socket
|
||||||
* @param port the port at {@code hostname} to which the server wil forward
|
|
||||||
*
|
*
|
||||||
* @return a {@link LocalPortForwarder}
|
* @return a {@link LocalPortForwarder}
|
||||||
*
|
|
||||||
* @throws IOException if there is an error opening a local server socket
|
|
||||||
*/
|
*/
|
||||||
public LocalPortForwarder newLocalPortForwarder(SocketAddress address, String host, int port)
|
public LocalPortForwarder newLocalPortForwarder(LocalPortForwarder.Parameters parameters,
|
||||||
throws IOException {
|
ServerSocket serverSocket) {
|
||||||
return new LocalPortForwarder(getServerSocketFactory(), conn, address, host, port);
|
LocalPortForwarder forwarder = new LocalPortForwarder(conn, parameters, serverSocket, loggerFactory);
|
||||||
|
forwarders.add(forwarder);
|
||||||
|
return forwarder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -609,8 +680,9 @@ public class SSHClient
|
|||||||
|
|
||||||
/** @return Instantiated {@link SCPFileTransfer} implementation. */
|
/** @return Instantiated {@link SCPFileTransfer} implementation. */
|
||||||
public SCPFileTransfer newSCPFileTransfer() {
|
public SCPFileTransfer newSCPFileTransfer() {
|
||||||
assert isConnected() && isAuthenticated();
|
checkConnected();
|
||||||
return new SCPFileTransfer(this);
|
checkAuthenticated();
|
||||||
|
return new SCPFileTransfer(this, loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -621,7 +693,8 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
public SFTPClient newSFTPClient()
|
public SFTPClient newSFTPClient()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
assert isConnected() && isAuthenticated();
|
checkConnected();
|
||||||
|
checkAuthenticated();
|
||||||
return new SFTPClient(new SFTPEngine(this).init());
|
return new SFTPClient(new SFTPEngine(this).init());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,10 +711,10 @@ public class SSHClient
|
|||||||
@Override
|
@Override
|
||||||
public Session startSession()
|
public Session startSession()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
assert isConnected() && isAuthenticated();
|
checkConnected();
|
||||||
|
checkAuthenticated();
|
||||||
final SessionChannel sess = new SessionChannel(conn);
|
final SessionChannel sess = new SessionChannel(conn);
|
||||||
sess.open();
|
sess.open();
|
||||||
assert sess.isOpen();
|
|
||||||
return sess;
|
return sess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,11 +754,10 @@ public class SSHClient
|
|||||||
*/
|
*/
|
||||||
protected void doKex()
|
protected void doKex()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
assert trans.isRunning();
|
checkConnected();
|
||||||
|
|
||||||
final long start = System.currentTimeMillis();
|
final long start = System.currentTimeMillis();
|
||||||
trans.doKex();
|
trans.doKex();
|
||||||
log.info("Key exchange took {} seconds", (System.currentTimeMillis() - start) / 1000.0);
|
log.debug("Key exchange took {} seconds", (System.currentTimeMillis() - start) / 1000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -699,4 +771,16 @@ public class SSHClient
|
|||||||
disconnect();
|
disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
private void checkConnected() {
|
||||||
|
if (!isConnected()) {
|
||||||
|
throw new IllegalStateException("Not connected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAuthenticated() {
|
||||||
|
if (!isAuthenticated()) {
|
||||||
|
throw new IllegalStateException("Not authenticated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,40 +12,22 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file incorporates work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
import javax.net.ServerSocketFactory;
|
import com.hierynomus.sshj.backport.JavaVersion;
|
||||||
|
import com.hierynomus.sshj.backport.Jdk7HttpProxySocket;
|
||||||
|
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Proxy;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
|
public abstract class SocketClient {
|
||||||
abstract class SocketClient {
|
|
||||||
|
|
||||||
private final int defaultPort;
|
private final int defaultPort;
|
||||||
|
|
||||||
@@ -54,7 +36,6 @@ abstract class SocketClient {
|
|||||||
private OutputStream output;
|
private OutputStream output;
|
||||||
|
|
||||||
private SocketFactory socketFactory = SocketFactory.getDefault();
|
private SocketFactory socketFactory = SocketFactory.getDefault();
|
||||||
private ServerSocketFactory serverSocketFactory = ServerSocketFactory.getDefault();
|
|
||||||
|
|
||||||
private static final int DEFAULT_CONNECT_TIMEOUT = 0;
|
private static final int DEFAULT_CONNECT_TIMEOUT = 0;
|
||||||
private int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
private int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
||||||
@@ -67,21 +48,109 @@ abstract class SocketClient {
|
|||||||
this.defaultPort = defaultPort;
|
this.defaultPort = defaultPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(InetAddress host, int port)
|
/**
|
||||||
throws IOException {
|
* Connect to a host via a proxy.
|
||||||
|
* @param hostname The host name to connect to.
|
||||||
|
* @param proxy The proxy to connect via.
|
||||||
|
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
|
||||||
|
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void connect(String hostname, Proxy proxy) throws IOException {
|
||||||
|
connect(hostname, defaultPort, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to a host via a proxy.
|
||||||
|
* @param hostname The host name to connect to.
|
||||||
|
* @param port The port to connect to.
|
||||||
|
* @param proxy The proxy to connect via.
|
||||||
|
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
|
||||||
|
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void connect(String hostname, int port, Proxy proxy) throws IOException {
|
||||||
|
this.hostname = hostname;
|
||||||
|
if (JavaVersion.isJava7OrEarlier() && proxy.type() == Proxy.Type.HTTP) {
|
||||||
|
// Java7 and earlier have no support for HTTP Connect proxies, return our custom socket.
|
||||||
|
socket = new Jdk7HttpProxySocket(proxy);
|
||||||
|
} else {
|
||||||
|
socket = new Socket(proxy);
|
||||||
|
}
|
||||||
|
socket.connect(new InetSocketAddress(hostname, port), connectTimeout);
|
||||||
|
onConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to a host via a proxy.
|
||||||
|
* @param host The host address to connect to.
|
||||||
|
* @param proxy The proxy to connect via.
|
||||||
|
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
|
||||||
|
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void connect(InetAddress host, Proxy proxy) throws IOException {
|
||||||
|
connect(host, defaultPort, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to a host via a proxy.
|
||||||
|
* @param host The host address to connect to.
|
||||||
|
* @param port The port to connect to.
|
||||||
|
* @param proxy The proxy to connect via.
|
||||||
|
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
|
||||||
|
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void connect(InetAddress host, int port, Proxy proxy) throws IOException {
|
||||||
|
if (JavaVersion.isJava7OrEarlier() && proxy.type() == Proxy.Type.HTTP) {
|
||||||
|
// Java7 and earlier have no support for HTTP Connect proxies, return our custom socket.
|
||||||
|
socket = new Jdk7HttpProxySocket(proxy);
|
||||||
|
} else {
|
||||||
|
socket = new Socket(proxy);
|
||||||
|
}
|
||||||
|
socket.connect(new InetSocketAddress(host, port), connectTimeout);
|
||||||
|
onConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(String hostname) throws IOException {
|
||||||
|
connect(hostname, defaultPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(String hostname, int port) throws IOException {
|
||||||
|
if (hostname == null) {
|
||||||
|
connect(InetAddress.getByName(null), port);
|
||||||
|
} else {
|
||||||
|
this.hostname = hostname;
|
||||||
|
socket = socketFactory.createSocket();
|
||||||
|
socket.connect(new InetSocketAddress(hostname, port), connectTimeout);
|
||||||
|
onConnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(String hostname, int port, InetAddress localAddr, int localPort) throws IOException {
|
||||||
|
if (hostname == null) {
|
||||||
|
connect(InetAddress.getByName(null), port, localAddr, localPort);
|
||||||
|
} else {
|
||||||
|
this.hostname = hostname;
|
||||||
|
socket = socketFactory.createSocket();
|
||||||
|
socket.bind(new InetSocketAddress(localAddr, localPort));
|
||||||
|
socket.connect(new InetSocketAddress(hostname, port), connectTimeout);
|
||||||
|
onConnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(InetAddress host) throws IOException {
|
||||||
|
connect(host, defaultPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(InetAddress host, int port) throws IOException {
|
||||||
socket = socketFactory.createSocket();
|
socket = socketFactory.createSocket();
|
||||||
socket.connect(new InetSocketAddress(host, port), connectTimeout);
|
socket.connect(new InetSocketAddress(host, port), connectTimeout);
|
||||||
onConnect();
|
onConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(String hostname, int port)
|
public void connect(InetAddress host, int port, InetAddress localAddr, int localPort)
|
||||||
throws IOException {
|
|
||||||
this.hostname = hostname;
|
|
||||||
connect(InetAddress.getByName(hostname), port);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connect(InetAddress host, int port,
|
|
||||||
InetAddress localAddr, int localPort)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
socket = socketFactory.createSocket();
|
socket = socketFactory.createSocket();
|
||||||
socket.bind(new InetSocketAddress(localAddr, localPort));
|
socket.bind(new InetSocketAddress(localAddr, localPort));
|
||||||
@@ -89,25 +158,7 @@ abstract class SocketClient {
|
|||||||
onConnect();
|
onConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(String hostname, int port,
|
public void disconnect() throws IOException {
|
||||||
InetAddress localAddr, int localPort)
|
|
||||||
throws IOException {
|
|
||||||
this.hostname = hostname;
|
|
||||||
connect(InetAddress.getByName(hostname), port, localAddr, localPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connect(InetAddress host)
|
|
||||||
throws IOException {
|
|
||||||
connect(host, defaultPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connect(String hostname)
|
|
||||||
throws IOException {
|
|
||||||
connect(hostname, defaultPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnect()
|
|
||||||
throws IOException {
|
|
||||||
if (socket != null) {
|
if (socket != null) {
|
||||||
socket.close();
|
socket.close();
|
||||||
socket = null;
|
socket = null;
|
||||||
@@ -130,7 +181,6 @@ abstract class SocketClient {
|
|||||||
return socket.getLocalPort();
|
return socket.getLocalPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public InetAddress getLocalAddress() {
|
public InetAddress getLocalAddress() {
|
||||||
return socket.getLocalAddress();
|
return socket.getLocalAddress();
|
||||||
}
|
}
|
||||||
@@ -148,27 +198,17 @@ abstract class SocketClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setSocketFactory(SocketFactory factory) {
|
public void setSocketFactory(SocketFactory factory) {
|
||||||
if (factory == null)
|
if (factory == null) {
|
||||||
socketFactory = SocketFactory.getDefault();
|
socketFactory = SocketFactory.getDefault();
|
||||||
else
|
} else {
|
||||||
socketFactory = factory;
|
socketFactory = factory;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketFactory getSocketFactory() {
|
public SocketFactory getSocketFactory() {
|
||||||
return socketFactory;
|
return socketFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setServerSocketFactory(ServerSocketFactory factory) {
|
|
||||||
if (factory == null)
|
|
||||||
serverSocketFactory = ServerSocketFactory.getDefault();
|
|
||||||
else
|
|
||||||
serverSocketFactory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerSocketFactory getServerSocketFactory() {
|
|
||||||
return serverSocketFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getConnectTimeout() {
|
public int getConnectTimeout() {
|
||||||
return connectTimeout;
|
return connectTimeout;
|
||||||
}
|
}
|
||||||
@@ -197,11 +237,10 @@ abstract class SocketClient {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onConnect()
|
void onConnect() throws IOException {
|
||||||
throws IOException {
|
|
||||||
socket.setSoTimeout(timeout);
|
socket.setSoTimeout(timeout);
|
||||||
input = socket.getInputStream();
|
input = socket.getInputStream();
|
||||||
output = socket.getOutputStream();
|
output = socket.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1727,4 +1727,4 @@ public class Base64 {
|
|||||||
private Base64() {
|
private Base64() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end class Base64
|
} // end class Base64
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
@@ -51,7 +31,7 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PlainBuffer
|
public static final class PlainBuffer
|
||||||
extends Buffer<PlainBuffer> {
|
extends Buffer<PlainBuffer> {
|
||||||
|
|
||||||
public PlainBuffer() {
|
public PlainBuffer() {
|
||||||
@@ -74,10 +54,15 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
/** The default size for a {@code Buffer} (256 bytes) */
|
/** The default size for a {@code Buffer} (256 bytes) */
|
||||||
public static final int DEFAULT_SIZE = 256;
|
public static final int DEFAULT_SIZE = 256;
|
||||||
|
|
||||||
|
/** The maximum valid size of buffer (i.e. biggest power of two that can be represented as an int - 2^30) */
|
||||||
|
public static final int MAX_SIZE = (1 << 30);
|
||||||
|
|
||||||
protected static int getNextPowerOf2(int i) {
|
protected static int getNextPowerOf2(int i) {
|
||||||
int j = 1;
|
int j = 1;
|
||||||
while (j < i)
|
while (j < i) {
|
||||||
j <<= 1;
|
j <<= 1;
|
||||||
|
if (j <= 0) throw new IllegalArgumentException("Cannot get next power of 2; "+i+" is too large");
|
||||||
|
}
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,8 +426,7 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
public PublicKey readPublicKey()
|
public PublicKey readPublicKey()
|
||||||
throws BufferException {
|
throws BufferException {
|
||||||
try {
|
try {
|
||||||
final String type = readString();
|
return KeyType.fromString(readString()).readPubKeyFromBuffer(this);
|
||||||
return KeyType.fromString(type).readPubKeyFromBuffer(type, this);
|
|
||||||
} catch (GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new SSHRuntimeException(e);
|
throw new SSHRuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,31 +12,10 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
@@ -46,25 +25,33 @@ import java.nio.charset.Charset;
|
|||||||
|
|
||||||
public class IOUtils {
|
public class IOUtils {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(IOUtils.class);
|
|
||||||
|
|
||||||
public static final Charset UTF8 = Charset.forName("UTF-8");
|
public static final Charset UTF8 = Charset.forName("UTF-8");
|
||||||
|
|
||||||
public static void closeQuietly(Closeable... closeables) {
|
public static void closeQuietly(Closeable... closeables) {
|
||||||
for (Closeable c : closeables)
|
closeQuietly(LoggerFactory.DEFAULT, closeables);
|
||||||
try {
|
|
||||||
if (c != null)
|
|
||||||
c.close();
|
|
||||||
} catch (IOException logged) {
|
|
||||||
LOG.warn("Error closing {} - {}", c, logged);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteArrayOutputStream readFully(InputStream stream)
|
public static ByteArrayOutputStream readFully(InputStream stream)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
return readFully(stream, LoggerFactory.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeQuietly(LoggerFactory loggerFactory, Closeable... closeables) {
|
||||||
|
for (Closeable c : closeables) {
|
||||||
|
try {
|
||||||
|
if (c != null)
|
||||||
|
c.close();
|
||||||
|
} catch (IOException logged) {
|
||||||
|
loggerFactory.getLogger(IOUtils.class).warn("Error closing {} - {}", c, logged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteArrayOutputStream readFully(InputStream stream, LoggerFactory loggerFactory)
|
||||||
|
throws IOException {
|
||||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
new StreamCopier(stream, baos).copy();
|
new StreamCopier(stream, baos, loggerFactory).copy();
|
||||||
return baos;
|
return baos;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,25 +15,38 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
import com.hierynomus.sshj.secg.SecgUtils;
|
||||||
|
import com.hierynomus.sshj.signature.Ed25519PublicKey;
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||||
|
import org.bouncycastle.asn1.nist.NISTNamedCurves;
|
||||||
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||||
|
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||||
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.interfaces.DSAPrivateKey;
|
import java.security.interfaces.*;
|
||||||
import java.security.interfaces.DSAPublicKey;
|
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
|
||||||
import java.security.interfaces.RSAPublicKey;
|
|
||||||
import java.security.spec.DSAPublicKeySpec;
|
import java.security.spec.DSAPublicKeySpec;
|
||||||
import java.security.spec.RSAPublicKeySpec;
|
import java.security.spec.RSAPublicKeySpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/** Type of key e.g. rsa, dsa */
|
/** Type of key e.g. rsa, dsa */
|
||||||
public enum KeyType {
|
public enum KeyType {
|
||||||
|
|
||||||
|
|
||||||
/** SSH identifier for RSA keys */
|
/** SSH identifier for RSA keys */
|
||||||
RSA("ssh-rsa") {
|
RSA("ssh-rsa") {
|
||||||
@Override
|
@Override
|
||||||
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
|
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
final BigInteger e, n;
|
final BigInteger e, n;
|
||||||
try {
|
try {
|
||||||
@@ -64,7 +77,7 @@ public enum KeyType {
|
|||||||
/** SSH identifier for DSA keys */
|
/** SSH identifier for DSA keys */
|
||||||
DSA("ssh-dss") {
|
DSA("ssh-dss") {
|
||||||
@Override
|
@Override
|
||||||
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
|
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
BigInteger p, q, g, y;
|
BigInteger p, q, g, y;
|
||||||
try {
|
try {
|
||||||
@@ -96,12 +109,116 @@ public enum KeyType {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** SSH identifier for ECDSA keys */
|
||||||
|
ECDSA("ecdsa-sha2-nistp256") {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
if (!SecurityUtils.isBouncyCastleRegistered()) {
|
||||||
|
throw new GeneralSecurityException("BouncyCastle is required to read a key of type " + sType);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// final String algo = buf.readString(); it has been already read
|
||||||
|
final String curveName = buf.readString();
|
||||||
|
final int keyLen = buf.readUInt32AsInt();
|
||||||
|
final byte x04 = buf.readByte(); // it must be 0x04, but don't think we need that check
|
||||||
|
final byte[] x = new byte[(keyLen - 1) / 2];
|
||||||
|
final byte[] y = new byte[(keyLen - 1) / 2];
|
||||||
|
buf.readRawBytes(x);
|
||||||
|
buf.readRawBytes(y);
|
||||||
|
if(log.isDebugEnabled()) {
|
||||||
|
log.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s",
|
||||||
|
sType,
|
||||||
|
curveName,
|
||||||
|
keyLen,
|
||||||
|
x04,
|
||||||
|
Arrays.toString(x),
|
||||||
|
Arrays.toString(y))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NISTP_CURVE.equals(curveName)) {
|
||||||
|
throw new GeneralSecurityException(String.format("Unknown curve %s", curveName));
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger bigX = new BigInteger(1, x);
|
||||||
|
BigInteger bigY = new BigInteger(1, y);
|
||||||
|
|
||||||
|
X9ECParameters ecParams = NISTNamedCurves.getByName("p-256");
|
||||||
|
ECPoint pPublicPoint = ecParams.getCurve().createPoint(bigX, bigY);
|
||||||
|
ECParameterSpec spec = new ECParameterSpec(ecParams.getCurve(),
|
||||||
|
ecParams.getG(), ecParams.getN());
|
||||||
|
ECPublicKeySpec publicSpec = new ECPublicKeySpec(pPublicPoint, spec);
|
||||||
|
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA");
|
||||||
|
return keyFactory.generatePublic(publicSpec);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new GeneralSecurityException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
|
||||||
|
final ECPublicKey ecdsa = (ECPublicKey) pk;
|
||||||
|
byte[] encoded = SecgUtils.getEncoded(ecdsa.getW(), ecdsa.getParams().getCurve());
|
||||||
|
|
||||||
|
buf.putString(sType)
|
||||||
|
.putString(NISTP_CURVE)
|
||||||
|
.putBytes(encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isMyType(Key key) {
|
||||||
|
return ("ECDSA".equals(key.getAlgorithm()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ED25519("ssh-ed25519") {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(KeyType.class);
|
||||||
|
@Override
|
||||||
|
public PublicKey readPubKeyFromBuffer(Buffer<?> buf) throws GeneralSecurityException {
|
||||||
|
try {
|
||||||
|
final int keyLen = buf.readUInt32AsInt();
|
||||||
|
final byte[] p = new byte[keyLen];
|
||||||
|
buf.readRawBytes(p);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug(String.format("Key algo: %s, Key curve: 25519, Key Len: %s\np: %s",
|
||||||
|
sType,
|
||||||
|
keyLen,
|
||||||
|
Arrays.toString(p))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
|
||||||
|
EdDSAPublicKeySpec publicSpec = new EdDSAPublicKeySpec(p, ed25519);
|
||||||
|
return new Ed25519PublicKey(publicSpec);
|
||||||
|
|
||||||
|
} catch (Buffer.BufferException be) {
|
||||||
|
throw new SSHRuntimeException(be);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
|
||||||
|
EdDSAPublicKey key = (EdDSAPublicKey) pk;
|
||||||
|
buf.putString(sType).putBytes(key.getAbyte());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isMyType(Key key) {
|
||||||
|
return "EdDSA".equals(key.getAlgorithm());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/** Unrecognized */
|
/** Unrecognized */
|
||||||
UNKNOWN("unknown") {
|
UNKNOWN("unknown") {
|
||||||
@Override
|
@Override
|
||||||
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
|
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
throw new UnsupportedOperationException("Don't know how to decode key:" + type);
|
throw new UnsupportedOperationException("Don't know how to decode key:" + sType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -113,17 +230,18 @@ public enum KeyType {
|
|||||||
protected boolean isMyType(Key key) {
|
protected boolean isMyType(Key key) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private static final String NISTP_CURVE = "nistp256";
|
||||||
|
|
||||||
protected final String sType;
|
protected final String sType;
|
||||||
|
|
||||||
private KeyType(String type) {
|
private KeyType(String type) {
|
||||||
this.sType = type;
|
this.sType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
|
public abstract PublicKey readPubKeyFromBuffer(Buffer<?> buf)
|
||||||
throws GeneralSecurityException;
|
throws GeneralSecurityException;
|
||||||
|
|
||||||
public abstract void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf);
|
public abstract void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf);
|
||||||
@@ -148,5 +266,4 @@ public enum KeyType {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return sType;
|
return sType;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
38
src/main/java/net/schmizz/sshj/common/LoggerFactory.java
Normal file
38
src/main/java/net/schmizz/sshj/common/LoggerFactory.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
public interface LoggerFactory {
|
||||||
|
Logger getLogger(String name);
|
||||||
|
Logger getLogger(Class<?> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default SLF4J-based implementation of the SSHJ LoggerFactory.
|
||||||
|
*/
|
||||||
|
LoggerFactory DEFAULT = new LoggerFactory() {
|
||||||
|
@Override
|
||||||
|
public Logger getLogger(String name) {
|
||||||
|
return org.slf4j.LoggerFactory.getLogger(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Logger getLogger(Class<?> clazz) {
|
||||||
|
return org.slf4j.LoggerFactory.getLogger(clazz);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -30,7 +30,7 @@ public enum Message {
|
|||||||
|
|
||||||
KEXDH_INIT(30),
|
KEXDH_INIT(30),
|
||||||
|
|
||||||
/** { KEXDH_REPLY, KEXDH_GEX_GROUP } */
|
/** { KEXDH_REPLY, KEXDH_GEX_GROUP, SSH_MSG_KEX_ECDH_REPLY } */
|
||||||
KEXDH_31(31),
|
KEXDH_31(31),
|
||||||
|
|
||||||
KEX_DH_GEX_INIT(32),
|
KEX_DH_GEX_INIT(32),
|
||||||
@@ -46,6 +46,9 @@ public enum Message {
|
|||||||
USERAUTH_60(60),
|
USERAUTH_60(60),
|
||||||
USERAUTH_INFO_RESPONSE(61),
|
USERAUTH_INFO_RESPONSE(61),
|
||||||
|
|
||||||
|
USERAUTH_GSSAPI_EXCHANGE_COMPLETE(63),
|
||||||
|
USERAUTH_GSSAPI_MIC(66),
|
||||||
|
|
||||||
GLOBAL_REQUEST(80),
|
GLOBAL_REQUEST(80),
|
||||||
REQUEST_SUCCESS(81),
|
REQUEST_SUCCESS(81),
|
||||||
REQUEST_FAILURE(82),
|
REQUEST_FAILURE(82),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,32 +12,12 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class SSHPacket
|
public final class SSHPacket
|
||||||
extends Buffer<SSHPacket> {
|
extends Buffer<SSHPacket> {
|
||||||
|
|
||||||
public SSHPacket() {
|
public SSHPacket() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,70 +12,28 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import java.security.*;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.KeyAgreement;
|
import javax.crypto.KeyAgreement;
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.NoSuchPaddingException;
|
import javax.crypto.NoSuchPaddingException;
|
||||||
import java.security.GeneralSecurityException;
|
import org.slf4j.Logger;
|
||||||
import java.security.KeyFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.Signature;
|
|
||||||
|
|
||||||
// TODO refactor
|
import static java.lang.String.format;
|
||||||
|
|
||||||
/** Static utility method relating to security facilities. */
|
/**
|
||||||
|
* Static utility method relating to security facilities.
|
||||||
|
*/
|
||||||
public class SecurityUtils {
|
public class SecurityUtils {
|
||||||
|
|
||||||
private static class BouncyCastleRegistration {
|
|
||||||
|
|
||||||
public void run()
|
|
||||||
throws Exception {
|
|
||||||
if (java.security.Security.getProvider(BOUNCY_CASTLE) == null) {
|
|
||||||
LOG.info("Trying to register BouncyCastle as a JCE provider");
|
|
||||||
java.security.Security.addProvider(new BouncyCastleProvider());
|
|
||||||
MessageDigest.getInstance("MD5", BOUNCY_CASTLE);
|
|
||||||
KeyAgreement.getInstance("DH", BOUNCY_CASTLE);
|
|
||||||
LOG.info("Registration succeeded");
|
|
||||||
} else
|
|
||||||
LOG.info("BouncyCastle already registered as a JCE provider");
|
|
||||||
securityProvider = BOUNCY_CASTLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(SecurityUtils.class);
|
private static final Logger LOG = LoggerFactory.getLogger(SecurityUtils.class);
|
||||||
|
|
||||||
/** Identifier for the BouncyCastle JCE provider */
|
/**
|
||||||
|
* Identifier for the BouncyCastle JCE provider
|
||||||
|
*/
|
||||||
public static final String BOUNCY_CASTLE = "BC";
|
public static final String BOUNCY_CASTLE = "BC";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -87,6 +45,42 @@ public class SecurityUtils {
|
|||||||
private static Boolean registerBouncyCastle;
|
private static Boolean registerBouncyCastle;
|
||||||
private static boolean registrationDone;
|
private static boolean registrationDone;
|
||||||
|
|
||||||
|
public static boolean registerSecurityProvider(String providerClassName) {
|
||||||
|
Provider provider = null;
|
||||||
|
try {
|
||||||
|
Class<?> name = Class.forName(providerClassName);
|
||||||
|
provider = (Provider) name.newInstance();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
LOG.info("Security Provider class '{}' not found", providerClassName);
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
LOG.info("Security Provider class '{}' could not be created", providerClassName);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
LOG.info("Security Provider class '{}' could not be accessed", providerClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (provider == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (Security.getProvider(provider.getName()) == null) {
|
||||||
|
Security.addProvider(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (securityProvider == null) {
|
||||||
|
MessageDigest.getInstance("MD5", provider.getName());
|
||||||
|
KeyAgreement.getInstance("DH", provider.getName());
|
||||||
|
setSecurityProvider(provider.getName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
LOG.info(format("Security Provider '%s' does not support necessary algorithm", providerClassName), e);
|
||||||
|
} catch (NoSuchProviderException e) {
|
||||||
|
LOG.info("Registration of Security Provider '{}' unexpectedly failed", providerClassName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static synchronized Cipher getCipher(String transformation)
|
public static synchronized Cipher getCipher(String transformation)
|
||||||
throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {
|
throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {
|
||||||
register();
|
register();
|
||||||
@@ -100,9 +94,7 @@ public class SecurityUtils {
|
|||||||
* Computes the fingerprint for a public key, in the standard SSH format, e.g. "4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21"
|
* Computes the fingerprint for a public key, in the standard SSH format, e.g. "4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21"
|
||||||
*
|
*
|
||||||
* @param key the public key
|
* @param key the public key
|
||||||
*
|
|
||||||
* @return the fingerprint
|
* @return the fingerprint
|
||||||
*
|
|
||||||
* @see <a href="http://tools.ietf.org/html/draft-friedl-secsh-fingerprint-00">specification</a>
|
* @see <a href="http://tools.ietf.org/html/draft-friedl-secsh-fingerprint-00">specification</a>
|
||||||
*/
|
*/
|
||||||
public static String getFingerprint(PublicKey key) {
|
public static String getFingerprint(PublicKey key) {
|
||||||
@@ -125,9 +117,7 @@ public class SecurityUtils {
|
|||||||
* Creates a new instance of {@link KeyAgreement} with the given algorithm.
|
* Creates a new instance of {@link KeyAgreement} with the given algorithm.
|
||||||
*
|
*
|
||||||
* @param algorithm key agreement algorithm
|
* @param algorithm key agreement algorithm
|
||||||
*
|
|
||||||
* @return new instance
|
* @return new instance
|
||||||
*
|
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
@@ -144,9 +134,7 @@ public class SecurityUtils {
|
|||||||
* Creates a new instance of {@link KeyFactory} with the given algorithm.
|
* Creates a new instance of {@link KeyFactory} with the given algorithm.
|
||||||
*
|
*
|
||||||
* @param algorithm key factory algorithm e.g. RSA, DSA
|
* @param algorithm key factory algorithm e.g. RSA, DSA
|
||||||
*
|
|
||||||
* @return new instance
|
* @return new instance
|
||||||
*
|
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
@@ -163,9 +151,7 @@ public class SecurityUtils {
|
|||||||
* Creates a new instance of {@link KeyPairGenerator} with the given algorithm.
|
* Creates a new instance of {@link KeyPairGenerator} with the given algorithm.
|
||||||
*
|
*
|
||||||
* @param algorithm key pair generator algorithm
|
* @param algorithm key pair generator algorithm
|
||||||
*
|
|
||||||
* @return new instance
|
* @return new instance
|
||||||
*
|
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
@@ -182,9 +168,7 @@ public class SecurityUtils {
|
|||||||
* Create a new instance of {@link Mac} with the given algorithm.
|
* Create a new instance of {@link Mac} with the given algorithm.
|
||||||
*
|
*
|
||||||
* @param algorithm MAC algorithm
|
* @param algorithm MAC algorithm
|
||||||
*
|
|
||||||
* @return new instance
|
* @return new instance
|
||||||
*
|
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
@@ -201,9 +185,7 @@ public class SecurityUtils {
|
|||||||
* Create a new instance of {@link MessageDigest} with the given algorithm.
|
* Create a new instance of {@link MessageDigest} with the given algorithm.
|
||||||
*
|
*
|
||||||
* @param algorithm MessageDigest algorithm name
|
* @param algorithm MessageDigest algorithm name
|
||||||
*
|
|
||||||
* @return new instance
|
* @return new instance
|
||||||
*
|
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* @throws NoSuchProviderException
|
* @throws NoSuchProviderException
|
||||||
*/
|
*/
|
||||||
@@ -263,20 +245,16 @@ public class SecurityUtils {
|
|||||||
|
|
||||||
private static void register() {
|
private static void register() {
|
||||||
if (!registrationDone) {
|
if (!registrationDone) {
|
||||||
if (securityProvider == null && (registerBouncyCastle == null || registerBouncyCastle))
|
if (securityProvider == null && (registerBouncyCastle == null || registerBouncyCastle)) {
|
||||||
// Use an inner class to avoid a strong dependency on BouncyCastle
|
registerSecurityProvider("org.bouncycastle.jce.provider.BouncyCastleProvider");
|
||||||
try {
|
if (securityProvider == null && registerBouncyCastle == null) {
|
||||||
new BouncyCastleRegistration().run();
|
LOG.info("BouncyCastle not registered, using the default JCE provider");
|
||||||
} catch (Throwable t) {
|
} else if (securityProvider == null) {
|
||||||
if (registerBouncyCastle == null)
|
LOG.error("Failed to register BouncyCastle as the defaut JCE provider");
|
||||||
LOG.info("BouncyCastle not registered, using the default JCE provider");
|
throw new SSHRuntimeException("Failed to register BouncyCastle as the defaut JCE provider");
|
||||||
else {
|
|
||||||
LOG.error("Failed to register BouncyCastle as the defaut JCE provider");
|
|
||||||
throw new SSHRuntimeException("Failed to register BouncyCastle as the defaut JCE provider", t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
registrationDone = true;
|
}
|
||||||
}
|
}
|
||||||
|
registrationDone = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,10 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.concurrent.Event;
|
import net.schmizz.concurrent.Event;
|
||||||
import net.schmizz.concurrent.ExceptionChainer;
|
import net.schmizz.concurrent.ExceptionChainer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -39,8 +39,8 @@ public class StreamCopier {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private final LoggerFactory loggerFactory;
|
||||||
|
private final Logger log;
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
|
|
||||||
@@ -50,9 +50,11 @@ public class StreamCopier {
|
|||||||
private boolean keepFlushing = true;
|
private boolean keepFlushing = true;
|
||||||
private long length = -1;
|
private long length = -1;
|
||||||
|
|
||||||
public StreamCopier(InputStream in, OutputStream out) {
|
public StreamCopier(InputStream in, OutputStream out, LoggerFactory loggerFactory) {
|
||||||
this.in = in;
|
this.in = in;
|
||||||
this.out = out;
|
this.out = out;
|
||||||
|
this.loggerFactory = loggerFactory;
|
||||||
|
this.log = loggerFactory.getLogger(getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
public StreamCopier bufSize(int bufSize) {
|
public StreamCopier bufSize(int bufSize) {
|
||||||
@@ -91,7 +93,7 @@ public class StreamCopier {
|
|||||||
public IOException chain(Throwable t) {
|
public IOException chain(Throwable t) {
|
||||||
return (t instanceof IOException) ? (IOException) t : new IOException(t);
|
return (t instanceof IOException) ? (IOException) t : new IOException(t);
|
||||||
}
|
}
|
||||||
});
|
}, loggerFactory);
|
||||||
|
|
||||||
new Thread() {
|
new Thread() {
|
||||||
{
|
{
|
||||||
@@ -107,7 +109,7 @@ public class StreamCopier {
|
|||||||
log.debug("Done copying from {}", in);
|
log.debug("Done copying from {}", in);
|
||||||
doneEvent.set();
|
doneEvent.set();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
log.error("In pipe from {} to {}: " + ioe.toString(), in, out);
|
log.error(String.format("In pipe from %1$s to %2$s", in.toString(), out.toString()), ioe);
|
||||||
doneEvent.deliverError(ioe);
|
doneEvent.deliverError(ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +138,7 @@ public class StreamCopier {
|
|||||||
|
|
||||||
final double timeSeconds = (System.currentTimeMillis() - startTime) / 1000.0;
|
final double timeSeconds = (System.currentTimeMillis() - startTime) / 1000.0;
|
||||||
final double sizeKiB = count / 1024.0;
|
final double sizeKiB = count / 1024.0;
|
||||||
log.info(sizeKiB + " KiB transferred in {} seconds ({} KiB/s)", timeSeconds, (sizeKiB / timeSeconds));
|
log.debug(String.format("%1$,.1f KiB transferred in %2$,.1f seconds (%3$,.2f KiB/s)", sizeKiB, timeSeconds, (sizeKiB / timeSeconds)));
|
||||||
|
|
||||||
if (length != -1 && read == -1)
|
if (length != -1 && read == -1)
|
||||||
throw new IOException("Encountered EOF, could not transfer " + length + " bytes");
|
throw new IOException("Encountered EOF, could not transfer " + length + " bytes");
|
||||||
@@ -154,4 +156,4 @@ public class StreamCopier {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
package net.schmizz.sshj.connection;
|
package net.schmizz.sshj.connection;
|
||||||
|
|
||||||
import net.schmizz.concurrent.Promise;
|
import net.schmizz.concurrent.Promise;
|
||||||
|
import net.schmizz.keepalive.KeepAlive;
|
||||||
import net.schmizz.sshj.common.SSHPacket;
|
import net.schmizz.sshj.common.SSHPacket;
|
||||||
import net.schmizz.sshj.connection.channel.Channel;
|
import net.schmizz.sshj.connection.channel.Channel;
|
||||||
import net.schmizz.sshj.connection.channel.OpenFailException;
|
import net.schmizz.sshj.connection.channel.OpenFailException;
|
||||||
@@ -125,29 +126,34 @@ public interface Connection {
|
|||||||
void setMaxPacketSize(int maxPacketSize);
|
void setMaxPacketSize(int maxPacketSize);
|
||||||
|
|
||||||
/** @return the size for the local window this connection recommends to any {@link Channel}'s that ask for it. */
|
/** @return the size for the local window this connection recommends to any {@link Channel}'s that ask for it. */
|
||||||
int getWindowSize();
|
long getWindowSize();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the size for the local window this connection recommends to any {@link Channel}'s that ask for it.
|
* Set the size for the local window this connection recommends to any {@link Channel}'s that ask for it.
|
||||||
*
|
*
|
||||||
* @param windowSize window size in bytes
|
* @param windowSize window size in bytes
|
||||||
*/
|
*/
|
||||||
void setWindowSize(int windowSize);
|
void setWindowSize(long windowSize);
|
||||||
|
|
||||||
/** @return the associated {@link Transport}. */
|
/** @return the associated {@link Transport}. */
|
||||||
Transport getTransport();
|
Transport getTransport();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the {@code timeout} in seconds that this connection uses for blocking operations and recommends to any
|
* @return the {@code timeout} in milliseconds that this connection uses for blocking operations and recommends to
|
||||||
* {@link Channel other} {@link ForwardedChannelOpener classes} that ask for it.
|
* any {@link Channel other} {@link ForwardedChannelOpener classes} that ask for it.
|
||||||
*/
|
*/
|
||||||
int getTimeout();
|
int getTimeoutMs();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@code timeout} this connection uses for blocking operations and recommends to any {@link Channel other}
|
* Set the {@code timeout} this connection uses for blocking operations and recommends to any {@link Channel other}
|
||||||
* {@link ForwardedChannelOpener classes} that ask for it.
|
* {@link ForwardedChannelOpener classes} that ask for it.
|
||||||
*
|
*
|
||||||
* @param timeout timeout in seconds
|
* @param timeout timeout in milliseconds
|
||||||
*/
|
*/
|
||||||
void setTimeout(int timeout);
|
void setTimeoutMs(int timeout);
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* @return The configured {@link net.schmizz.keepalive.KeepAlive} mechanism.
|
||||||
|
*/
|
||||||
|
KeepAlive getKeepAlive();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,13 +17,10 @@ package net.schmizz.sshj.connection;
|
|||||||
|
|
||||||
import net.schmizz.concurrent.ErrorDeliveryUtil;
|
import net.schmizz.concurrent.ErrorDeliveryUtil;
|
||||||
import net.schmizz.concurrent.Promise;
|
import net.schmizz.concurrent.Promise;
|
||||||
|
import net.schmizz.keepalive.KeepAlive;
|
||||||
|
import net.schmizz.keepalive.KeepAliveProvider;
|
||||||
import net.schmizz.sshj.AbstractService;
|
import net.schmizz.sshj.AbstractService;
|
||||||
import net.schmizz.sshj.common.Buffer;
|
import net.schmizz.sshj.common.*;
|
||||||
import net.schmizz.sshj.common.DisconnectReason;
|
|
||||||
import net.schmizz.sshj.common.ErrorNotifiable;
|
|
||||||
import net.schmizz.sshj.common.Message;
|
|
||||||
import net.schmizz.sshj.common.SSHException;
|
|
||||||
import net.schmizz.sshj.common.SSHPacket;
|
|
||||||
import net.schmizz.sshj.connection.channel.Channel;
|
import net.schmizz.sshj.connection.channel.Channel;
|
||||||
import net.schmizz.sshj.connection.channel.OpenFailException.Reason;
|
import net.schmizz.sshj.connection.channel.OpenFailException.Reason;
|
||||||
import net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener;
|
import net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener;
|
||||||
@@ -51,21 +48,29 @@ public class ConnectionImpl
|
|||||||
|
|
||||||
private final Queue<Promise<SSHPacket, ConnectionException>> globalReqPromises = new LinkedList<Promise<SSHPacket, ConnectionException>>();
|
private final Queue<Promise<SSHPacket, ConnectionException>> globalReqPromises = new LinkedList<Promise<SSHPacket, ConnectionException>>();
|
||||||
|
|
||||||
private int windowSize = 2048 * 1024;
|
/** {@code keep-alive} mechanism */
|
||||||
|
private final KeepAlive keepAlive;
|
||||||
|
|
||||||
|
private long windowSize = 2048 * 1024;
|
||||||
private int maxPacketSize = 32 * 1024;
|
private int maxPacketSize = 32 * 1024;
|
||||||
|
|
||||||
|
private volatile int timeoutMs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create with an associated {@link Transport}.
|
* Create with an associated {@link Transport}.
|
||||||
*
|
*
|
||||||
* @param trans transport layer
|
* @param trans transport layer
|
||||||
|
* @param keepAlive the keep alive provider
|
||||||
*/
|
*/
|
||||||
public ConnectionImpl(Transport trans) {
|
public ConnectionImpl(Transport trans, KeepAliveProvider keepAlive) {
|
||||||
super("ssh-connection", trans);
|
super("ssh-connection", trans);
|
||||||
|
timeoutMs = trans.getTimeoutMs();
|
||||||
|
this.keepAlive = keepAlive.provide(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attach(Channel chan) {
|
public void attach(Channel chan) {
|
||||||
log.info("Attaching `{}` channel (#{})", chan.getType(), chan.getID());
|
log.debug("Attaching `{}` channel (#{})", chan.getType(), chan.getID());
|
||||||
channels.put(chan.getID(), chan);
|
channels.put(chan.getID(), chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +86,7 @@ public class ConnectionImpl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forget(Channel chan) {
|
public void forget(Channel chan) {
|
||||||
log.info("Forgetting `{}` channel (#{})", chan.getType(), chan.getID());
|
log.debug("Forgetting `{}` channel (#{})", chan.getType(), chan.getID());
|
||||||
channels.remove(chan.getID());
|
channels.remove(chan.getID());
|
||||||
synchronized (internalSynchronizer) {
|
synchronized (internalSynchronizer) {
|
||||||
if (channels.isEmpty())
|
if (channels.isEmpty())
|
||||||
@@ -91,13 +96,13 @@ public class ConnectionImpl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forget(ForwardedChannelOpener opener) {
|
public void forget(ForwardedChannelOpener opener) {
|
||||||
log.info("Forgetting opener for `{}` channels: {}", opener.getChannelType(), opener);
|
log.debug("Forgetting opener for `{}` channels: {}", opener.getChannelType(), opener);
|
||||||
openers.remove(opener.getChannelType());
|
openers.remove(opener.getChannelType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attach(ForwardedChannelOpener opener) {
|
public void attach(ForwardedChannelOpener opener) {
|
||||||
log.info("Attaching opener for `{}` channels: {}", opener.getChannelType(), opener);
|
log.debug("Attaching opener for `{}` channels: {}", opener.getChannelType(), opener);
|
||||||
openers.put(opener.getChannelType(), opener);
|
openers.put(opener.getChannelType(), opener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,12 +164,12 @@ public class ConnectionImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWindowSize() {
|
public long getWindowSize() {
|
||||||
return windowSize;
|
return windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setWindowSize(int windowSize) {
|
public void setWindowSize(long windowSize) {
|
||||||
this.windowSize = windowSize;
|
this.windowSize = windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,14 +192,14 @@ public class ConnectionImpl
|
|||||||
byte[] specifics)
|
byte[] specifics)
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
synchronized (globalReqPromises) {
|
synchronized (globalReqPromises) {
|
||||||
log.info("Making global request for `{}`", name);
|
log.debug("Making global request for `{}`", name);
|
||||||
trans.write(new SSHPacket(Message.GLOBAL_REQUEST).putString(name)
|
trans.write(new SSHPacket(Message.GLOBAL_REQUEST).putString(name)
|
||||||
.putBoolean(wantReply)
|
.putBoolean(wantReply)
|
||||||
.putRawBytes(specifics));
|
.putRawBytes(specifics));
|
||||||
|
|
||||||
Promise<SSHPacket, ConnectionException> promise = null;
|
Promise<SSHPacket, ConnectionException> promise = null;
|
||||||
if (wantReply) {
|
if (wantReply) {
|
||||||
promise = new Promise<SSHPacket, ConnectionException>("global req for " + name, ConnectionException.chainer);
|
promise = new Promise<SSHPacket, ConnectionException>("global req for " + name, ConnectionException.chainer, trans.getConfig().getLoggerFactory());
|
||||||
globalReqPromises.add(promise);
|
globalReqPromises.add(promise);
|
||||||
}
|
}
|
||||||
return promise;
|
return promise;
|
||||||
@@ -205,13 +210,15 @@ public class ConnectionImpl
|
|||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
synchronized (globalReqPromises) {
|
synchronized (globalReqPromises) {
|
||||||
Promise<SSHPacket, ConnectionException> gr = globalReqPromises.poll();
|
Promise<SSHPacket, ConnectionException> gr = globalReqPromises.poll();
|
||||||
if (gr == null)
|
if (gr == null) {
|
||||||
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR,
|
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR,
|
||||||
"Got a global request response when none was requested");
|
"Got a global request response when none was requested");
|
||||||
else if (response == null)
|
} else if (response == null) {
|
||||||
gr.deliverError(new ConnectionException("Global request [" + gr + "] failed"));
|
gr.deliverError(new ConnectionException("Global request [" + gr + "] failed"));
|
||||||
else
|
} else {
|
||||||
gr.deliver(response);
|
// To prevent a race condition, copy the packet before delivering, as it will be handled in a different thread.
|
||||||
|
gr.deliver(new SSHPacket(response));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,8 +254,24 @@ public class ConnectionImpl
|
|||||||
ErrorDeliveryUtil.alertPromises(error, globalReqPromises);
|
ErrorDeliveryUtil.alertPromises(error, globalReqPromises);
|
||||||
globalReqPromises.clear();
|
globalReqPromises.clear();
|
||||||
}
|
}
|
||||||
|
keepAlive.interrupt();
|
||||||
ErrorNotifiable.Util.alertAll(error, channels.values());
|
ErrorNotifiable.Util.alertAll(error, channels.values());
|
||||||
channels.clear();
|
channels.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public void setTimeoutMs(int timeoutMs) {
|
||||||
|
this.timeoutMs = timeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTimeoutMs() {
|
||||||
|
return timeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeepAlive getKeepAlive() {
|
||||||
|
return keepAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,44 +12,17 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
import net.schmizz.concurrent.ErrorDeliveryUtil;
|
import net.schmizz.concurrent.ErrorDeliveryUtil;
|
||||||
import net.schmizz.concurrent.Event;
|
import net.schmizz.concurrent.Event;
|
||||||
import net.schmizz.sshj.common.Buffer;
|
import net.schmizz.sshj.common.*;
|
||||||
import net.schmizz.sshj.common.ByteArrayUtils;
|
|
||||||
import net.schmizz.sshj.common.DisconnectReason;
|
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
|
||||||
import net.schmizz.sshj.common.Message;
|
|
||||||
import net.schmizz.sshj.common.SSHException;
|
|
||||||
import net.schmizz.sshj.common.SSHPacket;
|
|
||||||
import net.schmizz.sshj.connection.Connection;
|
import net.schmizz.sshj.connection.Connection;
|
||||||
import net.schmizz.sshj.connection.ConnectionException;
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
import net.schmizz.sshj.transport.Transport;
|
import net.schmizz.sshj.transport.Transport;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -61,8 +34,11 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
public abstract class AbstractChannel
|
public abstract class AbstractChannel
|
||||||
implements Channel {
|
implements Channel {
|
||||||
|
|
||||||
|
private static final int REMOTE_MAX_PACKET_SIZE_CEILING = 1024 * 1024;
|
||||||
|
|
||||||
/** Logger */
|
/** Logger */
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final LoggerFactory loggerFactory;
|
||||||
|
protected final Logger log;
|
||||||
|
|
||||||
/** Transport layer */
|
/** Transport layer */
|
||||||
protected final Transport trans;
|
protected final Transport trans;
|
||||||
@@ -76,18 +52,17 @@ public abstract class AbstractChannel
|
|||||||
/** Remote recipient ID */
|
/** Remote recipient ID */
|
||||||
private int recipient;
|
private int recipient;
|
||||||
|
|
||||||
|
private boolean eof = false;
|
||||||
|
|
||||||
private final Queue<Event<ConnectionException>> chanReqResponseEvents = new LinkedList<Event<ConnectionException>>();
|
private final Queue<Event<ConnectionException>> chanReqResponseEvents = new LinkedList<Event<ConnectionException>>();
|
||||||
|
|
||||||
/* The lock used by to create the open & close events */
|
/* The lock used by to create the open & close events */
|
||||||
private final ReentrantLock lock = new ReentrantLock();
|
private final ReentrantLock openCloseLock = new ReentrantLock();
|
||||||
/** Channel open event */
|
/** Channel open event */
|
||||||
protected final Event<ConnectionException> open;
|
protected final Event<ConnectionException> openEvent;
|
||||||
/** Channel close event */
|
/** Channel close event */
|
||||||
protected final Event<ConnectionException> close;
|
protected final Event<ConnectionException> closeEvent;
|
||||||
|
/** Whether we have already sent a CHANNEL_CLOSE request to the server */
|
||||||
/* Access to these fields should be synchronized using this object */
|
|
||||||
private boolean eofSent;
|
|
||||||
private boolean eofGot;
|
|
||||||
private boolean closeRequested;
|
private boolean closeRequested;
|
||||||
|
|
||||||
/** Local window */
|
/** Local window */
|
||||||
@@ -104,23 +79,25 @@ public abstract class AbstractChannel
|
|||||||
|
|
||||||
protected AbstractChannel(Connection conn, String type) {
|
protected AbstractChannel(Connection conn, String type) {
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
|
this.loggerFactory = conn.getTransport().getConfig().getLoggerFactory();
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.log = loggerFactory.getLogger(getClass());
|
||||||
this.trans = conn.getTransport();
|
this.trans = conn.getTransport();
|
||||||
|
|
||||||
id = conn.nextID();
|
id = conn.nextID();
|
||||||
|
|
||||||
lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize());
|
lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize(), loggerFactory);
|
||||||
in = new ChannelInputStream(this, trans, lwin);
|
in = new ChannelInputStream(this, trans, lwin);
|
||||||
|
|
||||||
open = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, lock);
|
openEvent = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, openCloseLock, loggerFactory);
|
||||||
close = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, lock);
|
closeEvent = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, openCloseLock, loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void init(int recipient, int remoteWinSize, int remoteMaxPacketSize) {
|
protected void init(int recipient, long remoteWinSize, long remoteMaxPacketSize) {
|
||||||
this.recipient = recipient;
|
this.recipient = recipient;
|
||||||
rwin = new Window.Remote(remoteWinSize, remoteMaxPacketSize);
|
rwin = new Window.Remote(remoteWinSize, (int) Math.min(remoteMaxPacketSize, REMOTE_MAX_PACKET_SIZE_CEILING), loggerFactory);
|
||||||
out = new ChannelOutputStream(this, trans, rwin);
|
out = new ChannelOutputStream(this, trans, rwin);
|
||||||
log.info("Initialized - {}", this);
|
log.debug("Initialized - {}", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -144,7 +121,7 @@ public abstract class AbstractChannel
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLocalWinSize() {
|
public long getLocalWinSize() {
|
||||||
return lwin.getSize();
|
return lwin.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +141,7 @@ public abstract class AbstractChannel
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRemoteWinSize() {
|
public long getRemoteWinSize() {
|
||||||
return rwin.getSize();
|
return rwin.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,9 +193,19 @@ public abstract class AbstractChannel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEOF() {
|
||||||
|
return eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoggerFactory getLoggerFactory() {
|
||||||
|
return loggerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
private void gotClose()
|
private void gotClose()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
log.info("Got close");
|
log.debug("Got close");
|
||||||
try {
|
try {
|
||||||
closeAllStreams();
|
closeAllStreams();
|
||||||
sendClose();
|
sendClose();
|
||||||
@@ -236,7 +223,7 @@ public abstract class AbstractChannel
|
|||||||
public void notifyError(SSHException error) {
|
public void notifyError(SSHException error) {
|
||||||
log.debug("Channel #{} got notified of {}", getID(), error.toString());
|
log.debug("Channel #{} got notified of {}", getID(), error.toString());
|
||||||
|
|
||||||
ErrorDeliveryUtil.alertEvents(error, open, close);
|
ErrorDeliveryUtil.alertEvents(error, openEvent, closeEvent);
|
||||||
ErrorDeliveryUtil.alertEvents(error, chanReqResponseEvents);
|
ErrorDeliveryUtil.alertEvents(error, chanReqResponseEvents);
|
||||||
|
|
||||||
in.notifyError(error);
|
in.notifyError(error);
|
||||||
@@ -254,49 +241,53 @@ public abstract class AbstractChannel
|
|||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
lock.lock();
|
openCloseLock.lock();
|
||||||
try {
|
try {
|
||||||
try {
|
if (isOpen()) {
|
||||||
sendClose();
|
try {
|
||||||
} catch (TransportException e) {
|
sendClose();
|
||||||
if (!close.inError())
|
} catch (TransportException e) {
|
||||||
throw e;
|
if (!closeEvent.inError())
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
closeEvent.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
close.await(conn.getTimeout(), TimeUnit.SECONDS);
|
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
openCloseLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void join()
|
public void join()
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
close.await();
|
closeEvent.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void join(int timeout, TimeUnit unit)
|
public void join(long timeout, TimeUnit unit)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
close.await(timeout, unit);
|
closeEvent.await(timeout, unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void sendClose()
|
protected void sendClose()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
|
openCloseLock.lock();
|
||||||
try {
|
try {
|
||||||
if (!closeRequested) {
|
if (!closeRequested) {
|
||||||
log.info("Sending close");
|
log.debug("Sending close");
|
||||||
trans.write(newBuffer(Message.CHANNEL_CLOSE));
|
trans.write(newBuffer(Message.CHANNEL_CLOSE));
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
closeRequested = true;
|
closeRequested = true;
|
||||||
|
openCloseLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isOpen() {
|
public boolean isOpen() {
|
||||||
lock.lock();
|
openCloseLock.lock();
|
||||||
try {
|
try {
|
||||||
return open.isSet() && !close.isSet() && !closeRequested;
|
return openEvent.isSet() && !closeEvent.isSet() && !closeRequested;
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
openCloseLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,25 +300,25 @@ public abstract class AbstractChannel
|
|||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
}
|
}
|
||||||
log.info("Got chan request for `{}`", reqType);
|
log.debug("Got chan request for `{}`", reqType);
|
||||||
handleRequest(reqType, buf);
|
handleRequest(reqType, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotWindowAdjustment(SSHPacket buf)
|
private void gotWindowAdjustment(SSHPacket buf)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
final int howMuch;
|
final long howMuch;
|
||||||
try {
|
try {
|
||||||
howMuch = buf.readUInt32AsInt();
|
howMuch = buf.readUInt32();
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
}
|
}
|
||||||
log.info("Received window adjustment for {} bytes", howMuch);
|
log.debug("Received window adjustment for {} bytes", howMuch);
|
||||||
rwin.expand(howMuch);
|
rwin.expand(howMuch);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void finishOff() {
|
protected void finishOff() {
|
||||||
conn.forget(this);
|
conn.forget(this);
|
||||||
close.set();
|
closeEvent.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void gotExtendedData(SSHPacket buf)
|
protected void gotExtendedData(SSHPacket buf)
|
||||||
@@ -364,67 +355,53 @@ public abstract class AbstractChannel
|
|||||||
stream.receive(buf.array(), buf.rpos(), len);
|
stream.receive(buf.array(), buf.rpos(), len);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized Event<ConnectionException> sendChannelRequest(String reqType, boolean wantReply,
|
protected Event<ConnectionException> sendChannelRequest(String reqType, boolean wantReply,
|
||||||
Buffer.PlainBuffer reqSpecific)
|
Buffer.PlainBuffer reqSpecific)
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
log.info("Sending channel request for `{}`", reqType);
|
log.debug("Sending channel request for `{}`", reqType);
|
||||||
trans.write(
|
synchronized (chanReqResponseEvents) {
|
||||||
newBuffer(Message.CHANNEL_REQUEST)
|
trans.write(
|
||||||
.putString(reqType)
|
newBuffer(Message.CHANNEL_REQUEST)
|
||||||
.putBoolean(wantReply)
|
.putString(reqType)
|
||||||
.putBuffer(reqSpecific)
|
.putBoolean(wantReply)
|
||||||
);
|
.putBuffer(reqSpecific)
|
||||||
|
);
|
||||||
|
|
||||||
Event<ConnectionException> responseEvent = null;
|
Event<ConnectionException> responseEvent = null;
|
||||||
if (wantReply) {
|
if (wantReply) {
|
||||||
responseEvent = new Event<ConnectionException>("chan#" + id + " / " + "chanreq for " + reqType, ConnectionException.chainer, lock);
|
responseEvent = new Event<ConnectionException>("chan#" + id + " / " + "chanreq for " + reqType,
|
||||||
chanReqResponseEvents.add(responseEvent);
|
ConnectionException.chainer, loggerFactory);
|
||||||
|
chanReqResponseEvents.add(responseEvent);
|
||||||
|
}
|
||||||
|
return responseEvent;
|
||||||
}
|
}
|
||||||
return responseEvent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void gotResponse(boolean success)
|
private void gotResponse(boolean success)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll();
|
synchronized (chanReqResponseEvents) {
|
||||||
if (responseEvent != null) {
|
final Event<ConnectionException> responseEvent = chanReqResponseEvents.poll();
|
||||||
if (success)
|
if (responseEvent != null) {
|
||||||
responseEvent.set();
|
if (success)
|
||||||
else
|
responseEvent.set();
|
||||||
responseEvent.deliverError(new ConnectionException("Request failed"));
|
else
|
||||||
} else
|
responseEvent.deliverError(new ConnectionException("Request failed"));
|
||||||
throw new ConnectionException(
|
} else
|
||||||
DisconnectReason.PROTOCOL_ERROR,
|
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR,
|
||||||
"Received response to channel request when none was requested");
|
"Received response to channel request when none was requested");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void gotEOF()
|
private void gotEOF()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
log.info("Got EOF");
|
log.debug("Got EOF");
|
||||||
eofGot = true;
|
|
||||||
eofInputStreams();
|
eofInputStreams();
|
||||||
if (eofSent)
|
|
||||||
sendClose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when EOF has been received. Subclasses can override but must call super. */
|
/** Called when EOF has been received. Subclasses can override but must call super. */
|
||||||
protected void eofInputStreams() {
|
protected void eofInputStreams() {
|
||||||
in.eof();
|
in.eof();
|
||||||
}
|
eof = true;
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void sendEOF()
|
|
||||||
throws TransportException {
|
|
||||||
try {
|
|
||||||
if (!closeRequested && !eofSent) {
|
|
||||||
log.info("Sending EOF");
|
|
||||||
trans.write(newBuffer(Message.CHANNEL_EOF));
|
|
||||||
if (eofGot)
|
|
||||||
sendClose();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
eofSent = true;
|
|
||||||
out.setClosed();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -434,4 +411,4 @@ public abstract class AbstractChannel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.ErrorNotifiable;
|
import net.schmizz.sshj.common.ErrorNotifiable;
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.sshj.common.SSHPacketHandler;
|
import net.schmizz.sshj.common.SSHPacketHandler;
|
||||||
import net.schmizz.sshj.connection.ConnectionException;
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
@@ -25,13 +26,15 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/** A channel is the basic medium for application-layer data on top of an SSH transport. */
|
/**
|
||||||
public interface Channel
|
* A channel is the basic medium for application-layer data on top of an SSH transport.
|
||||||
extends Closeable, SSHPacketHandler, ErrorNotifiable {
|
*/
|
||||||
|
public interface Channel extends Closeable, SSHPacketHandler, ErrorNotifiable {
|
||||||
|
|
||||||
/** Direct channels are those that are initiated by us. */
|
/**
|
||||||
interface Direct
|
* Direct channels are those that are initiated by us.
|
||||||
extends Channel {
|
*/
|
||||||
|
interface Direct extends Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request opening this channel from remote end.
|
* Request opening this channel from remote end.
|
||||||
@@ -40,27 +43,30 @@ public interface Channel
|
|||||||
* @throws ConnectionException other connection-layer error
|
* @throws ConnectionException other connection-layer error
|
||||||
* @throws TransportException error writing packets etc.
|
* @throws TransportException error writing packets etc.
|
||||||
*/
|
*/
|
||||||
void open()
|
void open() throws ConnectionException, TransportException;
|
||||||
throws ConnectionException, TransportException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Forwarded channels are those that are initiated by the server. */
|
/**
|
||||||
interface Forwarded
|
* Forwarded channels are those that are initiated by the server.
|
||||||
extends Channel {
|
*/
|
||||||
|
interface Forwarded extends Channel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Confirm {@code CHANNEL_OPEN} request.
|
* Confirm {@code CHANNEL_OPEN} request.
|
||||||
*
|
*
|
||||||
* @throws TransportException error sending confirmation packet
|
* @throws TransportException error sending confirmation packet
|
||||||
*/
|
*/
|
||||||
void confirm()
|
void confirm() throws TransportException;
|
||||||
throws TransportException;
|
|
||||||
|
|
||||||
/** @return the IP of where the forwarded connection originates. */
|
/**
|
||||||
|
* @return the IP of where the forwarded connection originates.
|
||||||
|
*/
|
||||||
String getOriginatorIP();
|
String getOriginatorIP();
|
||||||
|
|
||||||
/** @return port from which the forwarded connection originates. */
|
/**
|
||||||
|
* @return port from which the forwarded connection originates.
|
||||||
|
*/
|
||||||
int getOriginatorPort();
|
int getOriginatorPort();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,65 +74,74 @@ public interface Channel
|
|||||||
*
|
*
|
||||||
* @param reason indicate {@link OpenFailException.Reason reason} for rejection of the request
|
* @param reason indicate {@link OpenFailException.Reason reason} for rejection of the request
|
||||||
* @param message indicate a message for why the request is rejected
|
* @param message indicate a message for why the request is rejected
|
||||||
*
|
|
||||||
* @throws TransportException error sending rejection packet
|
* @throws TransportException error sending rejection packet
|
||||||
*/
|
*/
|
||||||
void reject(OpenFailException.Reason reason, String message)
|
void reject(OpenFailException.Reason reason, String message) throws TransportException;
|
||||||
throws TransportException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Close this channel. */
|
/**
|
||||||
|
* Close this channel.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
void close()
|
void close() throws TransportException, ConnectionException;
|
||||||
throws TransportException, ConnectionException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whether auto-expansion of local window is set.
|
* @return whether auto-expansion of local window is set.
|
||||||
*
|
|
||||||
* @see #setAutoExpand(boolean)
|
* @see #setAutoExpand(boolean)
|
||||||
*/
|
*/
|
||||||
boolean getAutoExpand();
|
boolean getAutoExpand();
|
||||||
|
|
||||||
/** @return the channel ID */
|
/**
|
||||||
|
* @return the channel ID
|
||||||
|
*/
|
||||||
int getID();
|
int getID();
|
||||||
|
|
||||||
/** @return the {@code InputStream} for this channel. */
|
/**
|
||||||
|
* @return the {@code InputStream} for this channel.
|
||||||
|
*/
|
||||||
InputStream getInputStream();
|
InputStream getInputStream();
|
||||||
|
|
||||||
/** @return the maximum packet size that we have specified. */
|
/**
|
||||||
|
* @return the maximum packet size that we have specified.
|
||||||
|
*/
|
||||||
int getLocalMaxPacketSize();
|
int getLocalMaxPacketSize();
|
||||||
|
|
||||||
/** @return the current local window size. */
|
/**
|
||||||
int getLocalWinSize();
|
* @return the current local window size.
|
||||||
|
*/
|
||||||
/** @return an {@code OutputStream} for this channel. */
|
long getLocalWinSize();
|
||||||
OutputStream getOutputStream();
|
|
||||||
|
|
||||||
/** @return the channel ID at the remote end. */
|
|
||||||
int getRecipient();
|
|
||||||
|
|
||||||
/** @return the maximum packet size as specified by the remote end. */
|
|
||||||
int getRemoteMaxPacketSize();
|
|
||||||
|
|
||||||
/** @return the current remote window size. */
|
|
||||||
int getRemoteWinSize();
|
|
||||||
|
|
||||||
/** @return the channel type identifier. */
|
|
||||||
String getType();
|
|
||||||
|
|
||||||
/** @return whether the channel is open. */
|
|
||||||
boolean isOpen();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends an EOF message to the server for this channel; indicating that no more data will be sent by us. The {@code
|
* @return an {@code OutputStream} for this channel.
|
||||||
* OutputStream} for this channel will be closed and no longer usable.
|
|
||||||
*
|
|
||||||
* @throws TransportException if there is an error sending the EOF message
|
|
||||||
*/
|
*/
|
||||||
void sendEOF()
|
OutputStream getOutputStream();
|
||||||
throws TransportException;
|
|
||||||
|
/**
|
||||||
|
* @return the channel ID at the remote end.
|
||||||
|
*/
|
||||||
|
int getRecipient();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the maximum packet size as specified by the remote end.
|
||||||
|
*/
|
||||||
|
int getRemoteMaxPacketSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current remote window size.
|
||||||
|
*/
|
||||||
|
long getRemoteWinSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the channel type identifier.
|
||||||
|
*/
|
||||||
|
String getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return whether the channel is open.
|
||||||
|
*/
|
||||||
|
boolean isOpen();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether local window should automatically expand when data is received, irrespective of whether data has been
|
* Set whether local window should automatically expand when data is received, irrespective of whether data has been
|
||||||
@@ -137,10 +152,17 @@ public interface Channel
|
|||||||
*/
|
*/
|
||||||
void setAutoExpand(boolean autoExpand);
|
void setAutoExpand(boolean autoExpand);
|
||||||
|
|
||||||
void join()
|
void join() throws ConnectionException;
|
||||||
throws ConnectionException;
|
|
||||||
|
|
||||||
void join(int timeout, TimeUnit unit)
|
void join(long timeout, TimeUnit unit) throws ConnectionException;
|
||||||
throws ConnectionException;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether EOF has been received.
|
||||||
|
*/
|
||||||
|
boolean isEOF();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the LoggerFactory associated with the SSH client.
|
||||||
|
*/
|
||||||
|
LoggerFactory getLoggerFactory();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,35 +12,10 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.Buffer;
|
import net.schmizz.sshj.common.*;
|
||||||
import net.schmizz.sshj.common.ErrorNotifiable;
|
|
||||||
import net.schmizz.sshj.common.Message;
|
|
||||||
import net.schmizz.sshj.common.SSHException;
|
|
||||||
import net.schmizz.sshj.common.SSHPacket;
|
|
||||||
import net.schmizz.sshj.connection.ConnectionException;
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
import net.schmizz.sshj.transport.Transport;
|
import net.schmizz.sshj.transport.Transport;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
@@ -59,7 +34,7 @@ public final class ChannelInputStream
|
|||||||
extends InputStream
|
extends InputStream
|
||||||
implements ErrorNotifiable {
|
implements ErrorNotifiable {
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private final Logger log;
|
||||||
|
|
||||||
private final Channel chan;
|
private final Channel chan;
|
||||||
private final Transport trans;
|
private final Transport trans;
|
||||||
@@ -72,6 +47,7 @@ public final class ChannelInputStream
|
|||||||
|
|
||||||
public ChannelInputStream(Channel chan, Transport trans, Window.Local win) {
|
public ChannelInputStream(Channel chan, Transport trans, Window.Local win) {
|
||||||
this.chan = chan;
|
this.chan = chan;
|
||||||
|
log = chan.getLoggerFactory().getLogger(getClass());
|
||||||
this.trans = trans;
|
this.trans = trans;
|
||||||
this.win = win;
|
this.win = win;
|
||||||
buf = new Buffer.PlainBuffer(chan.getLocalMaxPacketSize());
|
buf = new Buffer.PlainBuffer(chan.getLocalMaxPacketSize());
|
||||||
@@ -151,7 +127,12 @@ public final class ChannelInputStream
|
|||||||
buf.putRawBytes(data, offset, len);
|
buf.putRawBytes(data, offset, len);
|
||||||
buf.notifyAll();
|
buf.notifyAll();
|
||||||
}
|
}
|
||||||
win.consume(len);
|
// Potential fix for #203 (window consumed below 0).
|
||||||
|
// This seems to be a race condition if we receive more data, while we're already sending a SSH_MSG_CHANNEL_WINDOW_ADJUST
|
||||||
|
// And the window has not expanded yet.
|
||||||
|
synchronized (win) {
|
||||||
|
win.consume(len);
|
||||||
|
}
|
||||||
if (chan.getAutoExpand())
|
if (chan.getAutoExpand())
|
||||||
checkWindow();
|
checkWindow();
|
||||||
}
|
}
|
||||||
@@ -159,9 +140,9 @@ public final class ChannelInputStream
|
|||||||
private void checkWindow()
|
private void checkWindow()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
synchronized (win) {
|
synchronized (win) {
|
||||||
final int adjustment = win.neededAdjustment();
|
final long adjustment = win.neededAdjustment();
|
||||||
if (adjustment > 0) {
|
if (adjustment > 0) {
|
||||||
log.info("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST to #{} for {} bytes", chan.getRecipient(), adjustment);
|
log.debug("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST to #{} for {} bytes", chan.getRecipient(), adjustment);
|
||||||
trans.write(new SSHPacket(Message.CHANNEL_WINDOW_ADJUST)
|
trans.write(new SSHPacket(Message.CHANNEL_WINDOW_ADJUST)
|
||||||
.putUInt32(chan.getRecipient()).putUInt32(adjustment));
|
.putUInt32(chan.getRecipient()).putUInt32(adjustment));
|
||||||
win.expand(adjustment);
|
win.expand(adjustment);
|
||||||
@@ -174,4 +155,4 @@ public final class ChannelInputStream
|
|||||||
return "< ChannelInputStream for Channel #" + chan.getID() + " >";
|
return "< ChannelInputStream for Channel #" + chan.getID() + " >";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,35 +12,13 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.ErrorNotifiable;
|
import net.schmizz.sshj.common.*;
|
||||||
import net.schmizz.sshj.common.Message;
|
|
||||||
import net.schmizz.sshj.common.SSHException;
|
|
||||||
import net.schmizz.sshj.common.SSHPacket;
|
|
||||||
import net.schmizz.sshj.connection.ConnectionException;
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
import net.schmizz.sshj.transport.Transport;
|
import net.schmizz.sshj.transport.Transport;
|
||||||
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -56,26 +34,99 @@ public final class ChannelOutputStream
|
|||||||
private final Channel chan;
|
private final Channel chan;
|
||||||
private final Transport trans;
|
private final Transport trans;
|
||||||
private final Window.Remote win;
|
private final Window.Remote win;
|
||||||
private final SSHPacket buffer = new SSHPacket();
|
|
||||||
|
private final DataBuffer buffer = new DataBuffer();
|
||||||
private final byte[] b = new byte[1];
|
private final byte[] b = new byte[1];
|
||||||
private int bufferLength;
|
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
private SSHException error;
|
private SSHException error;
|
||||||
|
|
||||||
|
private final class DataBuffer {
|
||||||
|
|
||||||
|
private final int headerOffset;
|
||||||
|
private final int dataOffset;
|
||||||
|
|
||||||
|
private final SSHPacket packet = new SSHPacket(Message.CHANNEL_DATA);
|
||||||
|
private final Buffer.PlainBuffer leftOvers = new Buffer.PlainBuffer();
|
||||||
|
|
||||||
|
DataBuffer() {
|
||||||
|
headerOffset = packet.rpos();
|
||||||
|
packet.putUInt32(0); // recipient
|
||||||
|
packet.putUInt32(0); // data length
|
||||||
|
dataOffset = packet.wpos();
|
||||||
|
}
|
||||||
|
|
||||||
|
int write(byte[] data, int off, int len)
|
||||||
|
throws TransportException, ConnectionException {
|
||||||
|
final int bufferSize = packet.wpos() - dataOffset;
|
||||||
|
if (bufferSize >= win.getMaxPacketSize()) {
|
||||||
|
flush(bufferSize, true);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
final int n = Math.min(len, win.getMaxPacketSize() - bufferSize);
|
||||||
|
packet.putRawBytes(data, off, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean flush(boolean canAwaitExpansion)
|
||||||
|
throws TransportException, ConnectionException {
|
||||||
|
return flush(packet.wpos() - dataOffset, canAwaitExpansion);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean flush(int bufferSize, boolean canAwaitExpansion)
|
||||||
|
throws TransportException, ConnectionException {
|
||||||
|
while (bufferSize > 0) {
|
||||||
|
|
||||||
|
long remoteWindowSize = win.getSize();
|
||||||
|
if (remoteWindowSize == 0) {
|
||||||
|
if (canAwaitExpansion) {
|
||||||
|
remoteWindowSize = win.awaitExpansion(remoteWindowSize);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can only write the min. of
|
||||||
|
// a) how much data we have
|
||||||
|
// b) the max packet size
|
||||||
|
// c) what the current window size will allow
|
||||||
|
final int writeNow = Math.min(bufferSize, (int) Math.min(win.getMaxPacketSize(), remoteWindowSize));
|
||||||
|
|
||||||
|
packet.wpos(headerOffset);
|
||||||
|
packet.putMessageID(Message.CHANNEL_DATA);
|
||||||
|
packet.putUInt32(chan.getRecipient());
|
||||||
|
packet.putUInt32(writeNow);
|
||||||
|
packet.wpos(dataOffset + writeNow);
|
||||||
|
|
||||||
|
final int leftOverBytes = bufferSize - writeNow;
|
||||||
|
if (leftOverBytes > 0) {
|
||||||
|
leftOvers.putRawBytes(packet.array(), packet.wpos(), leftOverBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
trans.write(packet);
|
||||||
|
win.consume(writeNow);
|
||||||
|
|
||||||
|
packet.rpos(headerOffset);
|
||||||
|
packet.wpos(dataOffset);
|
||||||
|
|
||||||
|
if (leftOverBytes > 0) {
|
||||||
|
packet.putBuffer(leftOvers);
|
||||||
|
leftOvers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferSize = leftOverBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public ChannelOutputStream(Channel chan, Transport trans, Window.Remote win) {
|
public ChannelOutputStream(Channel chan, Transport trans, Window.Remote win) {
|
||||||
this.chan = chan;
|
this.chan = chan;
|
||||||
this.trans = trans;
|
this.trans = trans;
|
||||||
this.win = win;
|
this.win = win;
|
||||||
prepBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepBuffer() {
|
|
||||||
bufferLength = 0;
|
|
||||||
buffer.rpos(5);
|
|
||||||
buffer.wpos(5);
|
|
||||||
buffer.putMessageID(Message.CHANNEL_DATA);
|
|
||||||
buffer.putUInt32(0); // meant to be recipient
|
|
||||||
buffer.putUInt32(0); // meant to be data length
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -86,19 +137,13 @@ public final class ChannelOutputStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void write(byte[] data, int off, int len)
|
public synchronized void write(final byte[] data, int off, int len)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
checkClose();
|
checkClose();
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
final int x = Math.min(len, win.getMaxPacketSize() - bufferLength);
|
final int n = buffer.write(data, off, len);
|
||||||
if (x <= 0) {
|
off += n;
|
||||||
flush();
|
len -= n;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
buffer.putRawBytes(data, off, x);
|
|
||||||
bufferLength += x;
|
|
||||||
off += x;
|
|
||||||
len -= x;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,55 +152,40 @@ public final class ChannelOutputStream
|
|||||||
this.error = error;
|
this.error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void checkClose()
|
private void checkClose()
|
||||||
throws SSHException {
|
throws SSHException {
|
||||||
if (closed)
|
if (closed) {
|
||||||
if (error != null)
|
if (error != null)
|
||||||
throw error;
|
throw error;
|
||||||
else
|
else
|
||||||
throw new ConnectionException("Stream closed");
|
throw new ConnectionException("Stream closed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void close()
|
public synchronized void close()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (!closed)
|
if (!closed) {
|
||||||
try {
|
try {
|
||||||
flush();
|
buffer.flush(false);
|
||||||
chan.sendEOF();
|
// trans.write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(chan.getRecipient()));
|
||||||
} finally {
|
} finally {
|
||||||
setClosed();
|
closed = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void setClosed() {
|
/**
|
||||||
closed = true;
|
* Send all data currently buffered. If window space is exhausted in the process, this will block
|
||||||
}
|
* until it is expanded by the server.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void flush()
|
public synchronized void flush()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
checkClose();
|
checkClose();
|
||||||
|
buffer.flush(true);
|
||||||
if (bufferLength <= 0) // No data to send
|
|
||||||
return;
|
|
||||||
|
|
||||||
putRecipientAndLength();
|
|
||||||
|
|
||||||
try {
|
|
||||||
win.waitAndConsume(bufferLength);
|
|
||||||
trans.write(buffer);
|
|
||||||
} finally {
|
|
||||||
prepBuffer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putRecipientAndLength() {
|
|
||||||
final int origPos = buffer.wpos();
|
|
||||||
buffer.wpos(6);
|
|
||||||
buffer.putUInt32(chan.getRecipient());
|
|
||||||
buffer.putUInt32(bufferLength);
|
|
||||||
buffer.wpos(origPos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -163,4 +193,4 @@ public final class ChannelOutputStream
|
|||||||
return "< ChannelOutputStream for Channel #" + chan.getID() + " >";
|
return "< ChannelOutputStream for Channel #" + chan.getID() + " >";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -18,11 +18,12 @@ package net.schmizz.sshj.connection.channel;
|
|||||||
import net.schmizz.concurrent.Event;
|
import net.schmizz.concurrent.Event;
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static com.hierynomus.sshj.backport.Sockets.asCloseable;
|
||||||
|
|
||||||
public class SocketStreamCopyMonitor
|
public class SocketStreamCopyMonitor
|
||||||
extends Thread {
|
extends Thread {
|
||||||
|
|
||||||
@@ -32,16 +33,6 @@ public class SocketStreamCopyMonitor
|
|||||||
setDaemon(true);
|
setDaemon(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Closeable wrapSocket(final Socket socket) {
|
|
||||||
return new Closeable() {
|
|
||||||
@Override
|
|
||||||
public void close()
|
|
||||||
throws IOException {
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void monitor(final int frequency, final TimeUnit unit,
|
public static void monitor(final int frequency, final TimeUnit unit,
|
||||||
final Event<IOException> x, final Event<IOException> y,
|
final Event<IOException> x, final Event<IOException> y,
|
||||||
final Channel channel, final Socket socket) {
|
final Channel channel, final Socket socket) {
|
||||||
@@ -54,7 +45,7 @@ public class SocketStreamCopyMonitor
|
|||||||
}
|
}
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(channel, wrapSocket(socket));
|
IOUtils.closeQuietly(channel, asCloseable(socket));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,30 +15,31 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel;
|
package net.schmizz.sshj.connection.channel;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.sshj.common.SSHRuntimeException;
|
import net.schmizz.sshj.common.SSHRuntimeException;
|
||||||
import net.schmizz.sshj.connection.ConnectionException;
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public abstract class Window {
|
public abstract class Window {
|
||||||
|
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log;
|
||||||
|
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
protected final int maxPacketSize;
|
protected final int maxPacketSize;
|
||||||
|
|
||||||
protected int size;
|
protected long size;
|
||||||
|
|
||||||
public Window(int initialWinSize, int maxPacketSize) {
|
public Window(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
|
||||||
size = initialWinSize;
|
size = initialWinSize;
|
||||||
this.maxPacketSize = maxPacketSize;
|
this.maxPacketSize = maxPacketSize;
|
||||||
|
log = loggerFactory.getLogger(getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expand(int inc) {
|
public void expand(long inc) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
log.debug("Increasing by {} up to {}", inc, size);
|
|
||||||
size += inc;
|
size += inc;
|
||||||
|
log.debug("Increasing by {} up to {}", inc, size);
|
||||||
lock.notifyAll();
|
lock.notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,16 +48,19 @@ public abstract class Window {
|
|||||||
return maxPacketSize;
|
return maxPacketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public long getSize() {
|
||||||
return size;
|
synchronized (lock) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void consume(int dec) {
|
public void consume(long dec)
|
||||||
|
throws ConnectionException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
log.debug("Consuming by " + dec + " down to " + size);
|
|
||||||
size -= dec;
|
size -= dec;
|
||||||
|
log.debug("Consuming by {} down to {}", dec, size);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
throw new SSHRuntimeException("Window consumed to below 0");
|
throw new ConnectionException("Window consumed to below 0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,22 +73,30 @@ public abstract class Window {
|
|||||||
public static final class Remote
|
public static final class Remote
|
||||||
extends Window {
|
extends Window {
|
||||||
|
|
||||||
public Remote(int initialWinSize, int maxPacketSize) {
|
public Remote(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
|
||||||
super(initialWinSize, maxPacketSize);
|
super(initialWinSize, maxPacketSize, loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitAndConsume(int howMuch)
|
public long awaitExpansion(long was)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
while (size < howMuch) {
|
while (size <= was) {
|
||||||
log.debug("Waiting, need window space for {} bytes", howMuch);
|
log.debug("Waiting, need size to grow from {} bytes", was);
|
||||||
try {
|
try {
|
||||||
lock.wait();
|
lock.wait();
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
throw new ConnectionException(ie);
|
throw new ConnectionException(ie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
consume(howMuch);
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void consume(long howMuch) {
|
||||||
|
try {
|
||||||
|
super.consume(howMuch);
|
||||||
|
} catch (ConnectionException e) { // It's a bug if we consume more than remote allowed
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,18 +106,18 @@ public abstract class Window {
|
|||||||
public static final class Local
|
public static final class Local
|
||||||
extends Window {
|
extends Window {
|
||||||
|
|
||||||
private final int initialSize;
|
private final long initialSize;
|
||||||
private final int threshold;
|
private final long threshold;
|
||||||
|
|
||||||
public Local(int initialWinSize, int maxPacketSize) {
|
public Local(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
|
||||||
super(initialWinSize, maxPacketSize);
|
super(initialWinSize, maxPacketSize, loggerFactory);
|
||||||
this.initialSize = initialWinSize;
|
this.initialSize = initialWinSize;
|
||||||
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
|
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int neededAdjustment() {
|
public long neededAdjustment() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
return (size - threshold <= 0) ? (initialSize - size) : 0;
|
return (size <= threshold) ? (initialSize - size) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel.direct;
|
package net.schmizz.sshj.connection.channel.direct;
|
||||||
|
|
||||||
@@ -65,23 +45,23 @@ public abstract class AbstractDirectChannel
|
|||||||
public void open()
|
public void open()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
trans.write(buildOpenReq());
|
trans.write(buildOpenReq());
|
||||||
open.await(conn.getTimeout(), TimeUnit.SECONDS);
|
openEvent.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotOpenConfirmation(SSHPacket buf)
|
private void gotOpenConfirmation(SSHPacket buf)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
try {
|
try {
|
||||||
init(buf.readUInt32AsInt(), buf.readUInt32AsInt(), buf.readUInt32AsInt());
|
init(buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32());
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
}
|
}
|
||||||
open.set();
|
openEvent.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void gotOpenFailure(SSHPacket buf)
|
private void gotOpenFailure(SSHPacket buf)
|
||||||
throws ConnectionException {
|
throws ConnectionException {
|
||||||
try {
|
try {
|
||||||
open.deliverError(new OpenFailException(getType(), buf.readUInt32AsInt(), buf.readString()));
|
openEvent.deliverError(new OpenFailException(getType(), buf.readUInt32AsInt(), buf.readString()));
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
}
|
}
|
||||||
@@ -114,4 +94,4 @@ public abstract class AbstractDirectChannel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,107 +16,115 @@
|
|||||||
package net.schmizz.sshj.connection.channel.direct;
|
package net.schmizz.sshj.connection.channel.direct;
|
||||||
|
|
||||||
import net.schmizz.concurrent.Event;
|
import net.schmizz.concurrent.Event;
|
||||||
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.sshj.common.SSHPacket;
|
import net.schmizz.sshj.common.SSHPacket;
|
||||||
import net.schmizz.sshj.common.StreamCopier;
|
import net.schmizz.sshj.common.StreamCopier;
|
||||||
import net.schmizz.sshj.connection.Connection;
|
import net.schmizz.sshj.connection.Connection;
|
||||||
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
|
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.net.ServerSocketFactory;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static com.hierynomus.sshj.backport.Sockets.asCloseable;
|
||||||
|
|
||||||
public class LocalPortForwarder {
|
public class LocalPortForwarder {
|
||||||
|
|
||||||
private class DirectTCPIPChannel
|
public static class Parameters {
|
||||||
extends AbstractDirectChannel {
|
|
||||||
|
|
||||||
private final Socket sock;
|
private final String localHost;
|
||||||
|
private final int localPort;
|
||||||
|
private final String remoteHost;
|
||||||
|
private final int remotePort;
|
||||||
|
|
||||||
private DirectTCPIPChannel(Connection conn, Socket sock) {
|
public Parameters(String localHost, int localPort, String remoteHost, int remotePort) {
|
||||||
super(conn, "direct-tcpip");
|
this.localHost = localHost;
|
||||||
this.sock = sock;
|
this.localPort = localPort;
|
||||||
|
this.remoteHost = remoteHost;
|
||||||
|
this.remotePort = remotePort;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void start()
|
public String getRemoteHost() {
|
||||||
|
return remoteHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRemotePort() {
|
||||||
|
return remotePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocalHost() {
|
||||||
|
return localHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLocalPort() {
|
||||||
|
return localPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DirectTCPIPChannel
|
||||||
|
extends AbstractDirectChannel {
|
||||||
|
|
||||||
|
protected final Socket socket;
|
||||||
|
protected final Parameters parameters;
|
||||||
|
|
||||||
|
public DirectTCPIPChannel(Connection conn, Socket socket, Parameters parameters) {
|
||||||
|
super(conn, "direct-tcpip");
|
||||||
|
this.socket = socket;
|
||||||
|
this.parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void start()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
sock.setSendBufferSize(getLocalMaxPacketSize());
|
socket.setSendBufferSize(getLocalMaxPacketSize());
|
||||||
sock.setReceiveBufferSize(getRemoteMaxPacketSize());
|
socket.setReceiveBufferSize(getRemoteMaxPacketSize());
|
||||||
final Event<IOException> soc2chan = new StreamCopier(sock.getInputStream(), getOutputStream())
|
final Event<IOException> soc2chan = new StreamCopier(socket.getInputStream(), getOutputStream(), loggerFactory)
|
||||||
.bufSize(getRemoteMaxPacketSize())
|
.bufSize(getRemoteMaxPacketSize())
|
||||||
.spawnDaemon("soc2chan");
|
.spawnDaemon("soc2chan");
|
||||||
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), sock.getOutputStream())
|
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), socket.getOutputStream(), loggerFactory)
|
||||||
.bufSize(getLocalMaxPacketSize())
|
.bufSize(getLocalMaxPacketSize())
|
||||||
.spawnDaemon("chan2soc");
|
.spawnDaemon("chan2soc");
|
||||||
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, sock);
|
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SSHPacket buildOpenReq() {
|
protected SSHPacket buildOpenReq() {
|
||||||
return super.buildOpenReq()
|
return super.buildOpenReq()
|
||||||
.putString(host)
|
.putString(parameters.getRemoteHost())
|
||||||
.putUInt32(port)
|
.putUInt32(parameters.getRemotePort())
|
||||||
.putString(ss.getInetAddress().getHostAddress())
|
.putString(parameters.getLocalHost())
|
||||||
.putUInt32(ss.getLocalPort());
|
.putUInt32(parameters.getLocalPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
private final LoggerFactory loggerFactory;
|
||||||
|
private final Logger log;
|
||||||
private final Connection conn;
|
private final Connection conn;
|
||||||
private final ServerSocket ss;
|
private final Parameters parameters;
|
||||||
private final String host;
|
private final ServerSocket serverSocket;
|
||||||
private final int port;
|
|
||||||
|
|
||||||
/**
|
public LocalPortForwarder(Connection conn, Parameters parameters, ServerSocket serverSocket, LoggerFactory loggerFactory) {
|
||||||
* Create a local port forwarder with specified binding ({@code listeningAddr}. It does not, however, start
|
|
||||||
* listening unless {@link #listen() explicitly told to}. The {@link javax.net.ServerSocketFactory#getDefault()
|
|
||||||
* default} server socket factory is used.
|
|
||||||
*
|
|
||||||
* @param conn {@link Connection} implementation
|
|
||||||
* @param listeningAddr {@link SocketAddress} this forwarder will listen on, if {@code null} then an ephemeral port
|
|
||||||
* and valid local address will be picked to bind the server socket
|
|
||||||
* @param host what host the SSH server will further forward to
|
|
||||||
* @param port port on {@code toHost}
|
|
||||||
*
|
|
||||||
* @throws IOException if there is an error binding on specified {@code listeningAddr}
|
|
||||||
*/
|
|
||||||
public LocalPortForwarder(Connection conn, SocketAddress listeningAddr, String host, int port)
|
|
||||||
throws IOException {
|
|
||||||
this(ServerSocketFactory.getDefault(), conn, listeningAddr, host, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a local port forwarder with specified binding ({@code listeningAddr}. It does not, however, start
|
|
||||||
* listening unless {@link #listen() explicitly told to}.
|
|
||||||
*
|
|
||||||
* @param ssf factory to use for creating the server socket
|
|
||||||
* @param conn {@link Connection} implementation
|
|
||||||
* @param listeningAddr {@link SocketAddress} this forwarder will listen on, if {@code null} then an ephemeral port
|
|
||||||
* and valid local address will be picked to bind the server socket
|
|
||||||
* @param host what host the SSH server will further forward to
|
|
||||||
* @param port port on {@code toHost}
|
|
||||||
*
|
|
||||||
* @throws IOException if there is an error binding on specified {@code listeningAddr}
|
|
||||||
*/
|
|
||||||
public LocalPortForwarder(ServerSocketFactory ssf, Connection conn, SocketAddress listeningAddr, String host, int port)
|
|
||||||
throws IOException {
|
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.host = host;
|
this.parameters = parameters;
|
||||||
this.port = port;
|
this.serverSocket = serverSocket;
|
||||||
this.ss = ssf.createServerSocket();
|
this.loggerFactory = loggerFactory;
|
||||||
ss.setReceiveBufferSize(conn.getMaxPacketSize());
|
this.log = loggerFactory.getLogger(getClass());
|
||||||
ss.bind(listeningAddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the address to which this forwarder is bound for listening */
|
private void startChannel(Socket socket) throws IOException {
|
||||||
public SocketAddress getListeningAddress() {
|
DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, socket, parameters);
|
||||||
return ss.getLocalSocketAddress();
|
try {
|
||||||
|
chan.open();
|
||||||
|
chan.start();
|
||||||
|
} catch (IOException e) {
|
||||||
|
IOUtils.closeQuietly(chan, asCloseable(socket));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,16 +134,35 @@ public class LocalPortForwarder {
|
|||||||
*/
|
*/
|
||||||
public void listen()
|
public void listen()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
log.info("Listening on {}", ss.getLocalSocketAddress());
|
log.info("Listening on {}", serverSocket.getLocalSocketAddress());
|
||||||
Socket sock;
|
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
sock = ss.accept();
|
try {
|
||||||
log.info("Got connection from {}", sock.getRemoteSocketAddress());
|
final Socket socket = serverSocket.accept();
|
||||||
DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, sock);
|
log.debug("Got connection from {}", socket.getRemoteSocketAddress());
|
||||||
chan.open();
|
startChannel(socket);
|
||||||
chan.start();
|
} catch (SocketException e) {
|
||||||
|
if (!serverSocket.isClosed()) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (serverSocket.isClosed()) {
|
||||||
|
log.debug("LocalPortForwarder closed");
|
||||||
|
} else {
|
||||||
|
log.debug("LocalPortForwarder interrupted!");
|
||||||
}
|
}
|
||||||
log.info("Interrupted!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Close the ServerSocket that's listening for connections to forward.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (!serverSocket.isClosed()) {
|
||||||
|
log.info("Closing listener on {}", serverSocket.getLocalSocketAddress());
|
||||||
|
serverSocket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -19,7 +19,6 @@ import net.schmizz.sshj.connection.ConnectionException;
|
|||||||
import net.schmizz.sshj.connection.channel.Channel;
|
import net.schmizz.sshj.connection.channel.Channel;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -49,18 +48,24 @@ public interface Session
|
|||||||
/**
|
/**
|
||||||
* If the command exit violently {@link #getExitSignal() with a signal}, an error message would have been
|
* If the command exit violently {@link #getExitSignal() with a signal}, an error message would have been
|
||||||
* received and can be retrieved via this method. Otherwise, this method will return {@code null}.
|
* received and can be retrieved via this method. Otherwise, this method will return {@code null}.
|
||||||
|
* <p/>
|
||||||
|
* <strong>NOTE: </strong> Always call {@link #close()} first before inspecting the exit error message.
|
||||||
*/
|
*/
|
||||||
String getExitErrorMessage();
|
String getExitErrorMessage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link Signal signal} if the command exit violently, or {@code null} if this information was not
|
* Returns the {@link Signal signal} if the command exit violently, or {@code null} if this information was not
|
||||||
* received.
|
* received.
|
||||||
|
* <p/>
|
||||||
|
* <strong>NOTE: </strong> Always call {@link #close()} first before inspecting the exit signal.
|
||||||
*/
|
*/
|
||||||
Signal getExitSignal();
|
Signal getExitSignal();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the exit status of the command if it was received, or {@code null} if this information was not
|
* Returns the exit status of the command if it was received, or {@code null} if this information was not
|
||||||
* received.
|
* received.
|
||||||
|
* <p/>
|
||||||
|
* <strong>NOTE: </strong> Always call {@link #close()} first before inspecting the exit status.
|
||||||
*/
|
*/
|
||||||
Integer getExitStatus();
|
Integer getExitStatus();
|
||||||
|
|
||||||
@@ -81,14 +86,6 @@ public interface Session
|
|||||||
void signal(Signal signal)
|
void signal(Signal signal)
|
||||||
throws TransportException;
|
throws TransportException;
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
String getOutputAsString()
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
String getErrorAsString()
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Shell API. */
|
/** Shell API. */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,41 +12,15 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel.direct;
|
package net.schmizz.sshj.connection.channel.direct;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.Buffer;
|
import net.schmizz.sshj.common.*;
|
||||||
import net.schmizz.sshj.common.DisconnectReason;
|
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
|
||||||
import net.schmizz.sshj.common.SSHException;
|
|
||||||
import net.schmizz.sshj.common.SSHPacket;
|
|
||||||
import net.schmizz.sshj.common.SSHRuntimeException;
|
|
||||||
import net.schmizz.sshj.connection.Connection;
|
import net.schmizz.sshj.connection.Connection;
|
||||||
import net.schmizz.sshj.connection.ConnectionException;
|
import net.schmizz.sshj.connection.ConnectionException;
|
||||||
import net.schmizz.sshj.connection.channel.ChannelInputStream;
|
import net.schmizz.sshj.connection.channel.ChannelInputStream;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -59,13 +33,13 @@ public class SessionChannel
|
|||||||
|
|
||||||
private final ChannelInputStream err = new ChannelInputStream(this, trans, lwin);
|
private final ChannelInputStream err = new ChannelInputStream(this, trans, lwin);
|
||||||
|
|
||||||
private Integer exitStatus;
|
private volatile Integer exitStatus;
|
||||||
|
|
||||||
private Signal exitSignal;
|
private volatile Signal exitSignal;
|
||||||
private Boolean wasCoreDumped;
|
private volatile Boolean wasCoreDumped;
|
||||||
private String exitErrMsg;
|
private volatile String exitErrMsg;
|
||||||
|
|
||||||
private Boolean canDoFlowControl;
|
private volatile Boolean canDoFlowControl;
|
||||||
|
|
||||||
private boolean usedUp;
|
private boolean usedUp;
|
||||||
|
|
||||||
@@ -76,7 +50,7 @@ public class SessionChannel
|
|||||||
@Override
|
@Override
|
||||||
public void allocateDefaultPTY()
|
public void allocateDefaultPTY()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
allocatePTY("dummy", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
|
allocatePTY("vt100", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -92,7 +66,7 @@ public class SessionChannel
|
|||||||
.putUInt32(width)
|
.putUInt32(width)
|
||||||
.putUInt32(height)
|
.putUInt32(height)
|
||||||
.putBytes(PTYMode.encode(modes))
|
.putBytes(PTYMode.encode(modes))
|
||||||
).await(conn.getTimeout(), TimeUnit.SECONDS);
|
).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -118,9 +92,9 @@ public class SessionChannel
|
|||||||
public Command exec(String command)
|
public Command exec(String command)
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
checkReuse();
|
checkReuse();
|
||||||
log.info("Will request to exec `{}`", command);
|
log.debug("Will request to exec `{}`", command);
|
||||||
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command))
|
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command))
|
||||||
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
usedUp = true;
|
usedUp = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -176,14 +150,14 @@ public class SessionChannel
|
|||||||
.putString(authProto)
|
.putString(authProto)
|
||||||
.putString(authCookie)
|
.putString(authCookie)
|
||||||
.putUInt32(screen)
|
.putUInt32(screen)
|
||||||
).await(conn.getTimeout(), TimeUnit.SECONDS);
|
).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEnvVar(String name, String value)
|
public void setEnvVar(String name, String value)
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
sendChannelRequest("env", true, new Buffer.PlainBuffer().putString(name).putString(value))
|
sendChannelRequest("env", true, new Buffer.PlainBuffer().putString(name).putString(value))
|
||||||
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -196,7 +170,7 @@ public class SessionChannel
|
|||||||
public Shell startShell()
|
public Shell startShell()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
checkReuse();
|
checkReuse();
|
||||||
sendChannelRequest("shell", true, null).await(conn.getTimeout(), TimeUnit.SECONDS);
|
sendChannelRequest("shell", true, null).await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
usedUp = true;
|
usedUp = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -207,7 +181,7 @@ public class SessionChannel
|
|||||||
checkReuse();
|
checkReuse();
|
||||||
log.info("Will request `{}` subsystem", name);
|
log.info("Will request `{}` subsystem", name);
|
||||||
sendChannelRequest("subsystem", true, new Buffer.PlainBuffer().putString(name))
|
sendChannelRequest("subsystem", true, new Buffer.PlainBuffer().putString(name))
|
||||||
.await(conn.getTimeout(), TimeUnit.SECONDS);
|
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
usedUp = true;
|
usedUp = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -255,18 +229,4 @@ public class SessionChannel
|
|||||||
throw new SSHRuntimeException("This session channel is all used up");
|
throw new SSHRuntimeException("This session channel is all used up");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public String getOutputAsString()
|
|
||||||
throws IOException {
|
|
||||||
return IOUtils.readFully(getInputStream()).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public String getErrorAsString()
|
|
||||||
throws IOException {
|
|
||||||
return IOUtils.readFully(getErrorStream()).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj.connection.channel.direct;
|
package net.schmizz.sshj.connection.channel.direct;
|
||||||
|
|
||||||
/** Various signals that may be sent or received. The signals are from POSIX and simply miss the {@code "SIG_"} prefix. */
|
/** Various signals that may be sent or received. The signals are from POSIX and simply miss the {@code "SIG_"} prefix. */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -12,26 +12,6 @@
|
|||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
|
||||||
* This file may incorporate work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.connection.channel.forwarded;
|
package net.schmizz.sshj.connection.channel.forwarded;
|
||||||
|
|
||||||
@@ -54,8 +34,9 @@ public abstract class AbstractForwardedChannel
|
|||||||
* First 2 args are standard; the others can be parsed from a CHANNEL_OPEN packet.
|
* First 2 args are standard; the others can be parsed from a CHANNEL_OPEN packet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected AbstractForwardedChannel(Connection conn, String type, int recipient, int remoteWinSize,
|
protected AbstractForwardedChannel(Connection conn, String type,
|
||||||
int remoteMaxPacketSize, String origIP, int origPort) {
|
int recipient, long remoteWinSize, long remoteMaxPacketSize,
|
||||||
|
String origIP, int origPort) {
|
||||||
super(conn, type);
|
super(conn, type);
|
||||||
this.origIP = origIP;
|
this.origIP = origIP;
|
||||||
this.origPort = origPort;
|
this.origPort = origPort;
|
||||||
@@ -65,20 +46,20 @@ public abstract class AbstractForwardedChannel
|
|||||||
@Override
|
@Override
|
||||||
public void confirm()
|
public void confirm()
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
log.info("Confirming `{}` channel #{}", getType(), getID());
|
log.debug("Confirming `{}` channel #{}", getType(), getID());
|
||||||
// Must ensure channel is attached before confirming, data could start coming in immediately!
|
// Must ensure channel is attached before confirming, data could start coming in immediately!
|
||||||
conn.attach(this);
|
conn.attach(this);
|
||||||
trans.write(newBuffer(Message.CHANNEL_OPEN_CONFIRMATION)
|
trans.write(newBuffer(Message.CHANNEL_OPEN_CONFIRMATION)
|
||||||
.putUInt32(getID())
|
.putUInt32(getID())
|
||||||
.putUInt32(getLocalWinSize())
|
.putUInt32(getLocalWinSize())
|
||||||
.putUInt32(getLocalMaxPacketSize()));
|
.putUInt32(getLocalMaxPacketSize()));
|
||||||
open.set();
|
openEvent.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reject(Reason reason, String message)
|
public void reject(Reason reason, String message)
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
log.info("Rejecting `{}` channel: {}", getType(), message);
|
log.debug("Rejecting `{}` channel: {}", getType(), message);
|
||||||
conn.sendOpenFailure(getRecipient(), reason, message);
|
conn.sendOpenFailure(getRecipient(), reason, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,4 +73,4 @@ public abstract class AbstractForwardedChannel
|
|||||||
return origPort;
|
return origPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.schmizz.sshj.connection.channel.forwarded;
|
package net.schmizz.sshj.connection.channel.forwarded;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
@@ -30,14 +29,14 @@ import java.io.IOException;
|
|||||||
public abstract class AbstractForwardedChannelOpener
|
public abstract class AbstractForwardedChannelOpener
|
||||||
implements ForwardedChannelOpener {
|
implements ForwardedChannelOpener {
|
||||||
|
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log;
|
||||||
|
|
||||||
protected final String chanType;
|
protected final String chanType;
|
||||||
protected final Connection conn;
|
protected final Connection conn;
|
||||||
|
|
||||||
protected AbstractForwardedChannelOpener(String chanType, Connection conn) {
|
protected AbstractForwardedChannelOpener(String chanType, Connection conn) {
|
||||||
this.chanType = chanType;
|
this.chanType = chanType;
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
|
log = conn.getTransport().getConfig().getLoggerFactory().getLogger(getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -73,4 +72,4 @@ public abstract class AbstractForwardedChannelOpener
|
|||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -117,6 +117,34 @@ public class RemotePortForwarder
|
|||||||
return address + ":" + port;
|
return address + ":" + port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean handles(ForwardedTCPIPChannel channel) {
|
||||||
|
Forward channelForward = channel.getParentForward();
|
||||||
|
if (channelForward.getPort() != port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ("".equals(address)) {
|
||||||
|
// This forward handles all protocols
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (channelForward.address.equals(address)) {
|
||||||
|
// Addresses match up
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ("localhost".equals(address) && (channelForward.address.equals("127.0.0.1") || channelForward.address.equals("::1"))) {
|
||||||
|
// Localhost special case.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ("::".equals(address) && channelForward.address.indexOf("::") > 0) {
|
||||||
|
// Listen on all IPv6
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ("0.0.0.0".equals(address) && channelForward.address.indexOf('.') > 0) {
|
||||||
|
// Listen on all IPv4
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A {@code forwarded-tcpip} channel. */
|
/** A {@code forwarded-tcpip} channel. */
|
||||||
@@ -127,7 +155,8 @@ public class RemotePortForwarder
|
|||||||
|
|
||||||
private final Forward fwd;
|
private final Forward fwd;
|
||||||
|
|
||||||
public ForwardedTCPIPChannel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize,
|
public ForwardedTCPIPChannel(Connection conn,
|
||||||
|
int recipient, long remoteWinSize, long remoteMaxPacketSize,
|
||||||
Forward fwd, String origIP, int origPort) {
|
Forward fwd, String origIP, int origPort) {
|
||||||
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
||||||
this.fwd = fwd;
|
this.fwd = fwd;
|
||||||
@@ -200,7 +229,7 @@ public class RemotePortForwarder
|
|||||||
final byte[] specifics = new Buffer.PlainBuffer().putString(forward.address).putUInt32(forward.port)
|
final byte[] specifics = new Buffer.PlainBuffer().putString(forward.address).putUInt32(forward.port)
|
||||||
.getCompactData();
|
.getCompactData();
|
||||||
return conn.sendGlobalRequest(reqName, true, specifics)
|
return conn.sendGlobalRequest(reqName, true, specifics)
|
||||||
.retrieve(conn.getTimeout(), TimeUnit.SECONDS);
|
.retrieve(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the active forwards. */
|
/** @return the active forwards. */
|
||||||
@@ -217,17 +246,21 @@ public class RemotePortForwarder
|
|||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
final ForwardedTCPIPChannel chan;
|
final ForwardedTCPIPChannel chan;
|
||||||
try {
|
try {
|
||||||
chan = new ForwardedTCPIPChannel(conn, buf.readUInt32AsInt(), buf.readUInt32AsInt(), buf.readUInt32AsInt(),
|
chan = new ForwardedTCPIPChannel(conn, buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32(),
|
||||||
new Forward(buf.readString(), buf.readUInt32AsInt()),
|
new Forward(buf.readString(), buf.readUInt32AsInt()),
|
||||||
buf.readString(), buf.readUInt32AsInt());
|
buf.readString(), buf.readUInt32AsInt());
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
}
|
}
|
||||||
if (listeners.containsKey(chan.getParentForward()))
|
|
||||||
callListener(listeners.get(chan.getParentForward()), chan);
|
for (Forward forward : listeners.keySet()) {
|
||||||
else
|
if (forward.handles(chan)) {
|
||||||
chan.reject(OpenFailException.Reason.ADMINISTRATIVELY_PROHIBITED, "Forwarding was not requested on `"
|
callListener(listeners.get(forward), chan);
|
||||||
+ chan.getParentForward() + "`");
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chan.reject(OpenFailException.Reason.ADMINISTRATIVELY_PROHIBITED, "Forwarding was not requested on `"
|
||||||
|
+ chan.getParentForward() + "`");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -19,8 +19,6 @@ import net.schmizz.concurrent.Event;
|
|||||||
import net.schmizz.sshj.common.StreamCopier;
|
import net.schmizz.sshj.common.StreamCopier;
|
||||||
import net.schmizz.sshj.connection.channel.Channel;
|
import net.schmizz.sshj.connection.channel.Channel;
|
||||||
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
|
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
@@ -31,8 +29,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class SocketForwardingConnectListener
|
public class SocketForwardingConnectListener
|
||||||
implements ConnectListener {
|
implements ConnectListener {
|
||||||
|
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
protected final SocketAddress addr;
|
protected final SocketAddress addr;
|
||||||
|
|
||||||
/** Create with a {@link SocketAddress} this listener will forward to. */
|
/** Create with a {@link SocketAddress} this listener will forward to. */
|
||||||
@@ -44,7 +40,7 @@ public class SocketForwardingConnectListener
|
|||||||
@Override
|
@Override
|
||||||
public void gotConnect(Channel.Forwarded chan)
|
public void gotConnect(Channel.Forwarded chan)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
log.info("New connection from " + chan.getOriginatorIP() + ":" + chan.getOriginatorPort());
|
chan.getLoggerFactory().getLogger(getClass()).debug("New connection from {}:{}", chan.getOriginatorIP(), chan.getOriginatorPort());
|
||||||
|
|
||||||
final Socket sock = new Socket();
|
final Socket sock = new Socket();
|
||||||
sock.setSendBufferSize(chan.getLocalMaxPacketSize());
|
sock.setSendBufferSize(chan.getLocalMaxPacketSize());
|
||||||
@@ -55,15 +51,15 @@ public class SocketForwardingConnectListener
|
|||||||
// ok so far -- could connect, let's confirm the channel
|
// ok so far -- could connect, let's confirm the channel
|
||||||
chan.confirm();
|
chan.confirm();
|
||||||
|
|
||||||
final Event<IOException> soc2chan = new StreamCopier(sock.getInputStream(), chan.getOutputStream())
|
final Event<IOException> soc2chan = new StreamCopier(sock.getInputStream(), chan.getOutputStream(), chan.getLoggerFactory())
|
||||||
.bufSize(chan.getRemoteMaxPacketSize())
|
.bufSize(chan.getRemoteMaxPacketSize())
|
||||||
.spawnDaemon("soc2chan");
|
.spawnDaemon("soc2chan");
|
||||||
|
|
||||||
final Event<IOException> chan2soc = new StreamCopier(chan.getInputStream(), sock.getOutputStream())
|
final Event<IOException> chan2soc = new StreamCopier(chan.getInputStream(), sock.getOutputStream(), chan.getLoggerFactory())
|
||||||
.bufSize(chan.getLocalMaxPacketSize())
|
.bufSize(chan.getLocalMaxPacketSize())
|
||||||
.spawnDaemon("chan2soc");
|
.spawnDaemon("chan2soc");
|
||||||
|
|
||||||
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, chan2soc, soc2chan, chan, sock);
|
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, chan2soc, soc2chan, chan, sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -34,8 +34,9 @@ public class X11Forwarder
|
|||||||
|
|
||||||
public static final String TYPE = "x11";
|
public static final String TYPE = "x11";
|
||||||
|
|
||||||
public X11Channel(Connection conn, int recipient, int remoteWinSize, int remoteMaxPacketSize, String origIP,
|
public X11Channel(Connection conn,
|
||||||
int origPort) {
|
int recipient, long remoteWinSize, long remoteMaxPacketSize,
|
||||||
|
String origIP, int origPort) {
|
||||||
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
super(conn, TYPE, recipient, remoteWinSize, remoteMaxPacketSize, origIP, origPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,8 +59,7 @@ public class X11Forwarder
|
|||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
try {
|
try {
|
||||||
callListener(listener, new X11Channel(conn,
|
callListener(listener, new X11Channel(conn,
|
||||||
buf.readUInt32AsInt(),
|
buf.readUInt32AsInt(), buf.readUInt32(), buf.readUInt32(),
|
||||||
buf.readUInt32AsInt(), buf.readUInt32AsInt(),
|
|
||||||
buf.readString(), buf.readUInt32AsInt()));
|
buf.readString(), buf.readUInt32AsInt()));
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new ConnectionException(be);
|
throw new ConnectionException(be);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -222,7 +222,7 @@ public final class FileAttributes {
|
|||||||
sb.append("size=").append(size).append(";");
|
sb.append("size=").append(size).append(";");
|
||||||
|
|
||||||
if (has(Flag.UIDGID))
|
if (has(Flag.UIDGID))
|
||||||
sb.append("uid=").append(size).append(",gid=").append(gid).append(";");
|
sb.append("uid=").append(uid).append(",gid=").append(gid).append(";");
|
||||||
|
|
||||||
if (has(Flag.MODE))
|
if (has(Flag.MODE))
|
||||||
sb.append("mode=").append(mode.toString()).append(";");
|
sb.append("mode=").append(mode.toString()).append(";");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011 sshj contributors
|
* Copyright (C)2009 - SSHJ Contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -36,7 +36,7 @@ public class FileMode {
|
|||||||
/** directory */
|
/** directory */
|
||||||
DIRECTORY(0040000),
|
DIRECTORY(0040000),
|
||||||
/** symbolic link */
|
/** symbolic link */
|
||||||
SYMKLINK(0120000),
|
SYMLINK(0120000),
|
||||||
/** unknown */
|
/** unknown */
|
||||||
UNKNOWN(0);
|
UNKNOWN(0);
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ public class FileMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getTypeMask() {
|
public int getTypeMask() {
|
||||||
return mask & 0770000;
|
return mask & 0170000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPermissionsMask() {
|
public int getPermissionsMask() {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user