Compare commits

..

184 Commits

Author SHA1 Message Date
Jeroen van Erp
63927a3e2b Setting version to 0.18.0 2016-09-30 11:43:02 +02:00
Jeroen van Erp
ac262f8086 Updated README for 0.17.3 2016-09-30 11:26:01 +02:00
Jeroen van Erp
6e56cd9d0a Changed release process to bintray 2016-09-30 11:03:22 +02:00
Jeroen van Erp
2f6025d9ba Merge branch 'CherifGh-gcif-patch-android-compat' 2016-09-30 10:38:22 +02:00
Jeroen van Erp
275e98e55b Refactored SecurityUtils a bit 2016-09-30 10:37:55 +02:00
Ghozzi Cherif
655d070571 Update AndroidConfig.java 2016-09-25 15:28:59 +02:00
Jeroen van Erp
c9775ca2c7 Fixed formatting warnings of Codacy 2016-09-13 15:34:08 +02:00
Jeroen van Erp
a2fb4fbd98 Merge pull request #271 from joval/master
Gracefully load OpenSSH known_hosts without requiring BouncyCastle
2016-09-13 15:21:09 +02:00
David Solin
6185ac4db8 Improvements per JVE. 2016-09-13 08:04:15 -05:00
David Solin
e420593fa9 Okay, more spaces Codacy, you win! 2016-09-09 16:03:45 -05:00
David Solin
68b924863e Fail gracefully when reading an OpenSSH Known Hosts file that uses key types requiring BouncyCastle, but we're not including BouncyCastle. 2016-09-09 14:39:21 -05:00
Jeroen van Erp
613ace1864 Upgrade to gradle 3.0 2016-09-05 11:32:59 +02:00
Jeroen van Erp
78e0ecd264 Merge pull request #270 from hierynomus/java6
Java6 re-enabled
2016-09-05 11:29:02 +02:00
Jeroen van Erp
64085e62f4 Removed openJDK6 as release plugin is incompatible 2016-09-05 09:54:15 +02:00
Jeroen van Erp
8c7d2fa8d0 Java6 re-enabled 2016-09-02 16:54:21 +02:00
Jeroen van Erp
766d292bad Merge pull request #269 from joval/master
Compatibility features
2016-09-02 16:46:56 +02:00
David Solin
a40957fffc Merge remote-tracking branch 'upstream/master' 2016-09-02 09:24:18 -05:00
David Solin
8ffd852e67 SPACES NOT TABS (like in Silicon Valley). 2016-09-02 09:16:26 -05:00
Jeroen van Erp
b90be512e7 REformatted 2016-09-02 16:08:26 +02:00
Jeroen van Erp
c0d49cf6b3 Removed dependency on VRallev ECC25519 library 2016-09-02 16:05:18 +02:00
David Solin
1b5b2b25b7 Merge branch 'master' into post-logging-factory 2016-09-02 06:45:58 -05:00
Jeroen van Erp
1dad19ca6e Merge pull request #267 from joval/logging-factory
Logging factory
2016-09-02 10:55:43 +02:00
David Solin
90fa26925d Merge branch 'logging-factory' into post-logging-factory 2016-08-29 15:19:57 -05:00
David Solin
9425300262 Better argument order for IdentificationStringParser constructor. 2016-08-29 15:19:06 -05:00
David A. Solin
f2bfe9bfcf Make Java-6 compatible. 2016-08-26 13:26:01 -05:00
David Solin
71498ad961 Added some features required to integrate sshj with Joval's remote jSAF provider.
1) Added boolean Channel.isEOF() method, for checking whether the server has sent EOF.
2) Added SFTP response constants to the Response enumeration
3) Spelling correction for the SYMLINK FileMode enum constant
2016-08-26 13:02:16 -05:00
David Solin
7b8b1cfdf5 Merge branch 'master' into logging-factory 2016-08-24 08:37:24 -05:00
David Solin
3f29879eca Test fixes 2016-08-24 08:35:08 -05:00
David Solin
79c1ae2bb0 Re-add public constructor used by Groovy 2016-08-24 08:08:33 -05:00
David Solin
819d411cf1 Merge branch 'master' of github.com:joval/sshj into logging-factory 2016-08-24 07:57:22 -05:00
David Solin
6579f6f710 Removed unnecessary DefaultLoggerFactory inner class from DefaultConfig
Fixed license header in LoggerFactory.java (via gradle licenseForamat)
2016-08-24 07:34:01 -05:00
David Solin
cf5830eda5 Indentation fixes. 2016-08-24 06:23:45 -05:00
Jeroen van Erp
36ad389ccf Merge pull request #266 from joval/master
Decryption fix and junit test updates for PKCS5
2016-08-24 13:04:36 +02:00
David Solin
f63a88ec9f Removed unnecessary import statements. 2016-08-23 19:24:11 -05:00
David Solin
7379a89268 Inadvertently added this class to a PR where it's not in-scope. 2016-08-23 19:18:51 -05:00
David Solin
219901211e Changes for injecting a LoggingFactory. 2016-08-23 19:13:43 -05:00
David Solin
8c1329036a Updated test case for PKCS5 over-"simplification", to prevent regression. 2016-08-23 19:08:03 -05:00
David Solin
733c19350c Un-break PKCS5 (I inadvertently over-simplified setting the salt length). 2016-08-23 17:40:00 -05:00
Jeroen van Erp
e5ec84c06a Merge pull request #265 from joval/master
Minor modifications to PKCS5KeyFile
2016-08-19 23:35:03 +02:00
David Solin
ed0156c985 Forgot to move 2 fields to the top of the file. 2016-08-19 15:54:48 -05:00
David Solin
6321685881 Moved constant declarations per codacy. 2016-08-19 15:51:07 -05:00
David Solin
f6b4d47945 Another missing import. This should be it. 2016-08-19 15:09:50 -05:00
David Solin
d198ef121c Missing import in test. 2016-08-19 15:04:55 -05:00
David Solin
7786468875 Simplification? 2016-08-19 15:00:12 -05:00
David Solin
0847e8460a Merge remote-tracking branch 'upstream/master' 2016-08-19 12:24:14 -05:00
David Solin
62b8726807 Fixed bug wherein PKCS5KeyFile messed up the data if a bad passphrase was used, which prevented decryption with a subsequent correct passphrase.
Also, made it possible for subclasses of PKCS5KeyFile to access the decrypted ASN.1 data directly (useful if you want to decrypt then store a PKCS5 key for later use elsewhere).
And I think I made the code a little prettier.
2016-08-19 12:18:49 -05:00
Jeroen van Erp
a6af27ae91 Added Codacy badge 2016-08-19 13:02:55 +02:00
Jeroen van Erp
628cbf5eba Organized imports 2016-08-19 12:57:37 +02:00
Jeroen van Erp
e134e00574 Merge pull request #263 from joval/master
Modifications for working with SSH gateways
2016-08-17 08:41:33 +02:00
David Solin
1caa7ac722 For null hostnames, use the loopback InetAddress (for backward-compatibility). 2016-08-16 10:26:57 -05:00
David Solin
4183776adb Updates per Jeroen van Erp. 2016-08-16 09:17:30 -05:00
David Solin
791f112752 Merge remote-tracking branch 'upstream/master' 2016-08-15 09:27:10 -05:00
Jeroen van Erp
233f3765c9 Added PKCS5 key file support (#262) 2016-08-15 15:49:47 +02:00
Jeroen van Erp
5f292d398f Fixed toString of FileAttributes (Fixes #258) 2016-08-15 09:56:13 +02:00
David Solin
ba347f927d Close any LocalPortForwarders with the SSHClient that produced them (assuming they're still open). 2016-08-15 00:17:48 -05:00
David Solin
6f9ecf69e4 Reordered connect methods so that the similar ones are grouped together.
Also, eliminated all use of InetAddress.getByName, because we'll want to be able to connect even when the target host is only visible to DNS from the Proxy, or the SocketFactory.
2016-08-14 14:06:40 -05:00
David Solin
e78ae4dbeb 4th time's the charm? 2016-08-13 15:11:20 -05:00
David Solin
618f2fd111 String.format error was causing tests to unexpectedly fail. 2016-08-13 14:45:00 -05:00
David Solin
8503046302 Made the pkcs8-blanks file an actual pkcs8 file (so it doesn't fail the test). 2016-08-13 14:21:59 -05:00
David Solin
c6cde27e4b Oops, I shouldn't have encrypted the pkcs8 key file. 2016-08-13 11:00:00 -05:00
David Solin
113aa0aebd Updated KeyProviderUtil, KeyFormat, KeyProviderUtilTest and test resources to properly differentiate between PKCS5 and PKCS8 file formats. 2016-08-13 10:24:05 -05:00
David Solin
e7c50165c7 Removed GNUmake-related files from source control
Removed 3rd-party JARs from source control
Re-introduced original BouncyCastle-dependent PKCS5KeyFile class
Re-named non-BouncyCastle-dependent PKCS8KeyFile class to PKCS5KeyFile, since it really only supports PKCS5 formats anyway
2016-08-13 10:03:52 -05:00
David Solin
09616c4834 Tweaks 2016-08-12 20:03:08 -05:00
David Solin
df710d8dc9 Added getFingerprint method to SSH Known Host entry API.
Removed BouncyCastle dependency for public key authentication.
2016-08-12 19:58:09 -05:00
David Solin
df82774ea3 Added resources and GNUmake files.
Updated StreamCopier class to make it compatible with older SLF4J versions.
2016-08-10 21:45:30 -05:00
Jeroen van Erp
caa6cca665 Updated README for 0.17.2 and upcoming 0.17.3 release 2016-07-19 11:36:03 +02:00
Jeroen van Erp
9a5ccefb5d Removed dependency on net.i2p.crypto.eddsa.math classes (Fixes #255) 2016-07-19 11:22:13 +02:00
Jeroen van Erp
90f8c592b0 Prepped for v0.17.2 release 2016-07-07 11:03:05 +02:00
Jeroen van Erp
f491e8d101 Fixed bug that crept in 0edc4a5 2016-07-07 11:01:43 +02:00
Jeroen van Erp
77c10334f1 Updated for 0.17.1 release 2016-07-06 16:23:12 +02:00
Jeroen van Erp
0edc4a5787 Reimplemented parsing the identification (Fixes #176)
This ensures that any header lines sent before the identification
string do not break the identification parsing if they are longer
than the identification string should be.
2016-07-06 16:20:39 +02:00
Jeroen van Erp
b43cff07bf Updated README 2016-07-05 13:14:30 +02:00
Jeroen van Erp
1ab72b7eaf Ensure that same name subdirs aren't omitted when doing SFTP (#253)
* Updated version string in config

* Fixed #252 with backwards compatible behaviour

* Fixed logic and expanded test
2016-07-05 12:21:51 +02:00
Juraj Oprsal
3229584a95 made classes non-final to allow mocking (#250) 2016-05-20 14:59:31 +02:00
Jeroen van Erp
364a82154d Add correct source manifest headers for OSGI (#244) (Fixes #242)
* Improved OSGI sources manifest

* Added correct manifest entries for OSGI source bundle (Fixes #242)

* Removed empty sourceset
2016-04-15 11:01:50 +02:00
Jeroen van Erp
11fbf2964b Merge pull request #243 from valery1707/badges
Add some useful badges with automatic version detection: Maven and Javadoc
2016-04-14 20:39:39 +02:00
Valeriy.Vyrva
a248d50301 Add some useful badges with automatic version detection: Maven and Javadoc 2016-04-14 16:42:36 +06:00
Jeroen van Erp
fddc943565 updated release notes 2016-04-11 16:17:14 +02:00
Jeroen van Erp
ae834134d0 Release task depends on build and uploadArchives 2016-04-11 16:14:58 +02:00
Jeroen van Erp
bc41908694 Added gradle release and license plugins, and updated all license headers 2016-04-11 15:48:43 +02:00
Jeroen van Erp
bf1a855647 Updated README with release notes. 2016-04-11 15:08:24 +02:00
Jeroen van Erp
cd3b0a5bd6 Some cleanup 2016-04-11 15:05:54 +02:00
Jeroen van Erp
b01eccda4a Fixed bug in Forward lookup in which we did not deal with the special cases (Fixes #239) 2016-04-11 15:05:27 +02:00
Jeroen van Erp
4c9ebc306d Added OSGI manifest to -sources.jar (Fixes #242) 2016-04-11 10:56:18 +02:00
Jeroen van Erp
c3f75cda19 Fixed javadoc warning 2016-03-21 10:17:12 +01:00
Jeroen van Erp
1f0e2b1e69 Attempt to fix race condition if a packet is received from the server immediately after successful auth (Fixes #237) 2016-03-21 10:17:01 +01:00
Jeroen van Erp
8e55e50fd9 Fixed some Java7 warnings 2016-03-21 10:15:47 +01:00
Jeroen van Erp
eb8b7b51ca Added callback to request updated password for a user in case of USERAUTH_PASSWD_CHANGEREQ (Fixes #193) 2016-03-18 15:24:58 +01:00
Jeroen van Erp
a2cccd5cef Added javadoc to indicate that close() should always be called on a Command, before inspecting the result(s) (Fixes #114) 2016-03-18 13:31:25 +01:00
Jeroen van Erp
50403483da Implemented switch for waiting on server ident before sending client ident. (Fixes #118) 2016-03-18 13:24:33 +01:00
Jeroen van Erp
3c230a0fc4 Fixed potential race condition identified in #203 2016-03-18 13:11:59 +01:00
Jeroen van Erp
4f152749ce JavaDoc fixes 2016-03-18 13:11:03 +01:00
Jeroen van Erp
e0df6a5fb5 Organised some imports 2016-03-18 13:09:28 +01:00
Jeroen van Erp
f36c011844 Dropped Java6 support (Fixes #234) 2016-03-18 13:09:28 +01:00
Jeroen van Erp
94113eb6f5 Upgraded gradle to 2.12 2016-03-18 13:09:28 +01:00
Jeroen van Erp
0532f27a78 Merge pull request #238 from hierynomus/issue-236
Fix for race condition in global request response handling (fixes #236)
2016-03-18 11:29:01 +01:00
Jeroen van Erp
bd67135ffa Fixed race condition in global request response handling 2016-03-18 11:17:09 +01:00
Jeroen van Erp
ca49ca324f Added reproducing testcase 2016-03-18 10:53:15 +01:00
Jeroen van Erp
ac2ffbc367 Added settings.gradle with project name 2015-12-11 14:46:24 +01:00
Jeroen van Erp
dbb0eb0238 Ingoring integration test 2015-11-20 15:00:02 +01:00
Jeroen van Erp
347e6ad655 Set to snapshot 2015-11-20 14:47:38 +01:00
Jeroen van Erp
2622833831 Fixed typo in README 2015-11-20 14:47:17 +01:00
Jeroen van Erp
c0487c9ee5 v0.15.0 2015-11-20 14:46:06 +01:00
Jeroen van Erp
3372db75b5 Updated README with release notes 2015-11-20 13:52:40 +01:00
Jeroen van Erp
db75bad25c Added support for ed25519 keys (Fixes #220) 2015-11-20 13:48:59 +01:00
Jeroen van Erp
a73776ad40 Merge pull request #226 from hierynomus/ecdsa_fix
Correctly calculating ECDSA key fingerprint (Fixes #225)
2015-11-18 22:30:57 +01:00
Jeroen van Erp
237c7d18b6 Correctly calculating ECDSA key fingerprint (Fixes #225) 2015-11-18 22:19:15 +01:00
Jeroen van Erp
b7c8cda851 Refactored test to be reusable for other algorithm variants 2015-11-18 12:41:11 +01:00
Jeroen van Erp
2b6fedc939 Added all RFC Ciphers and some extended ones 2015-11-11 22:10:29 +01:00
Jeroen van Erp
51e1ff24e4 Merge pull request #223 from fingolfin/patch-1
README.adoc: fix typos (exhange -> exchange)
2015-11-10 09:40:38 +01:00
Max Horn
05efcb4889 README.adoc: fix typos (exhange -> exchange) 2015-11-10 08:39:55 +01:00
Jeroen van Erp
d456612d25 Now v0.14.0 for real, forgot buildfile 2015-11-04 10:32:49 +01:00
Jeroen van Erp
6feed72251 v0.14.0 2015-11-04 10:27:51 +01:00
Jeroen van Erp
67e44241d0 Upgraded wrapper 2015-11-04 10:27:46 +01:00
Jeroen van Erp
a2a5923767 Added todo comment 2015-11-04 10:27:39 +01:00
Jeroen van Erp
bdf9ab7452 Added missing key signature algorithm to README 2015-11-04 09:40:50 +01:00
Jeroen van Erp
afdfa91eb7 Added curve25519-sha256@libssh.org to the default config 2015-11-03 16:22:18 +01:00
Jeroen van Erp
29a6cf6f79 Added support for curve25519-sha256@libssh.org (Fixes #171) 2015-11-03 16:18:53 +01:00
Jeroen van Erp
eece80cf48 Enabled ecdh-sha2-nistp521 2015-11-03 13:47:04 +01:00
Jeroen van Erp
7973cb1ff6 Upgraded Apache SSHD to 1.0.0 2015-11-03 13:43:00 +01:00
Jeroen van Erp
75c0ae9a83 Updated readme with new kex algorithms 2015-11-02 15:31:31 +01:00
Jeroen van Erp
f2314e74ed Added support for ecdh-sha2-nistp256 and ecdh-sha2-nistp384 key exchange algorithms 2015-11-02 15:29:47 +01:00
Jeroen van Erp
e041e3e1e3 updated release notes 2015-10-29 12:37:17 +01:00
Jeroen van Erp
47df71c836 Implemented diffie-hellman-group-exchange Kex methods (Fixes #167) 2015-10-29 12:30:58 +01:00
Jeroen van Erp
e24ed6ee7b Merge pull request #216 from juddgaddie/master
Throw a SCPRemoteException when an error occurs on the remote server
2015-10-28 22:46:51 +01:00
gaddiej
10f8645ecd Throw a SCPRemoteException when an error occurs on the remote server. SCPRemoteException contains the error message returned from the remote server. 2015-10-24 13:54:49 +00:00
Jeroen van Erp
d520585a09 SCP remote path escaping is now configurable (Fixes #212, #184, #152) 2015-09-21 14:51:57 +02:00
Jeroen van Erp
28a11b0b45 Merge pull request #210 from iterate-ch/issue-209
Fix issue 209.
2015-08-18 18:55:50 +02:00
Jeroen van Erp
a335185827 Moved to SNAPSHOT 2015-08-18 17:30:25 +02:00
Jeroen van Erp
74a4012023 Merge pull request #208 from lguerin/bandwidth
SCP : limit the used bandwidth
2015-08-18 17:23:55 +02:00
Billy Keyes
c98ad22a7a Skip blank lines when detecting key formats
Some private keys found in the wild start with a blank line, which
breaks SSHJ. OpenSSH utilities worked as expected with these key files.

Also add some basic tests for key formats.
2015-08-18 14:25:13 +02:00
Jeroen van Erp
1c749da957 v0.13.0 2015-08-18 14:25:13 +02:00
David Kocher
5d81e87bce Fix issue 209. 2015-08-17 10:11:55 +02:00
lguerin
d18e9d9961 Refactor SCP arguments 2015-08-13 14:44:45 +02:00
lguerin
84990ada08 Fix typo 2015-08-13 14:41:09 +02:00
lguerin
9c424f9431 Remove underscores from Test method's name 2015-08-13 11:37:15 +02:00
lguerin
dec00efcaa Fix typo and clarify rate transfer comment 2015-08-13 10:49:56 +02:00
Jeroen van Erp
742553912c Move to new travis infra 2015-08-13 10:23:08 +02:00
lguerin
e81fdb8d8b Verbose failed tests 2015-08-13 09:36:02 +02:00
lguerin
782ff9b83e Add an option to limit the used bandwidth with SCP upload and download features 2015-08-12 16:55:08 +02:00
Jeroen van Erp
84d15f4cf5 Removed old pom 2015-08-03 14:06:55 +02:00
Jeroen van Erp
1ebcbb07ba Fixed examples build 2015-08-03 14:06:38 +02:00
Jeroen van Erp
9982e5c30e Added testcase for #194 2015-06-17 21:49:05 +02:00
Jeroen van Erp
3f340d6927 Updated version in default config 2015-06-17 16:17:36 +02:00
Jeroen van Erp
b8eec64a37 Added tests and categories 2015-06-17 16:04:01 +02:00
Jeroen van Erp
314d9d01cf Updated release notes 2015-06-17 13:04:32 +02:00
Jeroen van Erp
c526f8e3de Merge branch 'bkarge-issue-183' 2015-06-17 12:37:55 +02:00
Jeroen van Erp
9529c30105 Reformatted 2015-06-17 12:36:31 +02:00
Jeroen van Erp
6a476858d1 Added RemoteFileTest 2015-06-17 12:28:57 +02:00
Jeroen van Erp
6bfb268c11 Merge branch 'issue-183' of https://github.com/bkarge/sshj into bkarge-issue-183 2015-06-17 12:12:56 +02:00
Jeroen van Erp
e334525da5 Rewritten integration tests 2015-06-17 12:12:37 +02:00
Jeroen van Erp
8776500fa0 Merge pull request #201 from iterate-ch/feature/algorithms-verifier
Add option for client to verify negotiated key exchange algorithms.
2015-06-16 15:50:06 +02:00
David Kocher
a747db88ed Add option for client to verify negotiated key exchange algorithms. 2015-06-16 15:42:01 +02:00
Jeroen van Erp
97065264de Cleared some JavaDoc warnings 2015-06-16 14:12:36 +02:00
Jeroen van Erp
7c26ac669a Started better integration testing setup with Mina 2015-06-16 14:12:24 +02:00
Jeroen van Erp
1c5b462206 Merge pull request #195 from bluekeyes/feature/gss-api
Add support for "gssapi-with-mic" authentication (Kerberos)
2015-06-16 10:33:44 +02:00
Jeroen van Erp
4cb9610cdd Merge pull request #196 from Boris-de/fix_hostname_matching
bugfix: match complete host instead of contains on the hoststring
2015-06-16 10:23:52 +02:00
Billy Keyes
b9d0a03cb3 Add simple test for AuthGssApiWithMic
Mock enough of the JGSS API to avoid needing a real Kerberos
environment. I'm not sure how accurate this is, but it should test that
the client is sending the correct packets in the corect order.
2015-06-11 11:44:44 -07:00
Billy Keyes
4adc83b9df Expose GSSManager in AuthGssApiWithMic
The default implementation only supports Kerberos and encourages
subclassing, so there should be a way to provide subclasses.
2015-06-11 11:38:02 -07:00
Björn Karge
14edb33fa9 fix for issue 183 (sftp.RemoteFile.ReadAheadRemoteFileInputStream) (revised) 2015-06-04 10:50:13 +08:00
Björn Karge
8e74330b0b fix for issue 183 (sftp.RemoteFile.ReadAheadRemoteFileInputStream) 2015-06-03 14:36:23 +08:00
Boris Wachtmeister
5217d34198 bugfix: match complete host instead of contains on the hoststring
The SimpleEntry currently matches the hostname of the connection against
the complete hoststring of the entry. This way substrings also match, so
for example "10.0.0.1" matches on an entry for "10.0.0.10", resulting in
a host-key-changed message if the key differs which is usually does.
2015-05-28 21:57:25 +02:00
Billy Keyes
d3d019c1c2 Remove unused imports in SSHClient 2015-05-19 10:49:20 -07:00
Ben Hamme
49185b044d Added AuthGssApiWithMic for Kerberos auth 2015-05-18 15:00:11 -07:00
Jeroen van Erp
a18d623f44 Release notes for 0.12.0 2015-04-14 13:14:15 +02:00
Jeroen van Erp
6855873ffd removed release plugin 2015-04-14 12:57:40 +02:00
Jeroen van Erp
2ca8d8b19e Upgraded gradle 2015-04-14 12:03:38 +02:00
Jeroen van Erp
da32b145df Added braces to single-line statements 2015-04-13 11:50:34 +02:00
Jeroen van Erp
8ea6bb4a66 Updated README for fixed #181 and #180 issue 2015-04-01 11:28:14 +02:00
Jeroen van Erp
6cf767528a Added comment to check why that field is needed 2015-04-01 11:25:43 +02:00
Jeroen van Erp
b123a6ae30 Merge pull request #181 from iterate-ch/issue-180
Fix length field for SSH_FXP_WRITE packets.
2015-04-01 11:24:30 +02:00
Jeroen van Erp
4250c61e45 Deprecated Proxy connect methods, moved Sockets utility class to backport package 2015-03-31 09:27:13 +02:00
Jeroen van Erp
ace09fa8c8 Added support for HTTP CONNECT proxies by implementing custom Socket (Fixes #170) 2015-03-30 21:53:04 +02:00
Jeroen van Erp
8398b6e3c3 Revert "Added support for (unauthenticated) HTTP proxies (fixes #170)"
This reverts commit fc535a5e76.
2015-03-30 21:48:07 +02:00
Jeroen van Erp
3c1e0c1629 Updated readme 2015-03-27 16:04:42 +01:00
Andrew Kondratovich
e6c7c17664 Correctly closing channel and socket when LocalPortForwarder fails to open it. (Fix #175) 2015-03-27 16:02:07 +01:00
Jeroen van Erp
1e061aef25 Updated readme with work in progress for next release 2015-03-27 15:30:58 +01:00
Jeroen van Erp
66b772bac1 Compiling for JDK6, fixes #179 and #185 2015-03-27 15:25:45 +01:00
Jeroen van Erp
fc535a5e76 Added support for (unauthenticated) HTTP proxies (fixes #170) 2015-03-27 15:19:04 +01:00
Jeroen van Erp
c7373f05cc Merge pull request #186 from bluekeyes/fix/read-end-of-stream
Detect end-of-stream in TransportImpl#init
2015-03-16 10:34:47 +01:00
Billy Keyes
3ebd2eb363 Detect end-of-stream in TransportImpl#init
OpenSSH will drop connections based on the value of MaxStartups when
there are too many unauthenticated connection. When this happens, reads
on the client socket return -1, which was previously inserted into the
identification buffer, leading to the error in #118.
2015-03-13 15:34:18 -07:00
David Kocher
8638091517 Fix length field for SSH_FXP_WRITE packets. 2015-02-24 15:27:08 +01:00
hierynomus
5fc08a3fc8 back to snapshot 2015-01-23 10:08:51 +01:00
hierynomus
92df7c6924 v0.11.0 2015-01-23 10:07:43 +01:00
294 changed files with 8089 additions and 2332 deletions

5
.gitignore vendored
View File

@@ -12,6 +12,9 @@
# Output dirs
target/
build/
docs/
.gradle/
sshj.jar
# MacOS X
.DS_Store

View File

@@ -1 +1,5 @@
language: java
language: java
sudo: false
jdk:
- oraclejdk7
- oraclejdk8

13
LICENSE_HEADER Normal file
View 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.

View File

@@ -1,10 +1,13 @@
= sshj - SSHv2 library for Java
Jeroen van Erp
:sshj_groupid: com.hierynomus
:sshj_version: 0.11.0
:sshj_version: 0.18.0
:source-highlighter: pygments
image::https://travis-ci.org/hierynomus/sshj.svg?branch=master[]
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 :)
@@ -59,13 +62,15 @@ In the `examples` directory, there is a separate Maven project that shows how th
Implementations / adapters for the following algorithms are included:
ciphers::
`aes{128,192,256}-{cbc,ctr}`, `blowfish-cbc`, `3des-cbc`
`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-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`
`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`
@@ -78,6 +83,8 @@ private key files::
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.
@@ -92,8 +99,58 @@ Google Group: http://groups.google.com/group/sshj-users
Fork away!
== Release history
SSHJ 0.11.0 (No date set yet)::
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]

View File

@@ -1,34 +1,28 @@
apply plugin: "java"
apply plugin: "maven"
apply plugin: "signing"
apply plugin: "osgi"
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"
version = "0.11.0"
defaultTasks "build"
repositories {
mavenCentral()
mavenLocal()
}
configurations {
compile {
transitive = false
}
}
sourceCompatibility = 1.6
targetCompatibility = 1.6
test {
include "**/*Test.*"
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")
}
}
}
configurations.compile.transitive = false
def bouncycastleVersion = "1.51"
@@ -38,10 +32,36 @@ dependencies {
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:0.11.0"
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')
}
}
jar {
@@ -50,6 +70,7 @@ jar {
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*"
@@ -66,93 +87,123 @@ task javadocJar(type: Jar) {
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"
)
}
}
artifacts {
archives javadocJar, sourcesJar
}
signing {
required { !version.contains("SNAPSHOT") && gradle.taskGraph.hasTask("uploadArchives") }
sign configurations.archives
}
// This disables the pedantic doclint feature of JDK8
if (JavaVersion.current().isJava8Compatible()) {
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
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")
}
}
}
uploadArchives {
if(project.hasProperty('sonatypeUsername')) {
repositories.mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
project.tasks.compileGroovy.onlyIf { false }
configuration = configurations.archives
github {
user 'hierynomus'
license 'Apache'
}
repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2') {
authentication(userName: sonatypeUsername, password: sonatypePassword)
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"
}
snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/') {
authentication(userName: sonatypeUsername, password: sonatypePassword)
}
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"
}
}
}
}
pom.project {
name "sshj"
description "SSHv2 library for Java"
url "https://github.com/hierynomus/sshj"
inceptionYear "2009"
publishing.publications {
Sshj(MavenPublication) {
from components.java
artifact sourcesJar
artifact javadocJar
}
}
issueManagement {
system "github"
url "https://github.com/hierynomus/sshj/issues"
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")
}
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"
}
}
mavenCentralSync {
sync = true
user = project.property("sonatypeUsername")
password = project.property("sonatypePassword")
close = 1
}
}
}
}
}
project.tasks.release.dependsOn([project.tasks.build, project.tasks.bintrayUpload])

View File

@@ -21,10 +21,10 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.schmizz</groupId>
<artifactId>sshj</artifactId>
<groupId>com.hierynomus</groupId>
<artifactId>sshj-examples</artifactId>
<packaging>jar</packaging>
<version>0.10.0</version>
<version>0.14.0</version>
<name>sshj-examples</name>
<description>Examples for SSHv2 library for Java</description>
@@ -53,9 +53,9 @@
<dependencies>
<dependency>
<groupId>net.schmizz</groupId>
<groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
<version>0.10.0</version>
<version>0.15.0</version>
</dependency>
</dependencies>

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.keepalive.KeepAliveProvider;

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
@@ -37,4 +22,4 @@ public class SCPDownload {
}
}
}
}

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
@@ -42,4 +27,4 @@ public class SCPUpload {
ssh.disconnect();
}
}
}
}

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
@@ -42,4 +27,4 @@ public class SFTPDownload {
}
}
}
}

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
@@ -44,4 +29,4 @@ public class SFTPUpload {
}
}
}
}

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
@@ -67,4 +52,4 @@ public class X11 {
ssh.disconnect();
}
}
}
}

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#Wed Jan 21 09:17:25 CET 2015
#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-2.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-all.zip

344
pom.xml
View File

@@ -1,344 +0,0 @@
<?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>net.schmizz</groupId>
<artifactId>sshj</artifactId>
<packaging>bundle</packaging>
<version>0.10.1-SNAPSHOT</version>
<name>sshj</name>
<description>SSHv2 library for Java</description>
<url>http://github.com/hierynomus/sshj</url>
<inceptionYear>2009</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>
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>7</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.51</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.51</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>0.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</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.9.1</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>
<version>2.4.0</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
!net.schmizz.*,
javax.crypto*,
com.jcraft.jzlib*;version="[1.1,2)";resolution:=optional,
org.slf4j*;version="[1.7,5)",
org.bouncycastle*,
*
</Import-Package>
<Export-Package>net.schmizz.*</Export-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
<version>2.6.1</version>
</plugin>
<plugin>
<groupId>com.mycila</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>2.6</version>
<configuration>
<header>src/etc/license-header</header>
<properties>
<owner>sshj contributors</owner>
<email>sshj-users@googlegroups.com</email>
</properties>
<excludes>
<exclude>**/README</exclude>
<exclude>src/test/resources/**</exclude>
<exclude>src/main/resources/**</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.2</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</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-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>doclint-java8-disable</id>
<activation>
<jdk>[1.8,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
<version>2.6.1</version>
</plugin>
</plugins>
</reporting>
</project>

1
settings.gradle Normal file
View File

@@ -0,0 +1 @@
rootProject.name = "sshj"

View File

@@ -1,39 +0,0 @@
package nl.javadude.sshj.connection.channel;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import static org.hamcrest.MatcherAssert.assertThat;
public class ChannelCloseEofTest {
private SSHClient sshClient;
@Before
public void setUp() throws Exception {
sshClient = new SSHClient();
}
@After
public void tearDown() throws IOException {
sshClient.disconnect();
}
@Test
public void shouldCorrectlyHandleSessionChannelEof() throws IOException, InterruptedException {
sshClient.addHostKeyVerifier(new PromiscuousVerifier());
sshClient.connect("172.16.37.129");
sshClient.authPassword("jeroen", "jeroen");
Session session = sshClient.startSession();
session.allocateDefaultPTY();
session.close();
Thread.sleep(1000);
assertThat("Should still be connected", sshClient.isConnected());
}
}

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

View File

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

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

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

View File

@@ -0,0 +1,55 @@
/*
* 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;
/**
* 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("ed25519-sha-512");
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();
}
}

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

View File

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

View File

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

View File

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

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

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

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

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -18,6 +18,8 @@ package net.schmizz.concurrent;
import java.util.concurrent.TimeUnit;
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
* 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 chainer {@link ExceptionChainer} that will be used for chaining exceptions
*/
public Event(String name, ExceptionChainer<T> chainer) {
promise = new Promise<Object, T>(name, chainer);
public Event(String name, ExceptionChainer<T> chainer, LoggerFactory loggerFactory) {
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 lock lock to use
*/
public Event(String name, ExceptionChainer<T> chainer, ReentrantLock lock) {
promise = new Promise<Object, T>(name, chainer, lock);
public Event(String name, ExceptionChainer<T> chainer, ReentrantLock lock, LoggerFactory loggerFactory) {
promise = new Promise<Object, T>(name, chainer, lock, loggerFactory);
}
/** 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();
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -37,4 +37,4 @@ public interface ExceptionChainer<Z extends Throwable> {
Z chain(Throwable t);
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -16,13 +16,14 @@
package net.schmizz.concurrent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
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
* 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> {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Logger log;
private final String name;
private final ExceptionChainer<T> chainer;
private final ReentrantLock lock;
@@ -49,8 +49,8 @@ public class Promise<V, T extends Throwable> {
* @param name name of this promise
* @param chainer {@link ExceptionChainer} that will be used for chaining exceptions
*/
public Promise(String name, ExceptionChainer<T> chainer) {
this(name, chainer, null);
public Promise(String name, ExceptionChainer<T> chainer, LoggerFactory loggerFactory) {
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 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.chainer = chainer;
this.lock = lock == null ? new ReentrantLock() : lock;
this.log = loggerFactory.getLogger(getClass());
this.cond = this.lock.newCondition();
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -22,14 +22,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class KeepAlive extends Thread {
protected final Logger log = LoggerFactory.getLogger(getClass());
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);
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -22,14 +22,13 @@ import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.transport.Transport;
import net.schmizz.sshj.transport.TransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** An abstract class for {@link Service} that implements common or default functionality. */
public abstract class AbstractService
implements Service {
/** Logger */
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final Logger log;
/** Assigned name of this service */
protected final String name;
@@ -39,6 +38,7 @@ public abstract class AbstractService
public AbstractService(String name, Transport trans) {
this.name = name;
this.trans = trans;
log = trans.getConfig().getLoggerFactory().getLogger(getClass());
}
@Override

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,12 +15,24 @@
*/
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.SingletonRandomFactory;
public class AndroidConfig
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
protected void initRandomFactory(boolean ignored) {
setRandomFactory(new SingletonRandomFactory(new JCERandom.Factory()));

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -17,6 +17,7 @@ package net.schmizz.sshj;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.common.LoggerFactory;
import net.schmizz.sshj.signature.Signature;
import net.schmizz.sshj.transport.cipher.Cipher;
import net.schmizz.sshj.transport.compression.Compression;
@@ -155,4 +156,34 @@ public interface Config {
* @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();
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -16,6 +16,7 @@
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.signature.Signature;
import net.schmizz.sshj.transport.cipher.Cipher;
@@ -44,6 +45,9 @@ public class ConfigImpl
private List<Factory.Named<Signature>> signatureFactories;
private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories;
private boolean waitForServerIdentBeforeSendingClientIdent = false;
private LoggerFactory loggerFactory;
@Override
public List<Factory.Named<Cipher>> getCipherFactories() {
return cipherFactories;
@@ -157,4 +161,24 @@ public class ConfigImpl
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;
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,39 +15,27 @@
*/
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.LoggerFactory;
import net.schmizz.sshj.common.SecurityUtils;
import net.schmizz.sshj.signature.SignatureDSA;
import net.schmizz.sshj.signature.SignatureECDSA;
import net.schmizz.sshj.signature.SignatureRSA;
import net.schmizz.sshj.transport.cipher.AES128CBC;
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.cipher.*;
import net.schmizz.sshj.transport.compression.NoneCompression;
import net.schmizz.sshj.transport.kex.DHG1;
import net.schmizz.sshj.transport.kex.DHG14;
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.mac.HMACSHA2256;
import net.schmizz.sshj.transport.mac.HMACSHA2512;
import net.schmizz.sshj.transport.kex.*;
import net.schmizz.sshj.transport.mac.*;
import net.schmizz.sshj.transport.random.BouncyCastleRandom;
import net.schmizz.sshj.transport.random.JCERandom;
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.Iterator;
@@ -79,11 +67,12 @@ import java.util.List;
public class DefaultConfig
extends ConfigImpl {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String VERSION = "SSHJ_0_17_2";
private static final String VERSION = "SSHJ_0_9_2";
private Logger log;
public DefaultConfig() {
setLoggerFactory(LoggerFactory.DEFAULT);
setVersion(VERSION);
final boolean bouncyCastleRegistered = SecurityUtils.isBouncyCastleRegistered();
initKeyExchangeFactories(bouncyCastleRegistered);
@@ -96,11 +85,25 @@ public class DefaultConfig
setKeepAliveProvider(KeepAliveProvider.HEARTBEAT);
}
@Override
public void setLoggerFactory(LoggerFactory loggerFactory) {
super.setLoggerFactory(loggerFactory);
log = loggerFactory.getLogger(getClass());
}
protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) {
if (bouncyCastleRegistered)
setKeyExchangeFactories(new DHG14.Factory(), new DHG1.Factory());
else
setKeyExchangeFactories(new DHG1.Factory());
if (bouncyCastleRegistered) {
setKeyExchangeFactories(new Curve25519SHA256.Factory(),
new DHGexSHA256.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) {
@@ -124,7 +127,30 @@ public class DefaultConfig
new AES192CBC.Factory(),
new AES256CBC.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;
// Ref. https://issues.apache.org/jira/browse/SSHD-24
@@ -138,6 +164,7 @@ public class DefaultConfig
c.init(Cipher.Mode.Encrypt, key, iv);
} catch (Exception e) {
warn = true;
log.warn(e.getCause().getMessage());
i.remove();
}
}
@@ -145,20 +172,30 @@ public class DefaultConfig
log.warn("Disabling high-strength ciphers: cipher strengths apparently limited by JCE policy");
setCipherFactories(avail);
log.debug("Available cipher factories: {}", avail);
}
protected void initSignatureFactories() {
setSignatureFactories(new SignatureECDSA.Factory(), new SignatureRSA.Factory(), new SignatureDSA.Factory());
setSignatureFactories(
new SignatureECDSA.Factory(),
new SignatureRSA.Factory(),
new SignatureDSA.Factory(),
new SignatureEdDSA.Factory()
);
}
protected void initMACFactories() {
setMACFactories(new HMACSHA1.Factory(), new HMACSHA196.Factory(), new HMACMD5.Factory(),
new HMACMD596.Factory(), new HMACSHA2256.Factory(), new HMACSHA2512.Factory());
setMACFactories(
new HMACSHA1.Factory(),
new HMACSHA196.Factory(),
new HMACMD5.Factory(),
new HMACMD596.Factory(),
new HMACSHA2256.Factory(),
new HMACSHA2512.Factory()
);
}
protected void initCompressionFactories() {
setCompressionFactories(new NoneCompression.Factory());
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -16,6 +16,7 @@
package net.schmizz.sshj;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.common.LoggerFactory;
import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.common.SecurityUtils;
import net.schmizz.sshj.connection.Connection;
@@ -39,38 +40,30 @@ import net.schmizz.sshj.transport.TransportImpl;
import net.schmizz.sshj.transport.compression.DelayedZlibCompression;
import net.schmizz.sshj.transport.compression.NoneCompression;
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.OpenSSHKnownHosts;
import net.schmizz.sshj.userauth.UserAuth;
import net.schmizz.sshj.userauth.UserAuthException;
import net.schmizz.sshj.userauth.UserAuthImpl;
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
import net.schmizz.sshj.userauth.keyprovider.KeyFormat;
import net.schmizz.sshj.userauth.keyprovider.KeyPairWrapper;
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.keyprovider.*;
import net.schmizz.sshj.userauth.method.*;
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.Resource;
import net.schmizz.sshj.xfer.scp.SCPFileTransfer;
import org.ietf.jgss.Oid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.login.LoginContext;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
/**
* Secure SHell client API.
@@ -121,7 +114,8 @@ public class SSHClient
public static final int DEFAULT_PORT = 22;
/** Logger */
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final LoggerFactory loggerFactory;
protected final Logger log;
/** Transport layer */
protected final Transport trans;
@@ -132,6 +126,8 @@ public class SSHClient
/** {@code ssh-connection} service */
protected final Connection conn;
private final List<LocalPortForwarder> forwarders = new ArrayList<LocalPortForwarder>();
/** Default constructor. Initializes this object using {@link DefaultConfig}. */
public SSHClient() {
this(new DefaultConfig());
@@ -144,6 +140,8 @@ public class SSHClient
*/
public SSHClient(Config config) {
super(DEFAULT_PORT);
loggerFactory = config.getLoggerFactory();
log = loggerFactory.getLogger(getClass());
this.trans = new TransportImpl(config, this);
this.auth = new UserAuthImpl(trans);
this.conn = new ConnectionImpl(trans, config.getKeepAliveProvider());
@@ -153,10 +151,19 @@ public class SSHClient
* Add a {@link HostKeyVerifier} which will be invoked for verifying host key during connection establishment and
* future key exchanges.
*
* @param hostKeyVerifier {@link HostKeyVerifier} instance
* @param verifier {@link HostKeyVerifier} instance
*/
public void addHostKeyVerifier(HostKeyVerifier hostKeyVerifier) {
trans.addHostKeyVerifier(hostKeyVerifier);
public void addHostKeyVerifier(HostKeyVerifier verifier) {
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);
}
/**
@@ -207,6 +214,7 @@ public class SSHClient
checkConnected();
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;
@@ -278,6 +286,22 @@ public class SSHClient
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
* locations on the file system. This method relies on {@code ~/.ssh/id_rsa} and {@code ~/.ssh/id_dsa}.
@@ -365,6 +389,30 @@ public class SSHClient
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
* to attempt connection after this method has been called.
@@ -375,6 +423,14 @@ public class SSHClient
@Override
public void disconnect()
throws IOException {
for (LocalPortForwarder forwarder : forwarders) {
try {
forwarder.close();
} catch (IOException e) {
log.warn("Error closing forwarder", e);
}
}
forwarders.clear();
trans.disconnect();
super.disconnect();
}
@@ -574,7 +630,7 @@ public class SSHClient
*/
public void loadKnownHosts(File location)
throws IOException {
addHostKeyVerifier(new OpenSSHKnownHosts(location));
addHostKeyVerifier(new OpenSSHKnownHosts(location, loggerFactory));
}
/**
@@ -592,7 +648,9 @@ public class SSHClient
*/
public LocalPortForwarder newLocalPortForwarder(LocalPortForwarder.Parameters parameters,
ServerSocket serverSocket) {
return new LocalPortForwarder(conn, parameters, serverSocket);
LocalPortForwarder forwarder = new LocalPortForwarder(conn, parameters, serverSocket, loggerFactory);
forwarders.add(forwarder);
return forwarder;
}
/**
@@ -619,7 +677,7 @@ public class SSHClient
public SCPFileTransfer newSCPFileTransfer() {
checkConnected();
checkAuthenticated();
return new SCPFileTransfer(this);
return new SCPFileTransfer(this, loggerFactory);
}
/**
@@ -720,4 +778,4 @@ public class SSHClient
}
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,6 +15,9 @@
*/
package net.schmizz.sshj;
import com.hierynomus.sshj.backport.JavaVersion;
import com.hierynomus.sshj.backport.Jdk7HttpProxySocket;
import javax.net.SocketFactory;
import java.io.IOException;
import java.io.InputStream;
@@ -45,34 +48,109 @@ public abstract class SocketClient {
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.connect(new InetSocketAddress(host, port), connectTimeout);
onConnect();
}
public void connect(InetAddress host, int port, Proxy proxy)
throws IOException {
socket = new Socket(proxy);
socket.connect(new InetSocketAddress(host, port), connectTimeout);
onConnect();
}
public void connect(String hostname, int port)
throws IOException {
this.hostname = hostname;
connect(InetAddress.getByName(hostname), port);
}
public void connect(String hostname, int port, Proxy proxy)
throws IOException {
this.hostname = hostname;
connect(InetAddress.getByName(hostname), port, proxy);
}
public void connect(InetAddress host, int port,
InetAddress localAddr, int localPort)
public void connect(InetAddress host, int port, InetAddress localAddr, int localPort)
throws IOException {
socket = socketFactory.createSocket();
socket.bind(new InetSocketAddress(localAddr, localPort));
@@ -80,35 +158,7 @@ public abstract class SocketClient {
onConnect();
}
public void connect(String hostname, int port,
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 connect(InetAddress host, Proxy proxy)
throws IOException {
connect(host, defaultPort, proxy);
}
public void connect(String hostname, Proxy proxy)
throws IOException {
connect(hostname, defaultPort, proxy);
}
public void disconnect()
throws IOException {
public void disconnect() throws IOException {
if (socket != null) {
socket.close();
socket = null;
@@ -131,7 +181,6 @@ public abstract class SocketClient {
return socket.getLocalPort();
}
public InetAddress getLocalAddress() {
return socket.getLocalAddress();
}
@@ -149,10 +198,11 @@ public abstract class SocketClient {
}
public void setSocketFactory(SocketFactory factory) {
if (factory == null)
if (factory == null) {
socketFactory = SocketFactory.getDefault();
else
} else {
socketFactory = factory;
}
}
public SocketFactory getSocketFactory() {
@@ -187,8 +237,7 @@ public abstract class SocketClient {
return output;
}
void onConnect()
throws IOException {
void onConnect() throws IOException {
socket.setSoTimeout(timeout);
input = socket.getInputStream();
output = socket.getOutputStream();

View File

@@ -1,18 +1,3 @@
/**
* 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.
*/
package net.schmizz.sshj.common;
@@ -1742,4 +1727,4 @@ public class Base64 {
private Base64() {
}
} // end class Base64
} // end class Base64

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -426,8 +426,7 @@ public class Buffer<T extends Buffer<T>> {
public PublicKey readPublicKey()
throws BufferException {
try {
final String type = readString();
return KeyType.fromString(type).readPubKeyFromBuffer(type, this);
return KeyType.fromString(readString()).readPubKeyFromBuffer(this);
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e);
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -16,7 +16,6 @@
package net.schmizz.sshj.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
@@ -26,25 +25,33 @@ import java.nio.charset.Charset;
public class IOUtils {
private static final Logger LOG = LoggerFactory.getLogger(IOUtils.class);
public static final Charset UTF8 = Charset.forName("UTF-8");
public static void closeQuietly(Closeable... closeables) {
for (Closeable c : closeables)
try {
if (c != null)
c.close();
} catch (IOException logged) {
LOG.warn("Error closing {} - {}", c, logged);
}
closeQuietly(LoggerFactory.DEFAULT, closeables);
}
public static ByteArrayOutputStream readFully(InputStream stream)
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();
new StreamCopier(stream, baos).copy();
new StreamCopier(stream, baos, loggerFactory).copy();
return baos;
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,6 +15,12 @@
*/
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;
@@ -24,7 +30,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.security.*;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.*;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
@@ -37,7 +46,7 @@ public enum KeyType {
/** SSH identifier for RSA keys */
RSA("ssh-rsa") {
@Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
final BigInteger e, n;
try {
@@ -68,7 +77,7 @@ public enum KeyType {
/** SSH identifier for DSA keys */
DSA("ssh-dss") {
@Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
BigInteger p, q, g, y;
try {
@@ -105,8 +114,11 @@ public enum KeyType {
private final Logger log = LoggerFactory.getLogger(getClass());
@Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
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();
@@ -118,7 +130,7 @@ public enum KeyType {
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",
type,
sType,
curveName,
keyLen,
x04,
@@ -135,7 +147,7 @@ public enum KeyType {
BigInteger bigY = new BigInteger(1, y);
X9ECParameters ecParams = NISTNamedCurves.getByName("p-256");
ECPoint pPublicPoint = ecParams.getCurve().createPoint(bigX, bigY, false);
ECPoint pPublicPoint = ecParams.getCurve().createPoint(bigX, bigY);
ECParameterSpec spec = new ECParameterSpec(ecParams.getCurve(),
ecParams.getG(), ecParams.getN());
ECPublicKeySpec publicSpec = new ECPublicKeySpec(pPublicPoint, spec);
@@ -151,44 +163,62 @@ public enum KeyType {
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
final ECPublicKey ecdsa = (ECPublicKey) pk;
final java.security.spec.ECPoint point = ecdsa.getW();
final byte[] x = trimStartingZeros(point.getAffineX().toByteArray());
final byte[] y = trimStartingZeros(point.getAffineY().toByteArray());
byte[] encoded = SecgUtils.getEncoded(ecdsa.getW(), ecdsa.getParams().getCurve());
buf.putString(sType)
.putString(NISTP_CURVE)
.putUInt32(1 + x.length + y.length)
.putRawBytes(new byte[] { (byte) 0x04 })
.putRawBytes(x)
.putRawBytes(y)
;
.putBytes(encoded);
}
@Override
protected boolean isMyType(Key key) {
return ("ECDSA".equals(key.getAlgorithm()));
}
},
private byte[] trimStartingZeros(byte[] in) {
int i = 0;
for (; i < in.length; i++) {
if (in[i] != 0) {
break;
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);
}
final byte[] out = new byte[in.length - i];
System.arraycopy(in, i, out, 0, out.length);
return out;
}
@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 */
UNKNOWN("unknown") {
@Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
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
@@ -211,7 +241,7 @@ public enum KeyType {
this.sType = type;
}
public abstract PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
public abstract PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException;
public abstract void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf);
@@ -236,5 +266,4 @@ public enum KeyType {
public String toString() {
return sType;
}
}

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

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -30,7 +30,7 @@ public enum Message {
KEXDH_INIT(30),
/** { KEXDH_REPLY, KEXDH_GEX_GROUP } */
/** { KEXDH_REPLY, KEXDH_GEX_GROUP, SSH_MSG_KEX_ECDH_REPLY } */
KEXDH_31(31),
KEX_DH_GEX_INIT(32),
@@ -46,6 +46,9 @@ public enum Message {
USERAUTH_60(60),
USERAUTH_INFO_RESPONSE(61),
USERAUTH_GSSAPI_EXCHANGE_COMPLETE(63),
USERAUTH_GSSAPI_MIC(66),
GLOBAL_REQUEST(80),
REQUEST_SUCCESS(81),
REQUEST_FAILURE(82),

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,47 +15,25 @@
*/
package net.schmizz.sshj.common;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.*;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Signature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// 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 {
private static class BouncyCastleRegistration {
public void run()
throws Exception {
if (java.security.Security.getProvider(BOUNCY_CASTLE) == null) {
LOG.debug("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("BouncyCastle registration succeeded");
} else
LOG.info("BouncyCastle already registered as a JCE provider");
securityProvider = BOUNCY_CASTLE;
}
}
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";
/*
@@ -67,6 +45,42 @@ public class SecurityUtils {
private static Boolean registerBouncyCastle;
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)
throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {
register();
@@ -80,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"
*
* @param key the public key
*
* @return the fingerprint
*
* @see <a href="http://tools.ietf.org/html/draft-friedl-secsh-fingerprint-00">specification</a>
*/
public static String getFingerprint(PublicKey key) {
@@ -105,9 +117,7 @@ public class SecurityUtils {
* Creates a new instance of {@link KeyAgreement} with the given algorithm.
*
* @param algorithm key agreement algorithm
*
* @return new instance
*
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
*/
@@ -124,9 +134,7 @@ public class SecurityUtils {
* Creates a new instance of {@link KeyFactory} with the given algorithm.
*
* @param algorithm key factory algorithm e.g. RSA, DSA
*
* @return new instance
*
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
*/
@@ -143,9 +151,7 @@ public class SecurityUtils {
* Creates a new instance of {@link KeyPairGenerator} with the given algorithm.
*
* @param algorithm key pair generator algorithm
*
* @return new instance
*
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
*/
@@ -162,9 +168,7 @@ public class SecurityUtils {
* Create a new instance of {@link Mac} with the given algorithm.
*
* @param algorithm MAC algorithm
*
* @return new instance
*
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
*/
@@ -181,9 +185,7 @@ public class SecurityUtils {
* Create a new instance of {@link MessageDigest} with the given algorithm.
*
* @param algorithm MessageDigest algorithm name
*
* @return new instance
*
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
*/
@@ -243,20 +245,16 @@ public class SecurityUtils {
private static void register() {
if (!registrationDone) {
if (securityProvider == null && (registerBouncyCastle == null || registerBouncyCastle))
// Use an inner class to avoid a strong dependency on BouncyCastle
try {
new BouncyCastleRegistration().run();
} catch (Throwable t) {
if (registerBouncyCastle == null)
LOG.info("BouncyCastle not registered, using the default 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);
}
if (securityProvider == null && (registerBouncyCastle == null || registerBouncyCastle)) {
registerSecurityProvider("org.bouncycastle.jce.provider.BouncyCastleProvider");
if (securityProvider == null && registerBouncyCastle == null) {
LOG.info("BouncyCastle not registered, using the default JCE provider");
} else if (securityProvider == null) {
LOG.error("Failed to register BouncyCastle as the defaut JCE provider");
throw new SSHRuntimeException("Failed to register BouncyCastle as the defaut JCE provider");
}
registrationDone = true;
}
}
registrationDone = true;
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,10 +15,10 @@
*/
package net.schmizz.sshj.common;
import net.schmizz.sshj.common.LoggerFactory;
import net.schmizz.concurrent.Event;
import net.schmizz.concurrent.ExceptionChainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
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 OutputStream out;
@@ -50,9 +50,11 @@ public class StreamCopier {
private boolean keepFlushing = true;
private long length = -1;
public StreamCopier(InputStream in, OutputStream out) {
public StreamCopier(InputStream in, OutputStream out, LoggerFactory loggerFactory) {
this.in = in;
this.out = out;
this.loggerFactory = loggerFactory;
this.log = loggerFactory.getLogger(getClass());
}
public StreamCopier bufSize(int bufSize) {
@@ -91,7 +93,7 @@ public class StreamCopier {
public IOException chain(Throwable t) {
return (t instanceof IOException) ? (IOException) t : new IOException(t);
}
});
}, loggerFactory);
new Thread() {
{
@@ -107,7 +109,7 @@ public class StreamCopier {
log.debug("Done copying from {}", in);
doneEvent.set();
} catch (IOException ioe) {
log.error("In pipe from {} to {}: {}", in, out, ioe);
log.error(String.format("In pipe from %1$s to %2$s", in.toString(), out.toString()), ioe);
doneEvent.deliverError(ioe);
}
}
@@ -136,7 +138,7 @@ public class StreamCopier {
final double timeSeconds = (System.currentTimeMillis() - startTime) / 1000.0;
final double sizeKiB = count / 1024.0;
log.debug("{} KiB transferred in {} seconds ({} KiB/s)", sizeKiB, 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)
throw new IOException("Encountered EOF, could not transfer " + length + " bytes");

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -156,4 +156,4 @@ public interface Connection {
* @return The configured {@link net.schmizz.keepalive.KeepAlive} mechanism.
*/
KeepAlive getKeepAlive();
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -20,12 +20,7 @@ import net.schmizz.concurrent.Promise;
import net.schmizz.keepalive.KeepAlive;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.AbstractService;
import net.schmizz.sshj.common.Buffer;
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.common.*;
import net.schmizz.sshj.connection.channel.Channel;
import net.schmizz.sshj.connection.channel.OpenFailException.Reason;
import net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener;
@@ -64,9 +59,8 @@ public class ConnectionImpl
/**
* Create with an associated {@link Transport}.
*
* @param config the ssh config
* @param trans transport layer
* @param keepAlive
* @param keepAlive the keep alive provider
*/
public ConnectionImpl(Transport trans, KeepAliveProvider keepAlive) {
super("ssh-connection", trans);
@@ -205,7 +199,7 @@ public class ConnectionImpl
Promise<SSHPacket, ConnectionException> promise = null;
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);
}
return promise;
@@ -216,13 +210,15 @@ public class ConnectionImpl
throws ConnectionException {
synchronized (globalReqPromises) {
Promise<SSHPacket, ConnectionException> gr = globalReqPromises.poll();
if (gr == null)
if (gr == null) {
throw new ConnectionException(DisconnectReason.PROTOCOL_ERROR,
"Got a global request response when none was requested");
else if (response == null)
"Got a global request response when none was requested");
} else if (response == null) {
gr.deliverError(new ConnectionException("Global request [" + gr + "] failed"));
else
gr.deliver(response);
} else {
// To prevent a race condition, copy the packet before delivering, as it will be handled in a different thread.
gr.deliver(new SSHPacket(response));
}
}
}
@@ -278,4 +274,4 @@ public class ConnectionImpl
return keepAlive;
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -17,19 +17,12 @@ package net.schmizz.sshj.connection.channel;
import net.schmizz.concurrent.ErrorDeliveryUtil;
import net.schmizz.concurrent.Event;
import net.schmizz.sshj.common.Buffer;
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.common.*;
import net.schmizz.sshj.connection.Connection;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.transport.Transport;
import net.schmizz.sshj.transport.TransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.io.OutputStream;
@@ -44,7 +37,8 @@ public abstract class AbstractChannel
private static final int REMOTE_MAX_PACKET_SIZE_CEILING = 1024 * 1024;
/** Logger */
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final LoggerFactory loggerFactory;
protected final Logger log;
/** Transport layer */
protected final Transport trans;
@@ -58,6 +52,8 @@ public abstract class AbstractChannel
/** Remote recipient ID */
private int recipient;
private boolean eof = false;
private final Queue<Event<ConnectionException>> chanReqResponseEvents = new LinkedList<Event<ConnectionException>>();
/* The lock used by to create the open & close events */
@@ -83,21 +79,23 @@ public abstract class AbstractChannel
protected AbstractChannel(Connection conn, String type) {
this.conn = conn;
this.loggerFactory = conn.getTransport().getConfig().getLoggerFactory();
this.type = type;
this.log = loggerFactory.getLogger(getClass());
this.trans = conn.getTransport();
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);
openEvent = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, openCloseLock);
closeEvent = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, openCloseLock);
openEvent = new Event<ConnectionException>("chan#" + id + " / " + "open", ConnectionException.chainer, openCloseLock, loggerFactory);
closeEvent = new Event<ConnectionException>("chan#" + id + " / " + "close", ConnectionException.chainer, openCloseLock, loggerFactory);
}
protected void init(int recipient, long remoteWinSize, long remoteMaxPacketSize) {
this.recipient = recipient;
rwin = new Window.Remote(remoteWinSize, (int) Math.min(remoteMaxPacketSize, REMOTE_MAX_PACKET_SIZE_CEILING));
rwin = new Window.Remote(remoteWinSize, (int) Math.min(remoteMaxPacketSize, REMOTE_MAX_PACKET_SIZE_CEILING), loggerFactory);
out = new ChannelOutputStream(this, trans, rwin);
log.debug("Initialized - {}", this);
}
@@ -195,6 +193,16 @@ public abstract class AbstractChannel
}
}
@Override
public boolean isEOF() {
return eof;
}
@Override
public LoggerFactory getLoggerFactory() {
return loggerFactory;
}
private void gotClose()
throws TransportException {
log.debug("Got close");
@@ -362,7 +370,7 @@ public abstract class AbstractChannel
Event<ConnectionException> responseEvent = null;
if (wantReply) {
responseEvent = new Event<ConnectionException>("chan#" + id + " / " + "chanreq for " + reqType,
ConnectionException.chainer);
ConnectionException.chainer, loggerFactory);
chanReqResponseEvents.add(responseEvent);
}
return responseEvent;
@@ -393,6 +401,7 @@ public abstract class AbstractChannel
/** Called when EOF has been received. Subclasses can override but must call super. */
protected void eofInputStreams() {
in.eof();
eof = true;
}
@Override
@@ -402,4 +411,4 @@ public abstract class AbstractChannel
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -16,6 +16,7 @@
package net.schmizz.sshj.connection.channel;
import net.schmizz.sshj.common.ErrorNotifiable;
import net.schmizz.sshj.common.LoggerFactory;
import net.schmizz.sshj.common.SSHPacketHandler;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.transport.TransportException;
@@ -25,13 +26,15 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
/** A channel is the basic medium for application-layer data on top of an SSH transport. */
public interface Channel
extends Closeable, SSHPacketHandler, ErrorNotifiable {
/**
* A channel is the basic medium for application-layer data on top of an SSH transport.
*/
public interface Channel extends Closeable, SSHPacketHandler, ErrorNotifiable {
/** Direct channels are those that are initiated by us. */
interface Direct
extends Channel {
/**
* Direct channels are those that are initiated by us.
*/
interface Direct extends Channel {
/**
* Request opening this channel from remote end.
@@ -40,27 +43,30 @@ public interface Channel
* @throws ConnectionException other connection-layer error
* @throws TransportException error writing packets etc.
*/
void open()
throws ConnectionException, TransportException;
void open() throws ConnectionException, TransportException;
}
/** Forwarded channels are those that are initiated by the server. */
interface Forwarded
extends Channel {
/**
* Forwarded channels are those that are initiated by the server.
*/
interface Forwarded extends Channel {
/**
* Confirm {@code CHANNEL_OPEN} request.
*
* @throws TransportException error sending confirmation packet
*/
void confirm()
throws TransportException;
void confirm() throws TransportException;
/** @return the IP of where the forwarded connection originates. */
/**
* @return the IP of where the forwarded connection originates.
*/
String getOriginatorIP();
/** @return port from which the forwarded connection originates. */
/**
* @return port from which the forwarded connection originates.
*/
int getOriginatorPort();
/**
@@ -68,55 +74,73 @@ public interface Channel
*
* @param reason indicate {@link OpenFailException.Reason reason} for rejection of the request
* @param message indicate a message for why the request is rejected
*
* @throws TransportException error sending rejection packet
*/
void reject(OpenFailException.Reason reason, String message)
throws TransportException;
void reject(OpenFailException.Reason reason, String message) throws TransportException;
}
/** Close this channel. */
/**
* Close this channel.
*/
@Override
void close()
throws TransportException, ConnectionException;
void close() throws TransportException, ConnectionException;
/**
* @return whether auto-expansion of local window is set.
*
* @see #setAutoExpand(boolean)
*/
boolean getAutoExpand();
/** @return the channel ID */
/**
* @return the channel ID
*/
int getID();
/** @return the {@code InputStream} for this channel. */
/**
* @return the {@code InputStream} for this channel.
*/
InputStream getInputStream();
/** @return the maximum packet size that we have specified. */
/**
* @return the maximum packet size that we have specified.
*/
int getLocalMaxPacketSize();
/** @return the current local window size. */
/**
* @return the current local window size.
*/
long getLocalWinSize();
/** @return an {@code OutputStream} for this channel. */
/**
* @return an {@code OutputStream} for this channel.
*/
OutputStream getOutputStream();
/** @return the channel ID at the remote end. */
/**
* @return the channel ID at the remote end.
*/
int getRecipient();
/** @return the maximum packet size as specified by the remote end. */
/**
* @return the maximum packet size as specified by the remote end.
*/
int getRemoteMaxPacketSize();
/** @return the current remote window size. */
/**
* @return the current remote window size.
*/
long getRemoteWinSize();
/** @return the channel type identifier. */
/**
* @return the channel type identifier.
*/
String getType();
/** @return whether the channel is open. */
/**
* @return whether the channel is open.
*/
boolean isOpen();
/**
@@ -128,10 +152,17 @@ public interface Channel
*/
void setAutoExpand(boolean autoExpand);
void join()
throws ConnectionException;
void join() throws ConnectionException;
void join(long timeout, TimeUnit unit)
throws ConnectionException;
void join(long timeout, TimeUnit unit) throws ConnectionException;
/**
* Returns whether EOF has been received.
*/
boolean isEOF();
/**
* Get the LoggerFactory associated with the SSH client.
*/
LoggerFactory getLoggerFactory();
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,11 +15,7 @@
*/
package net.schmizz.sshj.connection.channel;
import net.schmizz.sshj.common.Buffer;
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.common.*;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.transport.Transport;
import net.schmizz.sshj.transport.TransportException;
@@ -38,7 +34,7 @@ public final class ChannelInputStream
extends InputStream
implements ErrorNotifiable {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Logger log;
private final Channel chan;
private final Transport trans;
@@ -51,6 +47,7 @@ public final class ChannelInputStream
public ChannelInputStream(Channel chan, Transport trans, Window.Local win) {
this.chan = chan;
log = chan.getLoggerFactory().getLogger(getClass());
this.trans = trans;
this.win = win;
buf = new Buffer.PlainBuffer(chan.getLocalMaxPacketSize());
@@ -130,7 +127,12 @@ public final class ChannelInputStream
buf.putRawBytes(data, offset, len);
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())
checkWindow();
}
@@ -153,4 +155,4 @@ public final class ChannelInputStream
return "< ChannelInputStream for Channel #" + chan.getID() + " >";
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,11 +15,7 @@
*/
package net.schmizz.sshj.connection.channel;
import net.schmizz.sshj.common.Buffer;
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.common.*;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.transport.Transport;
import net.schmizz.sshj.transport.TransportException;

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -18,11 +18,12 @@ package net.schmizz.sshj.connection.channel;
import net.schmizz.concurrent.Event;
import net.schmizz.sshj.common.IOUtils;
import java.io.Closeable;
import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import static com.hierynomus.sshj.backport.Sockets.asCloseable;
public class SocketStreamCopyMonitor
extends Thread {
@@ -32,16 +33,6 @@ public class SocketStreamCopyMonitor
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,
final Event<IOException> x, final Event<IOException> y,
final Channel channel, final Socket socket) {
@@ -54,7 +45,7 @@ public class SocketStreamCopyMonitor
}
} catch (IOException ignored) {
} finally {
IOUtils.closeQuietly(channel, wrapSocket(socket));
IOUtils.closeQuietly(channel, asCloseable(socket));
}
}
}).start();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,14 +15,14 @@
*/
package net.schmizz.sshj.connection.channel;
import net.schmizz.sshj.common.LoggerFactory;
import net.schmizz.sshj.common.SSHRuntimeException;
import net.schmizz.sshj.connection.ConnectionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class Window {
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final Logger log;
protected final Object lock = new Object();
@@ -30,9 +30,10 @@ public abstract class Window {
protected long size;
public Window(long initialWinSize, int maxPacketSize) {
public Window(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
size = initialWinSize;
this.maxPacketSize = maxPacketSize;
log = loggerFactory.getLogger(getClass());
}
public void expand(long inc) {
@@ -72,8 +73,8 @@ public abstract class Window {
public static final class Remote
extends Window {
public Remote(long initialWinSize, int maxPacketSize) {
super(initialWinSize, maxPacketSize);
public Remote(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
super(initialWinSize, maxPacketSize, loggerFactory);
}
public long awaitExpansion(long was)
@@ -108,8 +109,8 @@ public abstract class Window {
private final long initialSize;
private final long threshold;
public Local(long initialWinSize, int maxPacketSize) {
super(initialWinSize, maxPacketSize);
public Local(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) {
super(initialWinSize, maxPacketSize, loggerFactory);
this.initialSize = initialWinSize;
threshold = Math.min(maxPacketSize * 20, initialSize / 4);
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -94,4 +94,4 @@ public abstract class AbstractDirectChannel
}
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -16,20 +16,22 @@
package net.schmizz.sshj.connection.channel.direct;
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.StreamCopier;
import net.schmizz.sshj.connection.Connection;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
import net.schmizz.sshj.transport.TransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.TimeUnit;
import static com.hierynomus.sshj.backport.Sockets.asCloseable;
public class LocalPortForwarder {
public static class Parameters {
@@ -80,10 +82,10 @@ public class LocalPortForwarder {
throws IOException {
socket.setSendBufferSize(getLocalMaxPacketSize());
socket.setReceiveBufferSize(getRemoteMaxPacketSize());
final Event<IOException> soc2chan = new StreamCopier(socket.getInputStream(), getOutputStream())
final Event<IOException> soc2chan = new StreamCopier(socket.getInputStream(), getOutputStream(), loggerFactory)
.bufSize(getRemoteMaxPacketSize())
.spawnDaemon("soc2chan");
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), socket.getOutputStream())
final Event<IOException> chan2soc = new StreamCopier(getInputStream(), socket.getOutputStream(), loggerFactory)
.bufSize(getLocalMaxPacketSize())
.spawnDaemon("chan2soc");
SocketStreamCopyMonitor.monitor(5, TimeUnit.SECONDS, soc2chan, chan2soc, this, socket);
@@ -100,23 +102,29 @@ public class LocalPortForwarder {
}
private final Logger log = LoggerFactory.getLogger(LocalPortForwarder.class);
private final LoggerFactory loggerFactory;
private final Logger log;
private final Connection conn;
private final Parameters parameters;
private final ServerSocket serverSocket;
public LocalPortForwarder(Connection conn, Parameters parameters, ServerSocket serverSocket) {
public LocalPortForwarder(Connection conn, Parameters parameters, ServerSocket serverSocket, LoggerFactory loggerFactory) {
this.conn = conn;
this.parameters = parameters;
this.serverSocket = serverSocket;
this.loggerFactory = loggerFactory;
this.log = loggerFactory.getLogger(getClass());
}
protected DirectTCPIPChannel openChannel(Socket socket)
throws TransportException, ConnectionException {
final DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, socket, parameters);
chan.open();
return chan;
private void startChannel(Socket socket) throws IOException {
DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, socket, parameters);
try {
chan.open();
chan.start();
} catch (IOException e) {
IOUtils.closeQuietly(chan, asCloseable(socket));
throw e;
}
}
/**
@@ -128,11 +136,33 @@ public class LocalPortForwarder {
throws IOException {
log.info("Listening on {}", serverSocket.getLocalSocketAddress());
while (!Thread.currentThread().isInterrupted()) {
final Socket socket = serverSocket.accept();
log.debug("Got connection from {}", socket.getRemoteSocketAddress());
openChannel(socket).start();
try {
final Socket socket = serverSocket.accept();
log.debug("Got connection from {}", socket.getRemoteSocketAddress());
startChannel(socket);
} catch (SocketException e) {
if (!serverSocket.isClosed()) {
throw e;
}
}
}
if (serverSocket.isClosed()) {
log.debug("LocalPortForwarder closed");
} else {
log.debug("LocalPortForwarder interrupted!");
}
log.debug("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();
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -48,18 +48,24 @@ public interface Session
/**
* 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}.
* <p/>
* <strong>NOTE: </strong> Always call {@link #close()} first before inspecting the exit error message.
*/
String getExitErrorMessage();
/**
* Returns the {@link Signal signal} if the command exit violently, or {@code null} if this information was not
* received.
* <p/>
* <strong>NOTE: </strong> Always call {@link #close()} first before inspecting the exit signal.
*/
Signal getExitSignal();
/**
* Returns the exit status of the command if it was received, or {@code null} if this information was not
* received.
* <p/>
* <strong>NOTE: </strong> Always call {@link #close()} first before inspecting the exit status.
*/
Integer getExitStatus();

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,12 +15,7 @@
*/
package net.schmizz.sshj.connection.channel.direct;
import net.schmizz.sshj.common.Buffer;
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.common.*;
import net.schmizz.sshj.connection.Connection;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.channel.ChannelInputStream;

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -73,4 +73,4 @@ public abstract class AbstractForwardedChannel
return origPort;
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -29,14 +29,14 @@ import java.io.IOException;
public abstract class AbstractForwardedChannelOpener
implements ForwardedChannelOpener {
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final Logger log;
protected final String chanType;
protected final Connection conn;
protected AbstractForwardedChannelOpener(String chanType, Connection conn) {
this.chanType = chanType;
this.conn = conn;
log = conn.getTransport().getConfig().getLoggerFactory().getLogger(getClass());
}
@Override
@@ -72,4 +72,4 @@ public abstract class AbstractForwardedChannelOpener
}.start();
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -117,6 +117,34 @@ public class RemotePortForwarder
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. */
@@ -224,11 +252,15 @@ public class RemotePortForwarder
} catch (Buffer.BufferException be) {
throw new ConnectionException(be);
}
if (listeners.containsKey(chan.getParentForward()))
callListener(listeners.get(chan.getParentForward()), chan);
else
chan.reject(OpenFailException.Reason.ADMINISTRATIVELY_PROHIBITED, "Forwarding was not requested on `"
+ chan.getParentForward() + "`");
for (Forward forward : listeners.keySet()) {
if (forward.handles(chan)) {
callListener(listeners.get(forward), chan);
return;
}
}
chan.reject(OpenFailException.Reason.ADMINISTRATIVELY_PROHIBITED, "Forwarding was not requested on `"
+ chan.getParentForward() + "`");
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -19,8 +19,6 @@ import net.schmizz.concurrent.Event;
import net.schmizz.sshj.common.StreamCopier;
import net.schmizz.sshj.connection.channel.Channel;
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.Socket;
@@ -31,8 +29,6 @@ import java.util.concurrent.TimeUnit;
public class SocketForwardingConnectListener
implements ConnectListener {
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final SocketAddress addr;
/** Create with a {@link SocketAddress} this listener will forward to. */
@@ -44,7 +40,7 @@ public class SocketForwardingConnectListener
@Override
public void gotConnect(Channel.Forwarded chan)
throws IOException {
log.debug("New connection from {}:{}", chan.getOriginatorIP(), chan.getOriginatorPort());
chan.getLoggerFactory().getLogger(getClass()).debug("New connection from {}:{}", chan.getOriginatorIP(), chan.getOriginatorPort());
final Socket sock = new Socket();
sock.setSendBufferSize(chan.getLocalMaxPacketSize());
@@ -55,11 +51,11 @@ public class SocketForwardingConnectListener
// ok so far -- could connect, let's confirm the channel
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())
.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())
.spawnDaemon("chan2soc");

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -222,7 +222,7 @@ public final class FileAttributes {
sb.append("size=").append(size).append(";");
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))
sb.append("mode=").append(mode.toString()).append(";");

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -36,7 +36,7 @@ public class FileMode {
/** directory */
DIRECTORY(0040000),
/** symbolic link */
SYMKLINK(0120000),
SYMLINK(0120000),
/** unknown */
UNKNOWN(0);

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -17,7 +17,6 @@ package net.schmizz.sshj.sftp;
import net.schmizz.concurrent.Promise;
import net.schmizz.sshj.common.SSHException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,7 +29,7 @@ public class PacketReader
extends Thread {
/** Logger */
private final Logger log = LoggerFactory.getLogger(getClass());
private final Logger log;
private final InputStream in;
private final Map<Long, Promise<Response, SFTPException>> promises = new ConcurrentHashMap<Long, Promise<Response, SFTPException>>();
@@ -40,6 +39,7 @@ public class PacketReader
public PacketReader(SFTPEngine engine) {
this.engine = engine;
log = engine.getLoggerFactory().getLogger(getClass());
this.in = engine.getSubsystem().getInputStream();
setName("sftp reader");
}
@@ -107,7 +107,7 @@ public class PacketReader
public Promise<Response, SFTPException> expectResponseTo(long requestId) {
final Promise<Response, SFTPException> promise
= new Promise<Response, SFTPException>("sftp / " + requestId, SFTPException.chainer);
= new Promise<Response, SFTPException>("sftp / " + requestId, SFTPException.chainer, engine.getLoggerFactory());
promises.put(requestId, promise);
return promise;
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -63,4 +63,4 @@ public class PathComponents {
return "[parent=" + parent + "; name=" + name + "; path=" + path + "]";
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -15,12 +15,7 @@
*/
package net.schmizz.sshj.sftp;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.*;
public class RandomAccessRemoteFile
implements DataInput, DataOutput {

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit;
public class RemoteDirectory
extends RemoteResource {
public RemoteDirectory(Requester requester, String path, byte[] handle) {
public RemoteDirectory(SFTPEngine requester, String path, byte[] handle) {
super(requester, path, handle);
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -19,6 +19,7 @@ import net.schmizz.concurrent.Promise;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.sftp.Response.StatusCode;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -29,41 +30,35 @@ import java.util.concurrent.TimeUnit;
public class RemoteFile
extends RemoteResource {
public RemoteFile(Requester requester, String path, byte[] handle) {
public RemoteFile(SFTPEngine requester, String path, byte[] handle) {
super(requester, path, handle);
}
public FileAttributes fetchAttributes()
throws IOException {
public FileAttributes fetchAttributes() throws IOException {
return requester.request(newRequest(PacketType.FSTAT))
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS)
.ensurePacketTypeIs(PacketType.ATTRS)
.readFileAttributes();
}
public long length()
throws IOException {
public long length() throws IOException {
return fetchAttributes().getSize();
}
public void setLength(long len)
throws IOException {
public void setLength(long len) throws IOException {
setAttributes(new FileAttributes.Builder().withSize(len).build());
}
public int read(long fileOffset, byte[] to, int offset, int len)
throws IOException {
public int read(long fileOffset, byte[] to, int offset, int len) throws IOException {
final Response res = asyncRead(fileOffset, len).retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
return checkReadResponse(res, to, offset);
}
protected Promise<Response, SFTPException> asyncRead(long fileOffset, int len)
throws IOException {
protected Promise<Response, SFTPException> asyncRead(long fileOffset, int len) throws IOException {
return requester.request(newRequest(PacketType.READ).putUInt64(fileOffset).putUInt32(len));
}
protected int checkReadResponse(Response res, byte[] to, int offset)
throws Buffer.BufferException, SFTPException {
protected int checkReadResponse(Response res, byte[] to, int offset) throws Buffer.BufferException, SFTPException {
switch (res.getType()) {
case DATA:
int recvLen = res.readUInt32AsInt();
@@ -79,27 +74,25 @@ public class RemoteFile
}
}
public void write(long fileOffset, byte[] data, int off, int len)
throws IOException {
public void write(long fileOffset, byte[] data, int off, int len) throws IOException {
checkWriteResponse(asyncWrite(fileOffset, data, off, len));
}
protected Promise<Response, SFTPException> asyncWrite(long fileOffset, byte[] data, int off, int len)
throws IOException {
return requester.request(newRequest(PacketType.WRITE)
.putUInt64(fileOffset)
.putUInt32(len - off)
.putRawBytes(data, off, len)
.putUInt64(fileOffset)
// TODO The SFTP spec claims this field is unneeded...? See #187
.putUInt32(len)
.putRawBytes(data, off, len)
);
}
private void checkWriteResponse(Promise<Response, SFTPException> responsePromise)
throws SFTPException {
private void checkWriteResponse(Promise<Response, SFTPException> responsePromise) throws SFTPException {
responsePromise.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS).ensureStatusPacketIsOK();
}
public void setAttributes(FileAttributes attrs)
throws IOException {
public void setAttributes(FileAttributes attrs) throws IOException {
requester.request(newRequest(PacketType.FSETSTAT).putFileAttributes(attrs))
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS).ensureStatusPacketIsOK();
}
@@ -139,15 +132,13 @@ public class RemoteFile
}
@Override
public void write(int w)
throws IOException {
public void write(int w) throws IOException {
b[0] = (byte) w;
write(b, 0, 1);
}
@Override
public void write(byte[] buf, int off, int len)
throws IOException {
public void write(byte[] buf, int off, int len) throws IOException {
if (unconfirmedWrites.size() > maxUnconfirmedWrites) {
checkWriteResponse(unconfirmedWrites.remove());
}
@@ -156,23 +147,20 @@ public class RemoteFile
}
@Override
public void flush()
throws IOException {
public void flush() throws IOException {
while (!unconfirmedWrites.isEmpty()) {
checkWriteResponse(unconfirmedWrites.remove());
}
}
@Override
public void close()
throws IOException {
public void close() throws IOException {
flush();
}
}
public class RemoteFileInputStream
extends InputStream {
public class RemoteFileInputStream extends InputStream {
private final byte[] b = new byte[1];
@@ -200,31 +188,32 @@ public class RemoteFile
}
@Override
public void reset()
throws IOException {
public void reset() throws IOException {
fileOffset = markPos;
}
@Override
public long skip(long n)
throws IOException {
return (this.fileOffset = Math.min(fileOffset + n, length()));
public long skip(long n) throws IOException {
final long fileLength = length();
final Long previousFileOffset = fileOffset;
fileOffset = Math.min(fileOffset + n, fileLength);
return fileOffset - previousFileOffset;
}
@Override
public int read()
throws IOException {
public int read() throws IOException {
return read(b, 0, 1) == -1 ? -1 : b[0] & 0xff;
}
@Override
public int read(byte[] into, int off, int len)
throws IOException {
public int read(byte[] into, int off, int len) throws IOException {
int read = RemoteFile.this.read(fileOffset, into, off, len);
if (read != -1) {
fileOffset += read;
if (markPos != 0 && read > readLimit) // Invalidate mark position
if (markPos != 0 && read > readLimit) {
// Invalidate mark position
markPos = 0;
}
}
return read;
}
@@ -237,27 +226,56 @@ public class RemoteFile
private final byte[] b = new byte[1];
private final int maxUnconfirmedReads;
private final Queue<Promise<Response, SFTPException>> unconfirmedReads;
private final Queue<Promise<Response, SFTPException>> unconfirmedReads = new LinkedList<Promise<Response, SFTPException>>();
private final Queue<Long> unconfirmedReadOffsets = new LinkedList<Long>();
private long fileOffset;
private long requestOffset;
private long responseOffset;
private boolean eof;
public ReadAheadRemoteFileInputStream(int maxUnconfirmedReads) {
assert 0 <= maxUnconfirmedReads;
this.maxUnconfirmedReads = maxUnconfirmedReads;
this.unconfirmedReads = new LinkedList<Promise<Response, SFTPException>>();
this.fileOffset = 0;
}
public ReadAheadRemoteFileInputStream(int maxUnconfirmedReads, long fileOffset) {
assert 0 <= maxUnconfirmedReads;
assert 0 <= fileOffset;
this.maxUnconfirmedReads = maxUnconfirmedReads;
this.unconfirmedReads = new LinkedList<Promise<Response, SFTPException>>();
this.fileOffset = fileOffset;
this.requestOffset = this.responseOffset = fileOffset;
}
@Override
public long skip(long n)
throws IOException {
throw new IOException("skip is not supported by ReadAheadFileInputStream, use RemoteFileInputStream instead");
private ByteArrayInputStream pending = new ByteArrayInputStream(new byte[0]);
private boolean retrieveUnconfirmedRead(boolean blocking) throws IOException {
if (unconfirmedReads.size() <= 0) {
return false;
}
if (!blocking && !unconfirmedReads.peek().isDelivered()) {
return false;
}
unconfirmedReadOffsets.remove();
final Response res = unconfirmedReads.remove().retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
switch (res.getType()) {
case DATA:
int recvLen = res.readUInt32AsInt();
responseOffset += recvLen;
pending = new ByteArrayInputStream(res.array(), res.rpos(), recvLen);
break;
case STATUS:
res.ensureStatusIs(Response.StatusCode.EOF);
eof = true;
break;
default:
throw new SFTPException("Unexpected packet: " + res.getType());
}
return true;
}
@Override
@@ -267,26 +285,66 @@ public class RemoteFile
}
@Override
public int read(byte[] into, int off, int len)
throws IOException {
while (!eof && unconfirmedReads.size() <= maxUnconfirmedReads) {
// Send read requests as long as there is no EOF and we have not reached the maximum parallelism
unconfirmedReads.add(asyncRead(fileOffset, len));
fileOffset += len;
public int read(byte[] into, int off, int len) throws IOException {
while (!eof && pending.available() <= 0) {
// we also need to go here for len <= 0, because pending may be at
// EOF in which case it would return -1 instead of 0
while (unconfirmedReads.size() <= maxUnconfirmedReads) {
// Send read requests as long as there is no EOF and we have not reached the maximum parallelism
int reqLen = Math.max(1024, len); // don't be shy!
unconfirmedReads.add(RemoteFile.this.asyncRead(requestOffset, reqLen));
unconfirmedReadOffsets.add(requestOffset);
requestOffset += reqLen;
}
long nextOffset = unconfirmedReadOffsets.peek();
if (responseOffset != nextOffset) {
// the server could not give us all the data we needed, so
// we try to fill the gap synchronously
assert responseOffset < nextOffset;
assert 0 < (nextOffset - responseOffset);
assert (nextOffset - responseOffset) <= Integer.MAX_VALUE;
byte[] buf = new byte[(int) (nextOffset - responseOffset)];
int recvLen = RemoteFile.this.read(responseOffset, buf, 0, buf.length);
if (recvLen < 0) {
eof = true;
return -1;
}
if (0 == recvLen) {
// avoid infinite loops
throw new SFTPException("Unexpected response size (0), bailing out");
}
responseOffset += recvLen;
pending = new ByteArrayInputStream(buf, 0, recvLen);
} else if (!retrieveUnconfirmedRead(true /*blocking*/)) {
// this may happen if we change prefetch strategy
// currently, we should never get here...
throw new IllegalStateException("Could not retrieve data for pending read request");
}
}
if (unconfirmedReads.isEmpty()) {
assert eof;
return -1;
}
// Retrieve first in
final Response res = unconfirmedReads.remove().retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
final int recvLen = checkReadResponse(res, into, off);
if (recvLen == -1) {
eof = true;
}
return recvLen;
return pending.read(into, off, len);
}
@Override
public int available() throws IOException {
boolean lastRead = true;
while (!eof && (pending.available() <= 0) && lastRead) {
lastRead = retrieveUnconfirmedRead(false /*blocking*/);
}
return pending.available();
}
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2009 sshj contributors
/*
* 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.
@@ -26,14 +26,15 @@ public abstract class RemoteResource
implements Closeable {
/** Logger */
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final Logger log;
protected final Requester requester;
protected final SFTPEngine requester;
protected final String path;
protected final byte[] handle;
protected RemoteResource(Requester requester, String path, byte[] handle) {
protected RemoteResource(SFTPEngine requester, String path, byte[] handle) {
this.requester = requester;
log = requester.getLoggerFactory().getLogger(getClass());
this.path = path;
this.handle = handle;
}

Some files were not shown because too many files have changed in this diff Show More