Compare commits

...

357 Commits

Author SHA1 Message Date
Jeroen van Erp
8f3d751431 Some cleanup of integration container and add integration test 2021-04-20 11:29:52 +02:00
Jeroen van Erp
9051c8c7e9 Merge branch 'master' into issue-670 2021-04-20 09:28:08 +02:00
Estraysian
e283880e49 Minor improvement for SCP preserve flag: (#680)
- Added an override for copy method, allowing the user to specify whether preserve flag is used in the SCP command.
- Propagated the preserveTime boolean to process method to skip preserveTimeIfPossible when it's not desired
2021-04-13 11:32:30 +02:00
Jeroen van Erp
cf7309c866 Add extra logging to troubleshoot issue #670 2021-03-30 12:00:34 +02:00
Jeroen van Erp
45b2f32b14 Fixed examples for 0.31.0 2021-03-29 11:39:49 +02:00
Jeroen van Erp
1d8eaa7ce2 Release version: 0.31.0 2021-02-08 22:21:35 +01:00
Jeroen van Erp
6eea9a993c VSCode files 2021-02-08 22:21:23 +01:00
Jeroen van Erp
67d2cf72d6 Prepare release notes for 0.31.0 2021-02-08 22:17:42 +01:00
Jeroen van Erp
b8d58389cf Merge branch 'informaticum-master' 2021-01-13 14:30:45 +01:00
Jeroen van Erp
c5f48f9888 Merge branch 'master' of github.com:informaticum/sshj into informaticum-master 2021-01-13 14:30:29 +01:00
Jeroen van Erp
c05c3307b3 Update dependencies
- BouncyCastle 1.68
- asn-one 0.5.0
- slf4j-api 1.7.30
2021-01-13 10:41:01 +01:00
Vladimir Lagunov
9bc9262842 Support ED25519 and ECDSA keys in the PuTTY format (#660)
* Support ED25519 PuTTY keys.

Fix #659

* PuTTYKeyFile: Use net.schmizz.sshj.common.Buffer instead of own KeyReader.

A tiny refactoring made in order to allow usage of other utility methods which require Buffer.

* Support ECDSA PuTTY keys.

* Some code cleanup

Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
2021-01-08 22:44:19 +01:00
Fabian Bonk
6d7dd741de Bump bouncycastle version (#655) 2020-12-21 13:41:11 +01:00
stefan
7f8328f23f Backdate license to prevent build's "License violations" (#653) 2020-12-12 20:10:32 +01:00
stefan
be18cc6e6a Add license prelude (#653) 2020-12-12 20:03:42 +01:00
stefan
ee68e0a8e6 Adopt project's import order (#653)
- copied by import order of 'SocketStreamCopyMonitorTest'
2020-12-12 20:03:12 +01:00
stefan
9266b6c04a Testing #toString of Parameters (#653) 2020-12-12 20:00:43 +01:00
stefan
9e9797c326 Adding #toString to Parameters (#653) 2020-12-12 19:58:31 +01:00
stefan
ee7a65531f Testing #equals of Parameters (#653) 2020-12-12 19:58:19 +01:00
stefan
8337cce382 Adding #equals to Parameters (#653) 2020-12-12 19:58:05 +01:00
stefan
bc5a119169 Testing #hashCode of Parameters (#653) 2020-12-12 19:57:51 +01:00
stefan
cda04809e1 Adding #hashCode to Parameters (#653) 2020-12-12 19:56:56 +01:00
Henning Poettker
07d624b1df reduced log level for lenient handling of missing CR at end of identification (#647) 2020-11-24 15:03:11 +01:00
Jeroen van Erp
60aa230929 Update release notes for upcoming 0.31.0 2020-11-17 14:47:18 +01:00
Fabian Henneke
2edaf07e71 Improve Android compatibility (#636)
* Loop through security providers to check for BC

Instead of only counting BouncyCastle as being registered if it
is set as the explicit security provider used by SSHJ, count it as
registered if it is available as a provider.

This commit improves Android compatibility, which requires not
specifying an explicit provider.

* Generify BC-specific curve specifiers

The ECNamendCurveGenParameterSpec is a BC-specific workaround for
missing curve tables in Java 1.4 and earlier. For the sake of Android
compatibility, where Conscrypt can't deal with this custom spec class,
replace it with the standard ECGenParameterSpec and update the curve
names to the standard identifiers.
2020-10-20 09:57:51 +02:00
Fabian Henneke
d124607225 Fix PR links in README (#632) 2020-09-10 09:26:08 +02:00
Jeroen van Erp
8c899eb867 Fix warnings 2020-09-09 11:02:28 +02:00
Jeroen van Erp
939a170ee8 Update README 2020-09-09 10:37:56 +02:00
Raymond Lai
143069e3e0 Implement AES-GCM cipher support (#630)
* Implement AES-GCM cipher support

Fixes #217.

A port of AES-GCM cipher support from Apache MINA-SSHD, based on https://github.com/apache/mina-sshd/pull/132.

Included tests for decoding SSH packets sent from Apache MINA-SSHD and OpenSSH (Version 7.9p1 as used by Debian 10).

Manual tests also done on OpenSSH server 7.9p1 running Debian 10 with its available ciphers, including 3des-cbc, aes128-cbc, aes192-cbc, aes256-cbc, aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com and aes256-gcm@openssh.com.

* Changes per PR feedback

- Fixed variable/statement whitespaces and add back missing braces per coding standard requirement
- Moved Buffer.putLong() and Buffer.getLong() into GcmCipher.CounterGCMParameterSpec since it's the only user
- Moved BaseCipher.authSize into GcmCipher since it is the only cipher that would return a non-zero. BaseCipher will keep return 0 instead
- Made BaseCipher.cipher protected instead of making it publicly accessible
- Combined the three decoding modes in Decoder.decode() into one single method, to reduce code duplication
- Added integration test for the ciphers, along with the newly implemented AES-GCM ciphers
2020-09-09 09:51:17 +02:00
Jeroen van Erp
4458332cbf Update release notes for 0.30.0 2020-08-25 15:56:15 +02:00
Pavel Dionisev
a0d7b7fd41 Avoid key lleakage. (#627)
In some cases, current code will leak parts or even the whole ssh key if it's slightly malformed.
One example of that malformation will be a key, where all newlines are replaced by other character, thus turning a multiline key to a single big string.
Then that whole line will be leaked to exception message.
2020-08-25 15:23:46 +02:00
Jeroen van Erp
b6213401db Release version: 0.30.0 2020-08-17 15:43:12 +02:00
Jeroen van Erp
19ec6d9d8d Made java 11 default java version 2020-08-17 15:42:58 +02:00
Jeroen van Erp
0ba491c01a Add testcase for reading signed certificate (Fixes #613) 2020-08-17 10:59:03 +02:00
Jeroen van Erp
73d7560e6e Add Reader constructor to OpenSSHKnownHosts (Fixes #626) 2020-08-17 10:23:37 +02:00
Vladimir Lagunov
0e0d730bbf Fix RSA certificate key determination. (#602)
* Fix RSA certificate key determination.

Fixes #599.

* Correct serialization of RSA certificates with unlimited dates.

* The test for connecting with RSA certificate.

* Remove redundant change in TransportImpl.java

* Add forgotten test keys.

* Make net.schmizz.sshj.common.KeyType.CertUtils.epochFromDate readable.

Co-authored-by: Vladimir Lagunov <vladimir.lagunov@jetbrains.com>
Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
2020-07-31 09:43:11 +02:00
Fabian Henneke
6becee176a Fix matching of pubkeys to key algorithms (#607)
* Fix matching of pubkeys to key algorithms

Allow all configured key algorithms for pubkey authentication, even if
these algorithms are not supported as host key algorithms by the
server.

Preference is given to the modern rsa-sha2-* signature algorithms if
the server indicates support for them as host keys signature
algorithms.

* Replace Boolean with primitive boolean

* Add integration tests for ecdsa-sha2-nistp384/521

* Remove redundant import

* Clean up Transport interface

Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
2020-07-28 12:30:29 +02:00
Fabian Henneke
4b1619d54f Fix transport encoding of nistp521 signatures (#623)
SignatureECDSA.encode() does not correctly handle signatures longer
than 128 bytes, which affects signatures using the nistp521 curve.

This commits fixes the issue by replacing the ad-hoc ASN.1 DER
parsing with a use of ASN1InputStream.
2020-07-28 11:56:17 +02:00
Fabian Henneke
64f448d438 Send ext-info-c with kex algorithms (#622)
Some SSH servers will not honor the negotiated rsa-sha2-256 algorithms
if the client does not indicate support for SSH_MSG_EXT_INFO messages.
Since we only need to accept these messages, but are free to ignore
their contents, adding support amounts to sending "ext-info-c" with our
kex algorithm proposal.
2020-07-20 15:54:28 +02:00
Moritz Weichert
a5efdf1f0d Bump bonucycastle version (#619)
Co-authored-by: Moritz Weichert <moritz.weichert@check24.de>
2020-07-10 19:02:32 +02:00
Moritz Weichert
588853554a Fix localport for openssh >= 8.0 (#618)
Co-authored-by: Moritz Weichert <moritz.weichert@check24.de>
2020-07-09 11:29:47 +02:00
Fabian Henneke
7bde5c15c1 Clear passphrase bytes after use (#609)
Mimics the behavior of `decrypt()` in `PKCS5KeyFile.java`.
2020-07-01 21:34:31 +02:00
Fabian Henneke
3c85b86915 Always use JCERandom as the default RNG (#606)
The current implementation relies on `VMPCRandomGenerator` for random number generation if BouncyCastle is registered, otherwise it falls back to `SecureRandom`. Nowadays, `SecureRandom` should always be the best available option, whereas `VMPCRandomGenerator` [has known weaknesses](https://books.google.de/books?id=niO6BQAAQBAJ&pg=PA140&lpg=PA140&dq=vmpc+prng&source=bl&ots=QAdZJOT607&sig=ACfU3U0Edqlpm08iRZJLxeWGQNwNQz7WsQ&hl=en&sa=X&ved=2ahUKEwjd2Zyr9pfqAhXWMMAKHT70AioQ6AEwDnoECAoQAQ#v=onepage&q=vmpc%20prng&f=false).
2020-06-23 14:51:55 +02:00
Simon Legner
2ca0fa4732 Use daemon thread to avoid blocking JVM shutdown (#605) 2020-06-23 12:48:11 +02:00
dajoropo
769c896e53 Added method to created Stateful clients ( #268). (#603)
Co-authored-by: Daniel Rodriguez <daniel.rodriguez@elca.ch>
2020-06-22 12:05:11 +02:00
Fabian Henneke
eb19325bc6 Don't specify JcaPEM providers as null (#596)
* Don't specify JcaPEMKeyConverter provider as null

If no provider is set in the `SecurityUtils`, no named provider should be set for the `JcaPEMKeyConverter` as this would cause a `missing provider` exception.

* Don't specify JcePEMDecryptorProviderBuilder provider as null

If no provider is set in the `SecurityUtils`, no named provider should be set for the `JcePEMDecryptorProviderBuilder` as this would cause a missing provider exception. This currently breaks `PKCS8KeyFile` if `SecurityUtils.setSecurityProvider(null)` and `SecurityUtils.setRegisterBouncyCastle(false)` is used.
2020-06-08 09:47:30 +02:00
David Kocher
2d8af5a687 Allow to query for server extensions available. (#591)
Co-authored-by: Jöran Malek <joeran3@gmail.com>
2020-06-05 11:40:58 +02:00
David Kocher
c4fef33d8f Remove length restriction in key reader. (#595) 2020-06-05 11:35:27 +02:00
Jeroen van Erp
ff85e832af Update README.adoc 2020-06-05 11:14:39 +02:00
David Kocher
0dcb4b9a7a Review interface to return collection for allowed authentication methods that allows to query for elements. (#593) 2020-06-05 11:11:50 +02:00
Jeroen van Erp
2baf51bf64 Replace BC ASN.1 dependency with asn-one library 2020-06-02 23:40:08 +02:00
Jeroen van Erp
3194fd9bd0 Refactored KeyAlgorithms slightly 2020-06-02 23:22:55 +02:00
Jeroen van Erp
ab3f0143bd Update release notes 2020-06-02 16:39:56 +02:00
Jeroen van Erp
9671352bda Introduce KeyAlgorithm to separate KeyType from Algorithm (Fixes #588) (#589) 2020-06-02 16:39:22 +02:00
Jeroen van Erp
91105e6a07 Fix integration build 2020-06-02 14:07:31 +02:00
Fabian Henneke
4e802cec86 Make KeyType compatible with Android Keystore (#586)
* Make KeyType compatible with Android Keystore

Android Keystore private keys do not implement PrivateKey since the
raw key material is not available to applications.

With this commit, sshj's KeyType correctly detects the algorithm
associated with Android Keystore keys, which makes them usable for SSH
authentication.

* Extract RSA, DSA, ECDSA and EC into constants

* Fix license lint issue

Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
2020-05-28 16:09:43 +02:00
Fabian Henneke
dfdc464e08 Add pwdf retry logic to OpenSSHKeyV1KeyFile (#587)
* Add pwdf retry logic to OpenSSHKeyV1KeyFile

While PKCS8KeyFile uses PasswordFinder's shouldRetry to determine
whether it should call reqPassword again if decryption of they key file
fails, OpenSSHKeyV1KeyFile simply gives up and throws an exception.

With this commit, retry logic similar to that of PKCS8KeyFile is added
to OpenSSHKeyV1KeyFile. The PasswordFinder's reqPassword is called
again if the validation of the "checkint" fails, which indicates an
incorrect passphrase.

* Use new exception to signal incorrect passphrase

* Throw common exception on key decryption failure

* Add test coverage for retry logic

Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
2020-05-28 09:25:52 +02:00
Jeroen van Erp
fa7c40cc66 Use java12 for building due to gradle --release flag 2020-05-27 16:41:48 +02:00
Vladimir Lagunov
b1be9258b4 Fix NPE in OpenSSHKnownHosts (#579)
Co-authored-by: Vladimir Lagunov <vladimir.lagunov@jetbrains.com>
2020-05-26 14:56:29 +02:00
Jeroen van Erp
11543b2c00 Release version: 0.29.0 2020-05-12 11:30:41 +02:00
Jeroen van Erp
3526694558 Fix build for Java9 and up, verifying Java7 compat 2020-05-12 11:29:30 +02:00
Jeroen van Erp
d618156ede Fix bintray plugin version 2020-05-11 23:17:02 +02:00
Jeroen van Erp
98063680bc Release version: 0.28.0 2020-05-01 11:30:34 +02:00
Jeroen van Erp
17754a65fe Update build.gradle for newer gradle versions 2020-04-16 09:38:04 +02:00
Jeroen van Erp
2bb52fcf7d Add checks for Channel.isOpen to ChannelOutputStream (Fixes #440) 2020-04-14 22:23:35 +02:00
Jeroen van Erp
1a70023e2d Fix task exclusion for java9 2020-04-14 21:48:04 +02:00
Jeroen van Erp
5e25c017bf Remove animalSniffer from Java9 build 2020-04-14 20:42:25 +02:00
Jeroen van Erp
27a5039831 Fixes for GH Actions 2020-04-14 20:39:46 +02:00
Jeroen van Erp
c2d25a9d62 Upgrade release plugin 2020-04-14 20:00:41 +02:00
Jeroen van Erp
2a22809de2 Update gradle.yml 2020-04-14 19:55:24 +02:00
Vladimir Dimitrov
9d1f6d9d83 Making OpenSSHKnownHosts.EntryFactory public 2020-04-14 19:45:11 +02:00
Jeroen van Erp
4542d94440 Add GitHub actions workflow 2020-04-14 16:47:04 +02:00
Jeroen van Erp
46a0cbac9e Upgrade BouncyCastle (Fixes #572) 2020-04-14 16:00:29 +02:00
Jeroen van Erp
f470ddf219 Fix race condition on SERVICE_ACCEPT (Fixes #559) (#560) 2020-02-25 13:33:38 +01:00
Meteorite
d09276fe01 extract makeInetSocketAddress (by hostname) in SocketClient (#509)
to allow overriding with InetSocketAddress.createUnresolved for use with proxy

Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
2020-02-20 09:04:38 +01:00
Josh Soref
241c355e20 Spelling (#547)
* spelling: accommodate

* spelling: algorithms

* spelling: containing

* spelling: creating

* spelling: developed

* spelling: environment

* spelling: exception

* spelling: heartbeat

* spelling: hellman

* spelling: identifier

* spelling: initiated

* spelling: interface

* spelling: negotiated

* spelling: occurred

* spelling: possibility

* spelling: requesting

* spelling: strong

* spelling: successfully

* spelling: suspended

Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
2020-02-19 11:06:27 +01:00
Jeroen van Erp
56ef6c1223 Fix divide by zero in trace logging (Fixes #550) (#561) 2020-02-19 10:27:00 +01:00
Jason
989fb8cde6 Added comment field in HostEntry for end-of-line comments in known_hosts file (#517)
* Added comment field in HostEntry for end-of-line comments in known_hosts file.

* Also modified the getLine() method to return the comment, if it exists.

* Fixed implementation

* Add CODEOWNERS file

Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
2020-02-14 11:40:15 +01:00
Michiel ten Hagen
d10a33ec59 Use nano time instead of current time millis. (#552)
* Use nano time instead of current time millis.

* Add license header
2020-01-22 09:40:53 +01:00
Vladimir Lagunov
327a4c4c5b Forgive redundant spaces in OpenSSHv2 public keys and known_hosts (#524)
* Forgive redundant spaces in OpenSSHv2 public keys and known_hosts

Sometimes users copy-pastes private and public keys in text editors. It leads to redundant spaces
and newlines. OpenSSH can easily read such keys, so users expect from SSHJ the same.

* Fixed bugs in OpenSSH key file and known_hosts parsers

* OpenSSHKnownHosts should not throw errors while parsing corrupted records
2019-09-18 15:14:45 +02:00
Vladimir Lagunov
d5c045defd Fix non-ASCII passwords 2019-09-18 14:36:20 +02:00
Tobias Gruetzmacher
02b70ef427 Minor updates (#520)
* Update Gradle Wrapper to Gradle 4.10.3

* Update test dependencies
2019-08-04 08:57:44 +02:00
Adam Iwaniuk
fdf08ef3c9 Add support for tunneling via channels (#511) 2019-06-03 16:33:39 +02:00
Adam Iwaniuk
633b42fec8 Added support for RSA certificates as host key (#514)
* Added support for RSA certificates as host key

* removed not needed check

* added rsa cert signature verification test
2019-05-27 10:46:01 +02:00
Adam Iwaniuk
3c594d9a1c fix exception when parsing max possible date (#513)
* fix exception when parsing max possible date

* added test with rsa cert with large date
2019-05-27 10:12:45 +02:00
Jeroen van Erp
c2b9c0266d Refactored out duplicate code. 2019-05-08 14:07:46 +02:00
Jeroen van Erp
0e784dd171 Merge branch 'master' into jumping 2019-03-01 21:45:09 +01:00
Jeroen van Erp
f322a4b060 Updated ed25519-java to 0.3.0 2019-03-01 21:44:18 +01:00
Michał Wyrzykowski
0cd19284ee Fix local port forwarding disconnecting issue (#491)
* `SocketStreamCopyMonitor` closes channel after setting the one event. It doesn't wait for the second stream to finish the job.

* #317 Fix `SocketStreamCopyMonitor` to wait for all events before closing the channel.
2019-02-20 15:18:58 +01:00
Jeroen van Erp
a5017d55c8 Cleanup some code 2019-01-24 15:09:00 +01:00
Jeroen van Erp
2f7b181306 Release version: 0.27.0 2019-01-24 13:21:11 +01:00
Jeroen van Erp
20223d3614 Added release notes 2019-01-24 13:19:02 +01:00
Jeroen van Erp
cac340dd43 Add support for other keytypes to openssh-key-v1 keyfiles (#485)
* Added support for RSA to openssh-key-v1 keyfile

* Fixed exception

* Added ECDSA support to openssh-key-v1

* Added integration tests for different keytypes
2019-01-17 13:01:49 +01:00
Jeroen van Erp
00cd335f47 Moved tests to spock 2018-11-27 11:27:45 +01:00
Andremoniy
e14fb2f695 Expose the numeric code of the Response.StatusCode #473 (#474)
* Expose the numeric code of the Response.StatusCode #473

* Expose the numeric code of the Response.StatusCode #473
2018-11-27 10:22:00 +01:00
Pepijn Van Eeckhoudt
b0dee02bf9 Handle server initiated global requests (#472)
* Handle server initiated global requests

* Code layout
2018-11-26 15:16:43 +01:00
Jeroen van Erp
17c09eb471 Fixed integration test 2018-11-16 12:29:45 +01:00
Jeroen van Erp
0301d4537f Enable 'curve25519-sha256@libssh.org' in DefaultConfig (Fixes #464) 2018-11-16 11:48:15 +01:00
Jeroen van Erp
f71d34e106 Ignore bin/ directory 2018-11-16 11:13:09 +01:00
Jeroen van Erp
254f739ac1 Upgraded sshd to 2.1.0 2018-11-16 11:12:58 +01:00
Jeroen van Erp
aa201fa08c Add AES256-CBC to OpenSSHKeyV1KeyFile (Fixes #467) 2018-11-16 10:39:20 +01:00
Jeroen van Erp
8721269d0f Added EdDSA as first signature factory (Fixed #470) 2018-11-16 10:07:32 +01:00
Ben Manes
971ccf6273 Add lock timeout for remote action (fixes #466) (#468)
When the remove window size is expanded, a condition is waited on until
the remote server acknowledges and completes the action. If the server
does not respond, e.g. due to a connectivity issue, then this blocks the
client indefinitely. Instead the client waits up to the connection's
timeout (500 min default) and fails. This allows users to set a reasonable
timeout, fail their operations, and retry accordingly.
2018-11-16 09:33:48 +01:00
Andremoniy
813469646e Improving logging for KeyExchanger (#458) 2018-10-23 10:47:34 +02:00
OlivierSalasc
17c368f9c2 add Buffer capacity check for type UInt64 (#454) 2018-09-27 14:49:25 +02:00
Jeroen van Erp
4de9f8ab9f Add support for Encrypt-then-MAC MAC Algorithms (#450) 2018-08-28 13:22:31 +02:00
Jeroen van Erp
deff097170 Fix SFTPClient.mkdirs to not inadvertently prefix with '/' (#415) 2018-08-02 13:11:09 +02:00
Jeroen van Erp
7556a7f6f6 Updated license header 2018-07-25 12:59:25 +02:00
Jeroen van Erp
c5792fe4a8 Added Kex integration test 2018-07-25 10:34:52 +02:00
Jeroen van Erp
02cfeb9a6a Release version: 0.26.0 2018-07-24 14:27:54 +02:00
Jeroen van Erp
5e771382fe Updated license header 2018-07-24 14:24:28 +02:00
Jeroen van Erp
59e68f1ed7 Updated release plugin 2018-07-24 14:20:10 +02:00
Jeroen van Erp
7d07c1bb46 Refactored Macs and added hmac-ripemd1600@openssh.com 2018-07-24 14:18:02 +02:00
Jeroen van Erp
5bebe044aa Code cleanup, add { to single-line if 2018-07-12 14:55:03 +02:00
Jeroen van Erp
d2a16385da Upgraded BouncyCastle to 1.60 (Fixes #436) 2018-07-10 16:33:33 +02:00
Jeroen van Erp
adc0451b3f Cleanup OpenSSHKeyFile and add Disconnection test 2018-07-10 16:29:09 +02:00
Jeroen van Erp
df5e73f1e8 Close before interrupt LocalPortForwarder (Fixes #426) 2018-07-10 16:28:28 +02:00
Jeroen van Erp
eeeba57c73 Code formatting improvements. 2018-07-10 16:15:37 +02:00
Jeroen van Erp
db48ff85c0 Add support for encrypted ed25519 openssh-key-v1 files (Fixes #427) (#429) 2018-06-19 11:53:32 +02:00
Jeroen van Erp
49a450fb53 Fixed some codacy issues 2018-06-18 14:27:45 +02:00
Tom Caflisch
80d93ae8e7 Remove unnecessary nested try/finally (#417)
* Remove unnecessary nested try/finally

* This handles the case of your concern.

An even better solution would be to have SSHClient and Session implement Auto-Closable so then you don't have to worry about doing anything in the finally block!
2018-06-11 09:54:26 +02:00
Jeroen van Erp
42c52e4fe6 Fixed logging of Encoder to log correct sequence number 2018-04-30 09:30:28 +02:00
Jeroen van Erp
329966ecc4 Using UTF-8 encoding for PrivateKeyFileResource (Fixes #413) 2018-04-30 09:30:00 +02:00
Jeroen van Erp
10918f3201 Using forked gradle process for upload 2018-04-04 13:15:54 +02:00
Jeroen van Erp
b5f0d4c9fb Release version: 0.25.0 2018-04-04 13:05:02 +02:00
Jeroen van Erp
c10cb7f138 Fix release plugin? 2018-04-04 13:03:56 +02:00
Jeroen van Erp
81e26f4a7f Release version: 0.24.0 2018-04-04 12:00:30 +02:00
Jeroen van Erp
aa53effce8 Merge branch 'issue-358' 2018-03-22 22:50:51 +01:00
Jeroen van Erp
76e6e572b4 Merge branch 'master' into issue-358 2018-03-22 22:50:37 +01:00
Jeroen van Erp
2003a9f8c9 Add support for verifying multiple host entries (Fixes #405) 2018-03-21 23:54:25 +01:00
Jeroen van Erp
84a7677a62 Add support for hmac-ripemd-160 2018-03-05 13:00:41 +01:00
Jeroen van Erp
3bcd3530cf Renamed test to spec 2018-03-05 13:00:41 +01:00
Jeroen van Erp
a63f9ee8fd New version Base64 class 2018-03-05 13:00:41 +01:00
Jeroen van Erp
4be5a98ea3 Merge pull request #400 from maxd/public_constructor_of_host_entry
HostEntry constructor must be public
2018-02-20 23:16:41 +01:00
Maxim Dobryakov
26df2f3c23 HostEntry constructor must be public
Reasons:

1) SimpleEntry (was replaced to HostEntry) class had public constructor
2) HostEntry class can be used outside of sshj library to add entries to .known_hosts file (i.e. for implementation of interactive HostKeyVerifier)
2018-02-20 22:59:36 +03:00
Michael Prankl
39b72eed62 Android Compability, again ;-) (#392)
* Rework SecurityUtils and PKCS8KeyFile for usage with SpongyCastle.

* Specifying providerName for registration is unneccessary.

* Update AndroidConfig, fix imports.

* Workaround for Android 5.0 bug when SpongyCastle is the default JCE provider.

On Android 5.0 reading the version from the jar does throw a SecurityException due to a bug in Android (see https://issuetracker.google.com/issues/36993752). Including that Exception in the catch provides a workaround for that issue.
2018-01-30 16:22:05 +01:00
Jeroen van Erp
d55eb6d02e Fix build for windows 2018-01-24 21:34:29 +01:00
Jeroen van Erp
265e9d2916 Add extra logging in OpenSSHKnownHosts and extra test 2018-01-24 15:53:12 +01:00
Jeroen van Erp
0b6552654b Fix 'key spec not recognized' exception with ECDSA keys 2018-01-23 19:58:04 +01:00
Jeroen van Erp
dabe43dfdc Fixed headers 2017-12-28 13:18:30 +01:00
Jeroen van Erp
0f67fa2541 Added integration test for append scenario (Fixes #390) 2017-12-28 13:00:49 +01:00
Michael Prankl
54018a4a81 Update AndroidConfig (#389)
* Add EdDSA signature for AndroidConfig.

* Initialize KeyExchange- and FileKeyProviderFactories with registered "bouncyCastle" (in fact, SpongyCastle is registered).

See #308 for discussion.
2017-12-28 11:55:36 +01:00
Jeroen van Erp
ca81c2eea4 Added integration test to travis 2017-12-28 10:13:56 +01:00
Jeroen van Erp
048f84b42a Removed docker from travis yml as it is included in gradle build now 2017-12-28 10:10:46 +01:00
Jeroen van Erp
8ca6451d5d Fixed length bug in putString (Fixes #187) 2017-12-27 23:02:41 +01:00
Jeroen van Erp
5e1be8b1b0 Separated out integration tests 2017-12-27 23:01:59 +01:00
Jeroen van Erp
bc4da2ea8e Upgraded gradle to cope with java9 2017-12-27 15:02:42 +01:00
Jeroen van Erp
09fb2b9dc2 Merge pull request #385 from Igerly/ssh-with-docker-tests
Integration test(s) with OpenSSH server in Docker
2017-12-04 00:23:44 +01:00
Iger
4045d5a7ef - One more time 2017-12-03 23:10:56 +02:00
Iger
d0daa2c12f - desperation 2017-12-03 23:00:40 +02:00
Iger
64a2a4f779 - orly? 2017-12-03 22:55:18 +02:00
Iger
7cb1f8b11c - switch username back 2017-12-03 22:49:29 +02:00
Iger
73bc785ab4 - eh? 2017-12-03 22:40:41 +02:00
Iger
9d697ede12 - minor improvements 2017-12-03 22:28:02 +02:00
Iger
2b62492caf - grr, ip 2017-12-03 22:11:29 +02:00
Iger
a0f1aa7e2c - Fixed server keys
- Use sshj branding
2017-12-03 22:08:06 +02:00
Iger
0e981f7656 - try common format 2017-12-03 20:25:26 +02:00
Iger
a014567c9e - still -d 2017-12-03 20:05:26 +02:00
Iger
8454cf1a0c - double before_install 2017-12-03 19:44:05 +02:00
Iger
663f118d0f - yaml-yaml 2017-12-03 19:36:20 +02:00
Iger
47d73a9381 - account for different working dir 2017-12-03 19:31:31 +02:00
Iger
c4552d5f3d - fix ip for online testing 2017-12-03 19:18:21 +02:00
Iger
7a884d0938 - Experimenting with travis 2017-12-03 19:10:08 +02:00
Jeroen van Erp
661f63eab7 Updated builds to include CodeCov 2017-11-30 11:33:13 +01:00
Jeroen van Erp
a71a7d7d33 Fix escaping in WildcardHostMatcher (#382)
* Escape '[' and ']' in WildcardHostMatcher

* Anchoring regex to match entire string (Fixes #381)
2017-11-13 15:49:48 +01:00
Jeroen van Erp
d2e0f50d0c Updated build plugins 2017-11-09 15:22:34 +01:00
Jeroen van Erp
b41f0acd19 Using new release plugin 2017-10-16 12:38:55 +02:00
Jeroen van Erp
a1f501a027 Updated README for v0.23.0 release 2017-10-13 16:19:27 +02:00
Jeroen van Erp
fef9cfaf79 Merge pull request #369 from charlesrgould/migrate-block-ciphers
Migrate remaining block ciphers
2017-10-11 23:50:02 +02:00
Charles Gould
c67ae242f2 Migrate remaining block ciphers 2017-10-11 17:34:18 -04:00
charlesrgould
823f1e5759 Log security provider registration failures (#374) 2017-10-11 23:21:49 +02:00
paladox
f046a41750 Update net.i2p.crypto:eddsa to 0.2.0 (#372)
* Update net.i2p.crypto:eddsa to 0.2.0

* Update net.i2p.crypto.eddsa to 0.2.0

* Update net.i2p.crypto.eddsa to 0.2.0

* Update net.i2p.crypto.eddsa to 0.2.0
2017-10-11 21:47:51 +02:00
charlesrgould
c161fe26f6 Extracted ASN.1/DER encoding to method (#368) 2017-10-04 11:06:37 +02:00
Jeroen van Erp
ec46a7a489 Fix decoding signature bytes (Fixes #355, #354) (#361)
* Fix for signature verify in DSA

* Cleaned up signature verification

* Fixed import

* Ignored erroneous pmd warnings

* Updated JavaDoc
2017-09-29 13:23:21 +02:00
Jeroen van Erp
762d088388 Added support for new-style fingerprints (#365)
* Added support for new-style fingerprints

* Fixed codacy warnings
2017-09-28 14:01:04 +02:00
Jeroen van Erp
99c85672b8 Added 'out/' to gitignore 2017-09-19 17:23:26 -04:00
Jeroen van Erp
28d57840ab Organised imports 2017-09-19 17:22:55 -04:00
Charles Gould
2984291d84 Removed deprecated method 2017-09-07 23:18:46 +02:00
Charles Gould
bdbd9d7eb5 Disambiguated signature initialization 2017-09-07 23:18:46 +02:00
Jeroen van Erp
9ac55de26c Fixed Java9 build? 2017-09-07 21:54:42 +02:00
Jeroen van Erp
a9928c2882 fixed build 2017-09-05 15:58:10 +02:00
Jeroen van Erp
c6c9a3f6a8 Correctly determine KeyType for ECDSA public key (Fixes #356) 2017-09-05 15:23:47 +02:00
Jeroen van Erp
0918bc626f Improved test stability 2017-08-24 13:59:58 +02:00
Jeroen van Erp
aa7748395d Removed build of broken openJDK7 in favour of using animal-sniffer to detect java 1.6 compatibility 2017-08-24 13:18:27 +02:00
Jeroen van Erp
cf077e2a4f Removed use of DataTypeConverter as that is no longer in default JDK9 2017-08-24 11:20:35 +02:00
Jeroen van Erp
c58c7c7c60 Added gradle caching to travis config 2017-08-24 09:32:24 +02:00
Jeroen van Erp
0b548d9d13 Removed oraclejdk7 as that is no longer supported on trusty, added openjdk 2017-08-24 09:30:03 +02:00
Jeroen van Erp
eb1629f250 Updated README release notes 2017-08-24 09:11:58 +02:00
Jeroen van Erp
8856aaea61 Fixed codacy 2017-08-22 19:32:45 +02:00
Jeroen van Erp
1f6615b57a Check whether filename is a child of the current file (Fixes #341) 2017-08-22 19:32:45 +02:00
Olli Helenius
a96fbfcf2f Merge branch 'master' into jumping 2017-07-29 10:16:36 +03:00
Matt Dailey
e5084ed8db Removed Builder, and fixed call to checkFormatString 2017-07-10 09:30:10 +02:00
Matt Dailey
3729119e23 Added assertions to testPromptFormat 2017-07-10 09:30:10 +02:00
Matt Dailey
aed3decf1d Upgraded Mockito, and added message and retries to ConsolePasswordFinder
* Upgraded Mockito to 2.8.47 (latest)
* Added extension to allow mocking final classes
* ConsolePasswordFinder allows custom message and number of retries
* Added builder for ConsolePasswordFinder
* Added more unit tests
2017-07-10 09:30:10 +02:00
Matt Dailey
303c03061c Add ConsolePasswordFinder to read from Console
* There was no example `PasswordFinder` to prompt
a user for their password
2017-07-10 09:30:10 +02:00
Olli Helenius
15e6924fc4 Fix indentation 2017-07-06 22:44:31 +03:00
Olli Helenius
9e8bef24c5 Add support for tunneling TCP/IP connections. 2017-07-06 22:32:56 +03:00
Iger
5e3a08a637 - boggle 2017-07-04 10:02:00 +02:00
Iger
d0800058e8 - Test ECDSA signature verifications 2017-07-04 10:02:00 +02:00
Iger
ad9c2d5411 - Test ECDSA fingerprints 2017-07-04 10:02:00 +02:00
Iger
ed65176b68 - Incorrect key format during write 2017-07-04 10:02:00 +02:00
Iger
28f3280a84 - license header 2017-07-04 10:02:00 +02:00
Iger
d69f722908 - Some more indentation fixes 2017-07-04 10:02:00 +02:00
Iger
1d7cb8c2c6 - Some more indentation fixes 2017-07-04 10:02:00 +02:00
Iger
6ad6242ed1 - Ident in spaces 2017-07-04 10:02:00 +02:00
Iger
3310530d42 - cleanup 2017-07-04 10:02:00 +02:00
Iger
3685f9dc36 - Formal generation of ASN.1 encoding for the ecdsa signature
- Support ecdsa-sha2-nistp521
2017-07-04 10:02:00 +02:00
Iger
f8cad120a6 - Pretty honed up implementation of -384 2017-07-04 10:02:00 +02:00
Iger
56dd4e4af4 - A separate enum members take with lots of code duplication 2017-07-04 10:02:00 +02:00
Jeroen van Erp
9f8cf1f298 Upgrade to gradle 4.0 2017-06-26 10:01:19 +02:00
Jeroen van Erp
a51270791d Remove deprecated ZLib usage 2017-06-26 09:56:37 +02:00
Jeroen van Erp
d43fc4551e Minor reformatting 2017-06-26 09:51:40 +02:00
Jan Peter Stotz
93bf6c0089 Fixed small exception logging problem 2017-06-09 11:58:24 +02:00
Jeroen van Erp
7b535a8db3 Added support for wildcard host entries in known_hosts (Fixes #331) 2017-05-22 14:43:30 +02:00
Jeroen van Erp
9d4f8fc46a Updated release notes 2017-04-25 15:32:44 +02:00
David Kocher
2b21ec6032 Fix regression from 40f956b. Invalid length parameter. (#322)
Also Fixes #306
2017-04-25 15:30:20 +02:00
Jeroen van Erp
8e15a8bd7d Updated README with release notes 2017-04-14 09:54:00 +02:00
Jeroen van Erp
531eb97767 Added log message for early identification termination 2017-04-14 09:14:52 +02:00
chqr
e36fd0fb3d Add support for authentication with DSA & RSA user certificates (#153) (#319)
* Add support for authentication with DSA & RSA user certificates (#153)

Updates:

- KeyType.java - add support for two certificate key types
    ssh-rsa-cert-v01@openssh.com
    ssh-dsa-cert-v01@openssh.com

- Buffer.java - allow uint64s that overflow Long.MAX_VALUE, otherwise
  we break on certificates with serial numbers greater Long.MAX_VALUE

- OpenSSHKeyFile, KeyProviderUtil - prefer public key files that end
  "-cert.pub" if they exist

Added new class Certificate, which represents certificate key

Reference:

https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD

* Use BigInteger for certificate serial numbers, address Codacy issues

* Address code review concerns
2017-04-14 08:49:16 +02:00
Jeroen van Erp
382321deca Updated README 2017-04-10 10:13:47 +02:00
Jeroen van Erp
7b75fb3d53 Upgraded Gradle to 3.4.1 2017-04-10 10:13:35 +02:00
Jeroen van Erp
4d84d3f67c Upgraded BouncyCastle (Fixes #312) 2017-04-10 10:08:09 +02:00
Jeroen van Erp
8eb7d1a2ad Update README to point to right repository (Fixes #309) 2017-03-23 14:05:32 +01:00
ISQ-GTT
a03fa9ac63 Added charset support, centralized UTF-8 usage (#305)
* Added charset support, centralized UTF-8 usage

* Code style, buffer methods with charsets

* assure remote charset isn't null
2017-03-09 13:58:51 +01:00
Jeroen van Erp
bcb15e6ccd Changed deprecated build notation 2017-03-01 21:53:42 +01:00
Jeroen van Erp
d85b22fe8d Upgrade to Gradle 3.4 2017-03-01 21:51:29 +01:00
Jeroen van Erp
f4b71941a3 Updated release notes for 0.20.0 2017-02-10 10:38:43 +01:00
Jeroen van Erp
636f896850 Cleaned up some code 2017-02-10 09:43:12 +01:00
Jeroen van Erp
56c0baf814 Merge pull request #301 from adagios/master
adds current version to exported classes
2017-02-06 10:16:45 +01:00
João Nelas
edfb069f2a adds current version to exported classes 2017-02-03 17:33:07 +00:00
Jeroen van Erp
65b3003e72 Merge pull request #295 from adagios/master
converts bouncycastle OSGi dep from Import-Bundle to Import-Package
2017-01-24 09:20:15 +01:00
Jeroen van Erp
fbee0b3956 Update build.gradle 2017-01-23 22:56:23 +01:00
Jeroen van Erp
fd60139b98 Merge branch 'master' into master 2017-01-23 22:54:15 +01:00
Jeroen van Erp
0b397bc3d7 Added TODO 2017-01-23 15:33:47 +01:00
Jeroen van Erp
40f956b4b6 More code cleanup 2017-01-23 15:33:22 +01:00
Jeroen van Erp
ef3f7a2eaf Fixed more warnings 2017-01-23 14:40:33 +01:00
Jeroen van Erp
8134113510 Cleaned up more PMD/Codacy warnings 2017-01-23 10:46:01 +01:00
Jeroen van Erp
c883c87963 Fixed a few warnings 2017-01-23 09:55:04 +01:00
Jeroen van Erp
920537dac9 More cleaning up 2017-01-20 16:41:16 +01:00
Jeroen van Erp
356ec9ed08 Upgraded to mina sshd 1.2.0 2017-01-20 16:30:01 +01:00
Jeroen van Erp
aa47b0c5f7 Cleaning up unused code 2017-01-20 16:29:37 +01:00
Jeroen van Erp
d3ed3cfe0f Merge pull request #296 from hierynomus/new-dhgroups
Added new DH groups
2017-01-20 16:17:06 +01:00
Jeroen van Erp
786734ce26 Suppressing Method naming conventions for Factory classes 2017-01-20 15:43:36 +01:00
Jeroen van Erp
9cb5bf4e10 Organized imports 2017-01-20 15:26:21 +01:00
Jeroen van Erp
0e3f7c2bbf Added new DH groups 2017-01-20 15:05:18 +01:00
João Nelas
66d4b34eba re-adding Export-Package of com.hierynomus.sshj.* 2017-01-12 14:37:02 +00:00
João Nelas
aafb9942a3 converts bouncycastle OSGi dep from Import-Bundle to Import-Package
Import-Bundle is generally discouraged by OSGi best practices.

See http://stackoverflow.com/questions/1865819/when-should-i-use-import-package-and-when-should-i-use-require-bundle for more info.
2017-01-12 14:26:59 +00:00
Jeroen van Erp
d1dff550ce Updated OSGi bundling (Fixes #255 again) 2017-01-11 23:14:43 +01:00
Jeroen van Erp
ac2720becd Added bettercodehub config 2017-01-10 17:45:37 +01:00
Jeroen van Erp
48dd1fdc41 Merge pull request #294 from joval/master
Reference the EdDSANamedCurveTable constant instead of its value...
2017-01-09 11:21:13 +01:00
Jeroen van Erp
9826a71d2b Merge pull request #293 from adagios/osgi-fix
excludes net.i2p.crypto.eddsa.math from OSGI Import-Package
2017-01-09 11:20:48 +01:00
David A. Solin
936eb26e9e Reference the EdDSANamedCurveTable constant instead of its value, for forward-compatibility with the ed25519-java project on Github.
See: abdee146c3
2017-01-06 12:58:04 -06:00
João Nelas
9438157b93 excludes net.i2p.crypto.eddsa.math from OSGI Import-Package 2017-01-06 15:12:44 +00:00
Jeroen van Erp
7d326e5ae4 Updated example build 2016-12-30 09:26:43 +01:00
Jeroen van Erp
f038b5ce2b Updated Release notes 2016-12-30 09:26:00 +01:00
Jeroen van Erp
20879a4aa5 LocalPortForwarder interrupts its thread on close() 2016-12-29 16:06:57 +01:00
Jeroen van Erp
516abb0282 Disable version inference when no git history present (Fixes #256) 2016-12-28 10:09:48 +01:00
Jeroen van Erp
0ad51709c2 Use the configured Random factory in DH KEX (Fixes #292) 2016-12-28 10:00:24 +01:00
Jeroen van Erp
c9c68f019e StreamCipher can use the constructor without random. 2016-12-28 09:52:58 +01:00
Jeroen van Erp
fc75f9796c Added logging to trace time creation of Randoms 2016-12-28 09:52:20 +01:00
Jeroen van Erp
61af500c3e Added 'classes' directory to ignore 2016-12-28 09:51:03 +01:00
Jeroen van Erp
56553ea086 Prepared release notes 2016-12-23 11:58:49 +01:00
Jeroen van Erp
86e6631b1e Enabled PKCS5 in DefaultConfig 2016-12-23 11:54:43 +01:00
Jeroen van Erp
b6f437a932 Merge pull request #291 from joval/master
Two minor changes
2016-12-21 21:51:23 +01:00
David Solin
9e3b9f7c24 Obtain the sshj.properties resource from the ClassLoader that loaded the DefaultConfig class, not from the context classloader. 2016-12-21 10:04:56 -06:00
David Solin
766ab916ee Use cause message when initializing an SSHRuntimeException from a Throwable. 2016-12-21 07:48:02 -06:00
Jeroen van Erp
cdca43a848 Merge pull request #284 from gatesking/patch-1
Catch interrupt signal in keepalive thread
2016-11-30 09:42:29 +01:00
gatesking
3ce7c2ebfb Catch interrupt signal in keepalive thread
Interrupt signal may be catched when keepalive thread is sleeping. As a result, it will still go into conn.getTransport().die(e).
2016-11-30 09:30:57 +08:00
Jeroen van Erp
ca4e0bf2d7 Update README.adoc 2016-11-25 13:27:20 +01:00
Jeroen van Erp
2ca2bbd633 Prepared for next release 2016-11-25 13:14:48 +01:00
Jeroen van Erp
256e65dea4 Build jar with correct version string automatically (Fixes #280) 2016-11-23 13:30:37 +01:00
Jeroen van Erp
1feb7fe9a6 Update README.adoc 2016-10-31 09:57:12 +01:00
Jeroen van Erp
d95b4db930 Merge pull request #279 from hierynomus/issue-276
Support for OpenSSH new key file format (fixes #276)
2016-10-31 09:55:47 +01:00
Jeroen van Erp
677f482a69 Fixed text 2016-10-28 16:31:23 +02:00
Jeroen van Erp
179b30ef4e Fixed some codacy warnings 2016-10-28 14:50:37 +02:00
Jeroen van Erp
f59bbccc5f Fixed ed-25519 and openssh-key-v1 formats 2016-10-28 14:45:16 +02:00
Jeroen van Erp
bf34072c3a Reading first part of the new openssh key format 2016-10-24 09:49:45 +02:00
Jeroen van Erp
771751ca4c Fixed license header 2016-10-19 14:48:06 +01:00
Jeroen van Erp
968d4284a0 Extracted common key file methods into an abstract base class 2016-10-19 12:08:51 +01:00
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
338 changed files with 14862 additions and 4266 deletions

8
.bettercodehub.yml Normal file
View File

@@ -0,0 +1,8 @@
exclude:
- /build-publishing.gradle
- /build.gradle
- /settings.gradle
component_depth: 1
languages:
- groovy
- java

2
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,2 @@
* @hierynomus

55
.github/workflows/gradle.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Build SSHJ
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
java12:
name: Build with Java 12
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 12
uses: actions/setup-java@v1
with:
java-version: 12
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew check
# java10:
# name: Build with Java 10
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - name: Set up JDK 10
# uses: actions/setup-java@v1
# with:
# java-version: 10
# - name: Grant execute permission for gradlew
# run: chmod +x gradlew
# - name: Build with Gradle
# run: ./gradlew check -xanimalsnifferMain -xanimalsnifferTest
integration:
name: Integration test
needs: [java12]
runs-on: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- uses: actions/setup-java@v1
with:
java-version: 12
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew integrationTest

9
.gitignore vendored
View File

@@ -10,8 +10,17 @@
.settings/
# Output dirs
out/
target/
classes/
bin/
build/
docs/
.gradle/
sshj.jar
# MacOS X
.DS_Store
# VSCode
.metals/

1
.java-version Normal file
View File

@@ -0,0 +1 @@
11.0

View File

@@ -1,2 +0,0 @@
language: java
sudo: false

6
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"java.checkstyle.configuration": "${workspaceFolder}/gradle/config/checkstyle/checkstyle.xml",
"files.watcherExclude": {
"**/target": true
}
}

2
NOTICE
View File

@@ -15,7 +15,7 @@ The Apache Software Foundation (http://www.apache.org/):
== in this case for the SSHD distribution. ==
=========================================================================
This product contains software developped by JCraft,Inc. and subject to
This product contains software developed by JCraft,Inc. and subject to
the following license:
Copyright (c) 2002,2003,2004,2005,2006,2007,2008 Atsuhiko Yamanaka, JCraft,Inc.

View File

@@ -1,10 +1,15 @@
= sshj - SSHv2 library for Java
Jeroen van Erp
:sshj_groupid: com.hierynomus
:sshj_version: 0.15.0
:sshj_version: 0.31.0
:source-highlighter: pygments
image::https://travis-ci.org/hierynomus/sshj.svg?branch=master[]
image:https://api.bintray.com/packages/hierynomus/maven/sshj/images/download.svg[link="https://bintray.com/hierynomus/maven/sshj/_latestVersion"]
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://codecov.io/gh/hierynomus/sshj/branch/master/graph/badge.svg["codecov", link="https://codecov.io/gh/hierynomus/sshj"]
image:http://www.javadoc.io/badge/com.hierynomus/sshj.svg?color=blue["JavaDocs", link="http://www.javadoc.io/doc/com.hierynomus/sshj"]
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"]
To get started, have a look at one of the examples. Hopefully you will find the API pleasant to work with :)
@@ -34,7 +39,7 @@ If you're building your project using Maven, you can add the following dependenc
If your project is built using another build tool that uses the Maven Central repository, translate this dependency into the format used by your build tool.
== Building SSHJ
. Clone the Overthere repository.
. Clone the SSHJ repository.
. Ensure you have Java6 installed with the http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html[Unlimited strength Java Cryptography Extensions (JCE)].
. Run the command `./gradlew clean build`.
@@ -59,24 +64,31 @@ 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,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}`
`aes{128,192,256}-{cbc,ctr}`, `aes{128,256}-gcm@openssh.com`, `blowfish-{cbc,ctr}`, `3des-{cbc,ctr}`, `twofish{128,192,256}-{cbc,ctr}`, `twofish-cbc`, `serpent{128,192,256}-{cbc,ctr}`, `idea-{cbc,ctr}`, `cast128-{cbc,ctr}`, `arcfour`, `arcfour{128,256}`
SSHJ also supports the following extended (non official) ciphers: `camellia{128,192,256}-{cbc,ctr}`, `camellia{128,192,256}-{cbc,ctr}@openssh.org`
key exchange::
`diffie-hellman-group1-sha1`, `diffie-hellman-group14-sha1`, `diffie-hellman-group-exchange-sha1`, `diffie-hellman-group-exchange-sha256`,
`diffie-hellman-group1-sha1`, `diffie-hellman-group14-sha1`,
`diffie-hellman-group14-sha256`, `diffie-hellman-group15-sha512`, `diffie-hellman-group16-sha512`, `diffie-hellman-group17-sha512`, `diffie-hellman-group18-sha512`
`diffie-hellman-group-exchange-sha1`, `diffie-hellman-group-exchange-sha256`,
`ecdh-sha2-nistp256`, `ecdh-sha2-nistp384`, `ecdh-sha2-nistp521`, `curve25519-sha256@libssh.org`
SSHJ also supports the following extended (non official) key exchange algorithms:
`diffie-hellman-group14-sha256@ssh.com`, `diffie-hellman-group15-sha256`, `diffie-hellman-group15-sha256@ssh.com`, `diffie-hellman-group15-sha384@ssh.com`,
`diffie-hellman-group16-sha256`, `diffie-hellman-group16-sha384@ssh.com`, `diffie-hellman-group16-sha512@ssh.com`, `diffie-hellman-group18-sha512@ssh.com`
signatures::
`ssh-rsa`, `ssh-dss`, `ecdsa-sha2-nistp256`, `ssh-ed25519`
`ssh-rsa`, `ssh-dss`, `ecdsa-sha2-nistp256`, `ecdsa-sha2-nistp384`, `ecdsa-sha2-nistp521`, `ssh-ed25519`, `ssh-rsa2-256`, `ssh-rsa2-512`
mac::
`hmac-md5`, `hmac-md5-96`, `hmac-sha1`, `hmac-sha1-96`, `hmac-sha2-256`, `hmac-sha2-512`
`hmac-md5`, `hmac-md5-96`, `hmac-sha1`, `hmac-sha1-96`, `hmac-sha2-256`, `hmac-sha2-512`, `hmac-ripemd160`, `hmac-ripemd160@openssh.com`
`hmac-md5-etm@openssh.com`, `hmac-md5-96-etm@openssh.com`, `hmac-sha1-etm@openssh.com`, `hmac-sha1-96-etm@openssh.com`, `hmac-sha2-256-etm@openssh.com`, `hmac-sha2-512-etm@openssh.com`, `hmac-ripemd160-etm@openssh.com`
compression::
`zlib` and `zlib@openssh.com` (delayed zlib)
private key files::
`pkcs8` encoded (what openssh uses)
`pkcs5`, `pkcs8`, `openssh-key-v1`, `ssh-rsa-cert-v01@openssh.com`, `ssh-dsa-cert-v01@openssh.com`
If you need something that is not included, it shouldn't be too hard to add (do contribute it!)
@@ -89,14 +101,110 @@ Java 6+. http://www.slf4j.org/download.html[slf4j] is required. http://www.bounc
== Reporting bugs
Issue tracker: https://github.com/hierynomus/sshj/issues
== Discussion
Google Group: http://groups.google.com/group/sshj-users
== Contributing
Fork away!
== Release history
SSHJ 0.16.0 (2016-??-??)::
SSHJ 0.31.0 (2021-02-08)::
* Bump dependencies (asn-one 0.5.0, BouncyCastle 1.68, slf4j-api 1.7.30)
* Merged https://github.com/hierynomus/sshj/pull/660[#660]: Support ED25519 and ECDSA keys in PuTTY format
* Merged https://github.com/hierynomus/sshj/pull/655[#655]: Bump BouncyCastle due to CVE
* Merged https://github.com/hierynomus/sshj/pull/653[#653]: Make Parameters class useable as HashMap key
* Merged https://github.com/hierynomus/sshj/pull/647[#647]: Reduce log level for identification parser
* Merged https://github.com/hierynomus/sshj/pull/630[#630]: Add support for `aes128-gcm@openssh.com` and `aes256-gcm@openssh.com` ciphers
* Merged https://github.com/hierynomus/sshj/pull/636[#636]: Improved Android compatibility
* Merged https://github.com/hierynomus/sshj/pull/627[#627]: Prevent key leakage
SSHJ 0.30.0 (2020-08-17)::
* **BREAKING CHANGE**: Removed `setSignatureFactories` and `getSignatureFactories` from the Config and switched them for `getKeyAlgorithms` and `setKeyAlgorithms`
* Fixed https://github.com/hierynomus/sshj/pull/588[#588]: Add support for `ssh-rsa2-256` and `ssh-rsa2-512` signatures
* Merged https://github.com/hierynomus/sshj/pull/579[#579]: Fix NPE in OpenSSHKnownHosts
* Merged https://github.com/hierynomus/sshj/pull/587[#587]: Add passwordfinder retry for OpenSSHKeyV1KeyFile
* Merged https://github.com/hierynomus/sshj/pull/586[#586]: Make KeyType compatible with Android Store
* Merged https://github.com/hierynomus/sshj/pull/593[#593]: Change `UserAuth.getAllowedMethods()` to Collection return type
* Merged https://github.com/hierynomus/sshj/pull/595[#595]: Allow reading arbitrary length keys
* Merged https://github.com/hierynomus/sshj/pull/591[#591]: Allow to query SFTP extensions
* Merged https://github.com/hierynomus/sshj/pull/603[#603]: Add method to create Stateful SFTP client
* Merged https://github.com/hierynomus/sshj/pull/605[#605]: Use Daemon threads to avoid blocking JVM shutdown
* Merged https://github.com/hierynomus/sshj/pull/606[#606]: Always use the JCERandom RNG by default
* Merged https://github.com/hierynomus/sshj/pull/609[#609]: Clear passphrase after use to prevent security issues
* Merged https://github.com/hierynomus/sshj/pull/618[#618]: Fix localport of DirectConnection for use with OpenSSH > 8.0
* Merged https://github.com/hierynomus/sshj/pull/619[#619]: Upgraded BouncyCastle to 1.66
* Merged https://github.com/hierynomus/sshj/pull/622[#622]: Send 'ext-info-c' with KEX algorithms
* Merged https://github.com/hierynomus/sshj/pull/623[#623]: Fix transport encoding of `nistp521` signatures
* Merged https://github.com/hierynomus/sshj/pull/607[#607]: Fix mathing pubkeys to key algorithms
* Merged https://github.com/hierynomus/sshj/pull/602[#602]: Fix RSA certificate key determination
SSHJ 0.27.0 (2019-01-24)::
* Fixed https://github.com/hierynomus/sshj/issues/415[#415]: Fixed wrongly prefixed '/' to path in SFTPClient.mkdirs
* Added support for ETM (Encrypt-then-Mac) MAC algorithms.
* Fixed https://github.com/hierynomus/sshj/issues/454[#454]: Added missing capacity check for Buffer.putUint64
* Fixed https://github.com/hierynomus/sshj/issues/466[#466]: Added lock timeout for remote action to prevent hanging
* Fixed https://github.com/hierynomus/sshj/issues/470[#470]: Made EdDSA the default (first) signature factory
* Fixed https://github.com/hierynomus/sshj/issues/467[#467]: Added AES256-CBC as cipher mode in openssh-key-v1 support
* Fixed https://github.com/hierynomus/sshj/issues/464[#464]: Enabled curve25519-sha256@openssh.org in DefaultConfig
* Fixed https://github.com/hierynomus/sshj/issues/472[#472]: Handle server initiated global requests
* Fixed https://github.com/hierynomus/sshj/issues/485[#485]: Added support for all keytypes to openssh-key-v1 keyfiles.
SSHJ 0.26.0 (2018-07-24)::
* Fixed https://github.com/hierynomus/sshj/issues/413[#413]: Use UTF-8 for PrivateKeyFileResource
* Fixed https://github.com/hierynomus/sshj/issues/427[#427]: Support encrypted ed25519 openssh-key-v1 files
* Upgraded BouncyCastle to 1.60
* Added support for hmac-ripemd160@openssh.com MAC
SSHJ 0.24.0 (2018-04-04)::
* Added support for hmac-ripemd160
* Fixed https://github.com/hierynomus/sshj/issues/382[#382]: Fixed escaping in WildcardHostmatcher
* Added integration testsuite using Docker against OpenSSH
* Fixed https://github.com/hierynomus/sshj/issues/187[#187]: Fixed length bug in Buffer.putString
* Fixed https://github.com/hierynomus/sshj/issues/405[#405]: Continue host verification if first hostkey does not match.
SSHJ 0.23.0 (2017-10-13)::
* Merged https://github.com/hierynomus/sshj/pull/372[#372]: Upgrade to 'net.i2p.crypto:eddsa:0.2.0'
* Fixed https://github.com/hierynomus/sshj/issues/355[#355] and https://github.com/hierynomus/sshj/issues/354[#354]: Correctly decode signature bytes
* Fixed https://github.com/hierynomus/sshj/issues/365[#365]: Added support for new-style OpenSSH fingerprints of server keys
* Fixed https://github.com/hierynomus/sshj/issues/356[#356]: Fixed key type detection for ECDSA public keys
* Made SSHJ Java9 compatible
SSHJ 0.22.0 (2017-08-24)::
* Fixed https://github.com/hierynomus/sshj/pull/341[#341]: Fixed path walking during recursive copy
* Merged https://github.com/hierynomus/sshj/pull/338[#338]: Added ConsolePasswordFinder to read password from stdin
* Merged https://github.com/hierynomus/sshj/pull/336[#336]: Added support for ecdsa-sha2-nistp384 and ecdsa-sha2-nistp521 signatures
* Fixed https://github.com/hierynomus/sshj/issues/331[#331]: Added support for wildcards in known_hosts file
SSHJ 0.21.1 (2017-04-25)::
* Merged https://github.com/hierynomus/sshj/pull/322[#322]: Fix regression from 40f956b (invalid length parameter on outputstream)
SSHJ 0.21.0 (2017-04-14)::
* Merged https://github.com/hierynomus/sshj/pull/319[#319]: Added support for `ssh-rsa-cert-v01@openssh.com` and `ssh-dsa-cert-v01@openssh.com` certificate key files
* Upgraded Gradle to 3.4.1
* Merged https://github.com/hierynomus/sshj/pull/305[#305]: Added support for custom string encoding
* Fixed https://github.com/hierynomus/sshj/issues/312[#312]: Upgraded BouncyCastle to 1.56
SSHJ 0.20.0 (2017-02-09)::
* Merged https://github.com/hierynomus/sshj/pull/294[#294]: Reference ED25519 by constant instead of name
* Merged https://github.com/hierynomus/sshj/pull/293[#293], https://github.com/hierynomus/sshj/pull/295[#295] and https://github.com/hierynomus/sshj/pull/301[#301]: Fixed OSGi packaging
* Added new Diffie Hellman groups 15-18 for stronger KeyExchange algorithms
SSHJ 0.19.1 (2016-12-30)::
* Enabled PKCS5 Key files in DefaultConfig
* Merged https://github.com/hierynomus/sshj/pull/291[#291]: Fixed sshj.properties loading and chained exception messages
* Merged https://github.com/hierynomus/sshj/pull/284[#284]: Correctly catch interrupt in keepalive thread
* Fixed https://github.com/hierynomus/sshj/issues/292[#292]: Pass the configured RandomFactory to Diffie Hellman KEX
* Fixed https://github.com/hierynomus/sshj/issues/256[#256]: SSHJ now builds if no git repository present
* LocalPortForwarder now correctly interrupts its own thread on close()
SSHJ 0.19.0 (2016-11-25)::
* Fixed https://github.com/hierynomus/sshj/issues/276[#276]: Add support for ed-25519 and new OpenSSH key format
* Fixed https://github.com/hierynomus/sshj/issues/280[#280]: Read version from a generated sshj.properties file to correctly output version during negotiation
SSHJ 0.18.0 (2016-09-30)::
* Fixed Android compatibility
* Upgrade to Gradle 3.0
* Merged https://github.com/hierynomus/sshj/pull/271[#271]: Load known_hosts without requiring BouncyCastle
* Merged https://github.com/hierynomus/sshj/pull/269[#269]: Brought back Java6 support by popular demand
* Merged https://github.com/hierynomus/sshj/pull/267[#267]: Added support for per connection logging (Fixes https://github.com/hierynomus/sshj/issues/264[#264])
* Merged https://github.com/hierynomus/sshj/pull/262[#262], https://github.com/hierynomus/sshj/pull/265[#265] and https://github.com/hierynomus/sshj/pull/266[#266]: Added PKCS5 key file support
* Fixed toString of sftp FileAttributes (Fixes https://github.com/hierynomus/sshj/pull/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/pull/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

View File

@@ -17,7 +17,7 @@ configurations {
pom
}
def bouncycastleVersion = "1.50"
def bouncycastleVersion = "1.67"
dependencies {
compile "org.slf4j:slf4j-api:1.7.7"

View File

@@ -1,198 +1,294 @@
import java.text.SimpleDateFormat
import com.bmuschko.gradle.docker.tasks.container.*
import com.bmuschko.gradle.docker.tasks.image.*
plugins {
id "java"
id "maven"
id "idea"
id "signing"
id "osgi"
id "org.ajoberstar.release-opinion" version "1.4.0-rc.1"
id "com.github.hierynomus.license" version "0.12.1"
id "java"
id "groovy"
id "jacoco"
id "com.github.blindpirate.osgi" version '0.0.3'
id "maven-publish"
id 'pl.allegro.tech.build.axion-release' version '1.11.0'
id "com.bmuschko.docker-remote-api" version "6.4.0"
id "com.github.hierynomus.license" version "0.12.1"
id "com.jfrog.bintray" version "1.8.5"
id 'ru.vyarus.java-lib' version '1.0.5'
// id 'ru.vyarus.pom' version '1.0.3'
id 'ru.vyarus.github-info' version '1.1.0'
}
group = "com.hierynomus"
repositories {
mavenCentral()
scmVersion {
tag {
prefix = 'v'
versionSeparator = ''
}
hooks {
pre 'fileUpdate', [file: 'README.adoc', pattern: { v, c -> /:sshj_version: .*/}, replacement: { v, c -> ":sshj_version: $v" }]
pre 'commit'
}
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
project.version = scmVersion.version
defaultTasks "build"
repositories {
mavenCentral()
}
configurations.compile.transitive = false
idea {
module {
downloadJavadoc = true
downloadSources = true
}
def bouncycastleVersion = "1.68"
def sshdVersion = "2.1.0"
dependencies {
implementation "org.slf4j:slf4j-api:1.7.30"
implementation "org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion"
implementation "org.bouncycastle:bcpkix-jdk15on:$bouncycastleVersion"
implementation "com.jcraft:jzlib:1.1.3"
implementation "com.hierynomus:asn-one:0.5.0"
implementation "net.i2p.crypto:eddsa:0.3.0"
testImplementation "junit:junit:4.12"
testImplementation 'org.spockframework:spock-core:1.3-groovy-2.4'
testImplementation "org.mockito:mockito-core:2.28.2"
testImplementation "org.apache.sshd:sshd-core:$sshdVersion"
testImplementation "org.apache.sshd:sshd-sftp:$sshdVersion"
testImplementation "org.apache.sshd:sshd-scp:$sshdVersion"
testRuntimeOnly "ch.qos.logback:logback-classic:1.2.3"
testImplementation 'org.glassfish.grizzly:grizzly-http-server:2.4.4'
testImplementation 'org.apache.httpcomponents:httpclient:4.5.9'
}
license {
mapping {
java = 'SLASHSTAR_STYLE'
}
header rootProject.file('LICENSE_HEADER')
strictCheck true
header rootProject.file('LICENSE_HEADER')
strictCheck true
mapping {
java = 'SLASHSTAR_STYLE'
}
excludes(['**/djb/Curve25519.java', '**/sshj/common/Base64.java', '**/org/mindrot/jbcrypt/*.java'])
}
release {
grgit = org.ajoberstar.grgit.Grgit.open(project.projectDir)
}
test {
testLogging {
exceptionFormat = 'full'
}
include "**/*Test.*"
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")
}
}
}
def bouncycastleVersion = "1.51"
dependencies {
compile "org.slf4j:slf4j-api:1.7.7"
compile "org.bouncycastle:bcprov-jdk15on:$bouncycastleVersion"
compile "org.bouncycastle:bcpkix-jdk15on:$bouncycastleVersion"
compile "com.jcraft:jzlib:1.1.3"
compile "net.vrallev.ecc:ecc-25519-java:1.0.1"
testCompile "junit:junit:4.11"
testCompile "org.mockito:mockito-core:1.9.5"
testCompile "org.apache.sshd:sshd-core:1.1.0"
testRuntime "ch.qos.logback:logback-classic:1.1.2"
testCompile 'org.glassfish.grizzly:grizzly-http-server:2.3.17'
testCompile 'org.apache.httpcomponents:httpclient:4.5.2'
}
jar {
manifest {
instruction "Bundle-Description", "SSHv2 library for Java"
instruction "Bundle-License", "http://www.apache.org/licenses/LICENSE-2.0.txt"
instruction "Import-Package", "!net.schmizz.*"
instruction "Import-Package", "javax.crypto*"
instruction "Import-Package", "net.i2p*"
instruction "Import-Package", "com.jcraft.jzlib*;version=\"[1.1,2)\";resolution:=optional"
instruction "Import-Package", "org.slf4j*;version=\"[1.7,5)\""
instruction "Import-Package", "org.bouncycastle*"
instruction "Import-Package", "*"
instruction "Export-Package", "net.schmizz.*"
}
}
task javadocJar(type: Jar) {
classifier = 'javadoc'
from javadoc
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
manifest = project.tasks.jar.manifest
}
artifacts {
archives javadocJar, sourcesJar
}
signing {
required { !version.toString().contains("SNAPSHOT") && gradle.taskGraph.hasTask("uploadArchives") }
sign configurations.archives
if (!JavaVersion.current().isJava9Compatible()) {
throw new GradleScriptException("Minimum compilation version is Java 9")
}
// This disables the pedantic doclint feature of JDK8
if (JavaVersion.current().isJava8Compatible()) {
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
}
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
}
}
uploadArchives {
if (project.hasProperty('sonatypeUsername')) {
repositories.mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
configuration = configurations.archives
compileJava {
options.compilerArgs.addAll(['--release', '7'])
}
repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2') {
authentication(userName: sonatypeUsername, password: sonatypePassword)
}
snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/') {
authentication(userName: sonatypeUsername, password: sonatypePassword)
}
task writeSshjVersionProperties {
doLast {
project.file("${project.buildDir}/resources/main").mkdirs()
project.file("${project.buildDir}/resources/main/sshj.properties").withWriter { w ->
w.append("sshj.version=${version}")
}
}
}
pom.project {
name "sshj"
description "SSHv2 library for Java"
url "https://github.com/hierynomus/sshj"
inceptionYear "2009"
jar.dependsOn writeSshjVersionProperties
jar {
manifest {
// please see http://bnd.bndtools.org/chapters/390-wrapping.html
instruction "Bundle-Description", "SSHv2 library for Java"
instruction "Bundle-License", "http://www.apache.org/licenses/LICENSE-2.0.txt"
instruction "Import-Package", "!net.schmizz.*"
instruction "Import-Package", "!com.hierynomus.sshj.*"
instruction "Import-Package", "javax.crypto*"
instruction "Import-Package", "!net.i2p.crypto.eddsa.math"
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*;resolution:=optional"
instruction "Import-Package", "org.bouncycastle.jce.provider;resolution:=optional"
instruction "Import-Package", "*"
instruction "Export-Package", "com.hierynomus.sshj.*;version=\"${project.jar.manifest.version}\""
instruction "Export-Package", "net.schmizz.*;version=\"${project.jar.manifest.version}\""
}
}
issueManagement {
system "github"
url "https://github.com/hierynomus/sshj/issues"
}
sourcesJar {
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"
)
}
}
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"
}
configurations {
integrationTestImplementation.extendsFrom testImplementation
integrationTestRuntimeOnly.extendsFrom testRuntimeOnly
}
licenses {
license {
name "Apache 2"
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
distribution "repo"
}
}
sourceSets {
integrationTest {
groovy {
compileClasspath += sourceSets.main.output + sourceSets.test.output
runtimeClasspath += sourceSets.main.output + sourceSets.test.output
srcDir file('src/itest/groovy')
}
resources.srcDir file('src/itest/resources')
}
}
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"
}
}
}
}
task integrationTest(type: Test) {
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
}
tasks.withType(Test) {
testLogging {
exceptionFormat = 'full'
}
include "**/*Test.*"
include "**/*Spec.*"
if (!project.hasProperty("allTests")) {
useJUnit {
excludeCategories 'com.hierynomus.sshj.test.SlowTests'
excludeCategories 'com.hierynomus.sshj.test.KnownFailingTests'
}
}
afterSuite { descriptor, result ->
if (descriptor.className != null) {
def indicator = "\u001B[32m✓\u001b[0m"
if (result.failedTestCount > 0) {
indicator = "\u001B[31m✘\u001b[0m"
}
logger.lifecycle("$indicator Test ${descriptor.name}; Executed: ${result.testCount}/\u001B[32m${result.successfulTestCount}\u001B[0m/\u001B[31m${result.failedTestCount}\u001B[0m")
}
}
}
project.tasks.compileGroovy.onlyIf { false }
github {
user 'hierynomus'
license 'Apache'
}
pom {
description "SSHv2 library for Java"
url "https://github.com/hierynomus/sshj"
inceptionYear "2009"
developers {
developer {
id "hierynomus"
name "Jeroen van Erp"
email "jeroen@javadude.nl"
roles {
role "Lead developer"
}
}
developer {
id "shikhar"
name "Shikhar Bhushan"
email "shikhar@schmizz.net"
url "http://schmizz.net"
roles {
role "Previous lead developer"
}
}
developer {
id "iterate"
name "David Kocher"
email "dkocher@iterate.ch"
organization "iterage GmbH"
organizationUrl "https://iterate.ch"
roles {
role "Developer"
}
}
}
}
if (project.hasProperty("bintrayUsername") && project.hasProperty("bintrayApiKey")) {
bintray {
user = project.property("bintrayUsername")
key = project.property("bintrayApiKey")
publish = true
publications = ["maven"]
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}"
vcsTag = "v${project.version}"
released = new SimpleDateFormat('yyyy-MM-dd\'T\'HH:mm:ss.SSSZZ').format(new Date())
gpg {
sign = true
passphrase = project.property("signing.password")
}
mavenCentralSync {
sync = true
user = project.property("sonatypeUsername")
password = project.property("sonatypePassword")
close = 1
}
}
}
}
}
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
}
}
tasks.release.dependsOn 'build', 'uploadArchives'
task buildItestImage(type: DockerBuildImage) {
inputDir = file('src/itest/docker-image')
images.add('sshj/sshd-itest:latest')
}
task createItestContainer(type: DockerCreateContainer) {
dependsOn buildItestImage
targetImageId buildItestImage.getImageId()
hostConfig.portBindings = ['2222:22']
hostConfig.autoRemove = true
}
task startItestContainer(type: DockerStartContainer) {
dependsOn createItestContainer
targetContainerId createItestContainer.getContainerId()
}
task stopItestContainer(type: DockerStopContainer) {
targetContainerId createItestContainer.getContainerId()
}
task forkedUploadRelease(type: GradleBuild) {
buildFile = project.buildFile
tasks = ["bintrayUpload"]
}
project.tasks.integrationTest.dependsOn(startItestContainer)
project.tasks.integrationTest.finalizedBy(stopItestContainer)
project.tasks.release.dependsOn([project.tasks.integrationTest, project.tasks.build])
project.tasks.release.finalizedBy(project.tasks.forkedUploadRelease)
project.tasks.jacocoTestReport.dependsOn(project.tasks.test)
project.tasks.check.dependsOn(project.tasks.jacocoTestReport)

View File

@@ -24,7 +24,7 @@
<groupId>com.hierynomus</groupId>
<artifactId>sshj-examples</artifactId>
<packaging>jar</packaging>
<version>0.14.0</version>
<version>0.19.1</version>
<name>sshj-examples</name>
<description>Examples for SSHv2 library for Java</description>
@@ -55,7 +55,7 @@
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
<version>0.15.0</version>
<version>0.31.0</version>
</dependency>
</dependencies>

View File

@@ -5,30 +5,36 @@ import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import java.io.Console;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/** This examples demonstrates how a remote command can be executed. */
public class Exec {
private static final Console con = System.console();
public static void main(String... args)
throws IOException {
final SSHClient ssh = new SSHClient();
ssh.loadKnownHosts();
ssh.connect("localhost");
Session session = null;
try {
ssh.authPublickey(System.getProperty("user.name"));
final Session session = ssh.startSession();
try {
final Command cmd = session.exec("ping -c 1 google.com");
System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
cmd.join(5, TimeUnit.SECONDS);
System.out.println("\n** exit status: " + cmd.getExitStatus());
} finally {
session.close();
}
session = ssh.startSession();
final Command cmd = session.exec("ping -c 1 google.com");
con.writer().print(IOUtils.readFully(cmd.getInputStream()).toString());
cmd.join(5, TimeUnit.SECONDS);
con.writer().print("\n** exit status: " + cmd.getExitStatus());
} finally {
try {
if (session != null) {
session.close();
}
} catch (IOException e) {
// Do Nothing
}
ssh.disconnect();
}
}

View File

@@ -0,0 +1,31 @@
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.KeyType;
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
import net.schmizz.sshj.xfer.FileSystemFile;
import java.io.*;
import java.nio.charset.Charset;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
/** This examples demonstrates how to configure {@link net.schmizz.sshj.SSHClient} client with an in-memory known_hosts file */
public class InMemoryKnownHosts {
public static void main(String[] args) throws IOException {
InputStream entry = new ByteArrayInputStream("localhost ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPmhSBtMctNa4hsZt8QGlsYSE5/gMkjeand69Vj4ir13".getBytes(Charset.defaultCharset()));
SSHClient ssh = new SSHClient();
ssh.addHostKeyVerifier(new OpenSSHKnownHosts(new InputStreamReader(entry, Charset.defaultCharset())));
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
ssh.newSCPFileTransfer().download("test_file", new FileSystemFile("/tmp/"));
} finally {
ssh.disconnect();
}
}
}

View File

@@ -0,0 +1,50 @@
package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.connection.channel.direct.DirectConnection;
import net.schmizz.sshj.connection.channel.direct.Session;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* This example demonstrates connecting via an intermediate "jump" server using a direct TCP/IP channel.
*/
public class Jump {
public static void main(String... args)
throws IOException {
SSHClient firstHop = new SSHClient();
firstHop.loadKnownHosts();
firstHop.connect("localhost");
try {
firstHop.authPublickey(System.getProperty("user.name"));
DirectConnection tunnel = firstHop.newDirectConnection("localhost", 22);
SSHClient ssh = new SSHClient();
try {
ssh.loadKnownHosts();
ssh.connectVia(tunnel);
ssh.authPublickey(System.getProperty("user.name"));
final Session session = ssh.startSession();
try {
final Session.Command cmd = session.exec("ping -c 1 google.com");
System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
cmd.join(5, TimeUnit.SECONDS);
System.out.println("\n** exit status: " + cmd.getExitStatus());
} finally {
session.close();
}
} finally {
ssh.disconnect();
}
} finally {
firstHop.disconnect();
}
}
}

View File

@@ -3,14 +3,11 @@ package net.schmizz.sshj.examples;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.DefaultConfig;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** This examples demonstrates how to setup keep-alive to detect connection dropping. */
public class KeepAlive {

View File

@@ -2,6 +2,7 @@ package net.schmizz.sshj.examples;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.LocalPortForwarder;
import net.schmizz.sshj.connection.channel.direct.Parameters;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -28,8 +29,8 @@ public class LocalPF {
* _We_ listen on localhost:8080 and forward all connections on to server, which then forwards it to
* google.com:80
*/
final LocalPortForwarder.Parameters params
= new LocalPortForwarder.Parameters("0.0.0.0", 8080, "google.com", 80);
final Parameters params
= new Parameters("0.0.0.0", 8080, "google.com", 80);
final ServerSocket ss = new ServerSocket();
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress(params.getLocalHost(), params.getLocalPort()));

View File

@@ -9,6 +9,7 @@ import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
import java.io.File;
import java.io.IOException;
import net.schmizz.sshj.common.LoggerFactory;
/** A very rudimentary psuedo-terminal based on console I/O. */
class RudimentaryPTY {
@@ -33,18 +34,18 @@ class RudimentaryPTY {
final Shell shell = session.startShell();
new StreamCopier(shell.getInputStream(), System.out)
new StreamCopier(shell.getInputStream(), System.out, LoggerFactory.DEFAULT)
.bufSize(shell.getLocalMaxPacketSize())
.spawn("stdout");
new StreamCopier(shell.getErrorStream(), System.err)
new StreamCopier(shell.getErrorStream(), System.err, LoggerFactory.DEFAULT)
.bufSize(shell.getLocalMaxPacketSize())
.spawn("stderr");
// Now make System.in act as stdin. To exit, hit Ctrl+D (since that results in an EOF on System.in)
// This is kinda messy because java only allows console input after you hit return
// But this is just an example... a GUI app could implement a proper PTY
new StreamCopier(System.in, shell.getOutputStream())
new StreamCopier(System.in, shell.getOutputStream(), LoggerFactory.DEFAULT)
.bufSize(shell.getRemoteMaxPacketSize())
.copy();

View File

@@ -5,6 +5,7 @@ import net.schmizz.sshj.common.StreamCopier;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.connection.channel.forwarded.SocketForwardingConnectListener;
import net.schmizz.sshj.common.LoggerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -42,8 +43,8 @@ public class X11 {
final Command cmd = sess.exec("/usr/X11/bin/xcalc");
new StreamCopier(cmd.getInputStream(), System.out).spawn("stdout");
new StreamCopier(cmd.getErrorStream(), System.err).spawn("stderr");
new StreamCopier(cmd.getInputStream(), System.out, LoggerFactory.DEFAULT).spawn("stdout");
new StreamCopier(cmd.getErrorStream(), System.err, LoggerFactory.DEFAULT).spawn("stderr");
// Wait for session & X11 channel to get closed
ssh.getConnection().join();

Binary file not shown.

View File

@@ -1,6 +1,5 @@
#Fri Mar 18 11:26:35 CET 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-all.zip

147
gradlew vendored
View File

@@ -1,4 +1,20 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# 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
#
# https://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.
#
##############################################################################
##
@@ -6,47 +22,6 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -61,9 +36,49 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -90,7 +105,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -110,10 +125,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -138,27 +154,30 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=`save "$@"`
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

33
gradlew.bat vendored
View File

@@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -8,14 +24,17 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +65,9 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +78,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line

View File

@@ -0,0 +1,26 @@
FROM sickp/alpine-sshd:7.5-r2
ADD authorized_keys /home/sshj/.ssh/authorized_keys
ADD test-container/ssh_host_dsa_key /etc/ssh/ssh_host_dsa_key
ADD test-container/ssh_host_dsa_key.pub /etc/ssh/ssh_host_dsa_key.pub
ADD test-container/ssh_host_ecdsa_key /etc/ssh/ssh_host_ecdsa_key
ADD test-container/ssh_host_ecdsa_key.pub /etc/ssh/ssh_host_ecdsa_key.pub
ADD test-container/ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key
ADD test-container/ssh_host_ed25519_key.pub /etc/ssh/ssh_host_ed25519_key.pub
ADD test-container/sshd_config /etc/ssh/sshd_config
ADD test-container/users_rsa_ca.pub /etc/ssh/users_rsa_ca.pub
RUN apk add --no-cache tini
RUN \
echo "root:smile" | chpasswd && \
adduser -D -s /bin/ash sshj && \
passwd -u sshj && \
chmod 600 /home/sshj/.ssh/authorized_keys && \
chmod 600 /etc/ssh/ssh_host_ecdsa_key && \
chmod 644 /etc/ssh/ssh_host_ecdsa_key.pub && \
chmod 600 /etc/ssh/ssh_host_ed25519_key && \
chmod 644 /etc/ssh/ssh_host_ed25519_key.pub && \
chown -R sshj:sshj /home/sshj
ENTRYPOINT ["/sbin/tini", "/entrypoint.sh", "-o", "LogLevel=DEBUG2"]

View File

@@ -0,0 +1,9 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOEQcvowiV3igdRO7rKPrZrao1hCQrnC4tgsxqSJdQCbABI+vHrdbJRfWZNuSk48aAtARJzJVmkn/r63EPJgkh8= root@itgcpkerberosstack-cbgateway-0-20151117031915
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHQiZm0wBbmI8gohA/N9ir1O+egikL6S9FjZS8GHbx4rTHI1V+vbXxx2O9bFWtep1PFb4iowtZkxf6gvRjGkL6M= ajvanerp@Heimdall.local
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDAdJiRkkBM8yC8seTEoAn2PfwbLKrkcahZ0xxPoWICJ root@sshj
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ8ww4hJG/gHJYdkjTTBDF1GNz+228nuWprPV+NbQauA ajvanerp@Heimdall.local
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOaWrwt3drIOjeBq2LSHRavxAT7ja2f+5soOUJl/zKSI ajvanerp@Heimdall.xebialabs.com
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAoZ9l6Tkm2aL1tSBy2yw4xU5s8BE9MfqS/4J7DzvsYJxF6oQmTIjmStuhH/CT7UjuDtKXdXZUsIhKtafiizxGO8kHSzKDeitpth2RSr8ddMzZKyD6RNs7MfsgjA3UTtrrSrCXEY6O43S2cnuJrWzkPxtwxaQ3zOvDbS2tiulzyq0VzYmuhA/a4CyuQtJBuu+P2oqmu6pU/VB6IzONpvBvYbNPsH1WDmP7zko5wHPihXPCliztspKxS4DRtOZ7BGXyvg44UmIy0Kf4jOkaBV/eCCA4qH7ZHz71/5ceMOpszPcNOEmLGGYhwI+P3OuGMpkrSAv1f8IY6R8spZNncP6UaQ== no-passphrase
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDKRyZAtOJJfAhPU6xE6ZXY564vwErAI3n3Yn4lTHL9bxev9Ily6eCqPLcV0WbSV04pztngFn9MjT7yb8mcXheHpIaWEH569sMpmpOtyfn4p68SceuXBGyyPGMIcfOTknkASd1JYSD4EPkd9rZmCzcx3vEnLu8ChnA/G221xSVQ5VC/jD/c/CgNUayhQ+xbn57qHKKtZwfTa21QmwIabGYJNwlVjlKTCdddeVnZfKqKrG7cxHQApsxd21rhM9IT/C/f4Y/Tx3WUUVeam0iZ265oiPHoPALqJIWSQIUheRYAxYAQqJwSQ0Or9MM8XXun2Iy3RUSGk6eIvrCsFbNURsHNs7Pu0UnpYv6FZ3vCkFep/1pAT6fQvY7pDOOWDHKXArD4watc9gIWaQBH73wDW/KgBcnMRSoGWgQjsYqIamP4oV1+HqUI3lRAsXZaX+eiBGt3+3A5KebP27UJ1YUwhwlzs7wzTKaCu0OaL+hOsP1F2AxAa995bgFksMd23645ux3YCJKXG4sGpJ1Z/Hs49K72gv+QjLZVxXqY623c8+3OUhlixqoEFd4iG7UMc5a552ch/VA+jaspmLZoFhPz99aBRVb1oCSPxSwLw+Q/wxv6pZmT+14rqTzY2farjU53hM+CsUPh7dnWXhGG7RuA5wCdeOXOYjuksfzAoHIZhPqTgQ== ajvanerp@Heimdall.local
ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBMvfRYSe44VQGwxexOMibcM3+fWeUP1jrBofOxFDRRrzRF8dK/vll2svqTPXMRnITnT1UoemEcB5OHtvH4hzfh/HFeDxJ5S7UncYxoClTSa8MeMFG2Zj9CoUZs1SHbwSGg== root@sshj
ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHquUYgkU9wJrcxDWVtdqtfqf6SBDdPDRxwDl7OCohV2UNu2KdjJwSj8j0fsPeMdHjSiv9OCnHYrVilQ+W5WW5q5wGXwk10oIcV0JJscohLA0nS7mKinBrxUwVHnNZbPExFciicnEArcYRb1BuT7HF8hfjuSSpWS0rob6kloSSi/jV7ZA== root@sshj

View File

@@ -0,0 +1,21 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH
NzAAAAgQDGUD3XnEQf3S4iB8LbVAw9diSaTTbaKGRt+D89d6QWHJ75I684F6iehXzr7iKq
PmmVy2Bp3BfSM1m6P4wJftHbVW6dbJSeVW1Ov6SIRA5XEG/hrY1DmlC9aXhksqYKUKffYx
WOEg4p2eCtvGyu/j9EucGrC76BraEboAHpXsojNwAAABUAuEexd+FsMSbNSsJz99HcNO7M
hy8AAACBAL++FvcyX8PZ7VeQj+gu0CkDhZM14IpNGKKOBDFvZTUILHHG7TnkjBR1HJw/bR
lwkvrvYC+155sT/BC2OKpVkiUyCw1LKGVtJBas7UlqmTa4m1fEGjaWX0b1Op2hpwpxCkmj
qS07HlC/nEHsEEMdCa9HxCfbEdMmUdLNSwEVJrPAAAAAgAGb6J24Ra4fz55vlK1vt34u39
0YdMg1RLiCa4dFubc8khEMYKpwBIoyECglJyDdLXnuJQiwVzNgX1azx10G84d5QCoAZPQK
WK1oWjj8rB+4gtEjE1sB7fZkxSXF/BaRJQPiglm0kN9gJU6RZSz4vKZIE8Bk/+htXgcXvv
8R0eShAAAB6EMk1g1DJNYNAAAAB3NzaC1kc3MAAACBAMZQPdecRB/dLiIHwttUDD12JJpN
NtooZG34Pz13pBYcnvkjrzgXqJ6FfOvuIqo+aZXLYGncF9IzWbo/jAl+0dtVbp1slJ5VbU
6/pIhEDlcQb+GtjUOaUL1peGSypgpQp99jFY4SDinZ4K28bK7+P0S5wasLvoGtoRugAele
yiM3AAAAFQC4R7F34WwxJs1KwnP30dw07syHLwAAAIEAv74W9zJfw9ntV5CP6C7QKQOFkz
Xgik0Yoo4EMW9lNQgsccbtOeSMFHUcnD9tGXCS+u9gL7XnmxP8ELY4qlWSJTILDUsoZW0k
FqztSWqZNribV8QaNpZfRvU6naGnCnEKSaOpLTseUL+cQewQQx0Jr0fEJ9sR0yZR0s1LAR
Ums8AAAACAAZvonbhFrh/Pnm+UrW+3fi7f3Rh0yDVEuIJrh0W5tzySEQxgqnAEijIQKCUn
IN0tee4lCLBXM2BfVrPHXQbzh3lAKgBk9ApYrWhaOPysH7iC0SMTWwHt9mTFJcX8FpElA+
KCWbSQ32AlTpFlLPi8pkgTwGT/6G1eBxe+/xHR5KEAAAAUCbVJM+EkJ5K/JWd08304hz+O
Cq8AAAANYWp2YW5lcnBAdGhvcgECAwQF
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAMZQPdecRB/dLiIHwttUDD12JJpNNtooZG34Pz13pBYcnvkjrzgXqJ6FfOvuIqo+aZXLYGncF9IzWbo/jAl+0dtVbp1slJ5VbU6/pIhEDlcQb+GtjUOaUL1peGSypgpQp99jFY4SDinZ4K28bK7+P0S5wasLvoGtoRugAeleyiM3AAAAFQC4R7F34WwxJs1KwnP30dw07syHLwAAAIEAv74W9zJfw9ntV5CP6C7QKQOFkzXgik0Yoo4EMW9lNQgsccbtOeSMFHUcnD9tGXCS+u9gL7XnmxP8ELY4qlWSJTILDUsoZW0kFqztSWqZNribV8QaNpZfRvU6naGnCnEKSaOpLTseUL+cQewQQx0Jr0fEJ9sR0yZR0s1LARUms8AAAACAAZvonbhFrh/Pnm+UrW+3fi7f3Rh0yDVEuIJrh0W5tzySEQxgqnAEijIQKCUnIN0tee4lCLBXM2BfVrPHXQbzh3lAKgBk9ApYrWhaOPysH7iC0SMTWwHt9mTFJcX8FpElA+KCWbSQ32AlTpFlLPi8pkgTwGT/6G1eBxe+/xHR5KE= ajvanerp@thor

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOpOBFjqe0hjK/hs4WZ3dZqnzanq1L3/JbvV1TCkbe4ToAoGCCqGSM49
AwEHoUQDQgAEVzkrS7Yj0nXML7A3mE08YDthfBR/ZbyYJDIq1vTzcqs6KTaCT529
swNXWLHO+mbHviZcRiI57ULXHZ1emom/Jw==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFc5K0u2I9J1zC+wN5hNPGA7YXwUf2W8mCQyKtb083KrOik2gk+dvbMDV1ixzvpmx74mXEYiOe1C1x2dXpqJvyc= root@404b27be2bf4

View File

@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBFG9PKAq8FtH0me+LHUE6YaVANCMqy/Znkffzief1W/gAAAKCyyoBkssqA
ZAAAAAtzc2gtZWQyNTUxOQAAACBFG9PKAq8FtH0me+LHUE6YaVANCMqy/Znkffzief1W/g
AAAED+Yfza2xk5LqP9pN6TpvhWYP0L60zOQJpHhbEuiS3LLkUb08oCrwW0fSZ74sdQTphp
UA0IyrL9meR9/OJ5/Vb+AAAAF2FqdmFuZXJwQEhlaW1kYWxsLmxvY2FsAQIDBAUG
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEUb08oCrwW0fSZ74sdQTphpUA0IyrL9meR9/OJ5/Vb+ ajvanerp@Heimdall.local

View File

@@ -0,0 +1,140 @@
# $OpenBSD: sshd_config,v 1.101 2017/03/14 07:19:07 djm Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/bin:/usr/bin:/sbin:/usr/sbin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile .ssh/authorized_keys
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
#UsePAM no
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
#X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# override default of no subsystems
Subsystem sftp /usr/lib/ssh/sftp-server
# the following are HPN related configuration options
# tcp receive buffer polling. disable in non autotuning kernels
#TcpRcvBufPoll yes
# disable hpn performance boosts
#HPNDisabled no
# buffer size for hpn to non-hpn connections
#HPNBufferSize 2048
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
TrustedUserCAKeys /etc/ssh/users_rsa_ca.pub
KexAlgorithms +diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1
macs +hmac-ripemd160-etm@openssh.com,hmac-ripemd160,hmac-ripemd160@openssh.com
Ciphers +3des-cbc,blowfish-cbc,aes128-cbc,aes192-cbc,aes256-cbc
PubKeyAcceptedKeyTypes +ssh-dss
HostKeyAlgorithms +ssh-dss
HostbasedAcceptedKeyTypes +ssh-dss

View File

@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDN70b/cYHZQMD1YW0mlncXqC2l++sEWrVYlIUCzNxNhRYjI4UmEVEq3ru1h6K3ZVAJi1DcZuf5ne1ZXtwJ1Uw1JA4wGdKw+9TwAb5Gubn+VEowgt62kLAPeChiPucTXD0FDDhIUOBv3KxytdrJIYAtzZT27STsBiDF1+7Ld3wk/1Dg9NAaI6q40PmuicTEACQRHn5snI1t9+LgZTd3/PPE5pjJM0ow9+r6mlUUM5oHCk5sZ8DBuRR1Ram4sxp/LFQM+9feMmW3ZM2C5AN0JG4A7NXnlwiTKmNVrGI0iFucBBKhjxN1qdgBF11/42cCrerC9UW1auTTi9mqwEIqBGL30VOPy+dCPQQViP+C09CBgyr3wpZciPKP1mvmcOkC5FDzKg9e3v1JBq0fqZgwt+PPG8cGnxRCGEQ+ZMLDuAixkQUEwDWeMskHLkbjUEiVZydViCPSzFczGtKatQiQVZA5Zx0Gn2sUaQjykhWzqKNL8oIbolEdkH9ubOZWNi0brzU= root@sshj

6
src/itest/generate.sh Normal file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
# Don't call it frequently. It's rather a documentation how everything is generated.
ssh-keygen -f resources/users_rsa_ca -t rsa -N ''
mv resources/users_rsa_ca.pub docker-image/test-container
ssh-keygen -f resources/keyfiles/id_rsa2 -t rsa -m pem -N ''
ssh-keygen -s resources/users_rsa_ca -I my_key_id -n sshj resources/keyfiles/id_rsa2.pub

View File

@@ -0,0 +1,42 @@
/*
* 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
import net.schmizz.sshj.Config
import net.schmizz.sshj.DefaultConfig
import net.schmizz.sshj.SSHClient
import net.schmizz.sshj.transport.verification.PromiscuousVerifier
import spock.lang.Specification
class IntegrationBaseSpec extends Specification {
protected static final int DOCKER_PORT = 2222
protected static final String USERNAME = "sshj"
protected static final String KEYFILE = "src/itest/resources/keyfiles/id_rsa"
protected final static String SERVER_IP = System.getProperty("serverIP", "127.0.0.1")
protected static SSHClient getConnectedClient(Config config) {
SSHClient sshClient = new SSHClient(config)
sshClient.addHostKeyVerifier(new PromiscuousVerifier())
sshClient.connect(SERVER_IP, DOCKER_PORT)
return sshClient
}
protected static SSHClient getConnectedClient() throws IOException {
return getConnectedClient(new DefaultConfig())
}
}

View File

@@ -0,0 +1,118 @@
/*
* 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
import com.hierynomus.sshj.key.KeyAlgorithms
import com.hierynomus.sshj.transport.kex.DHGroups
import com.hierynomus.sshj.transport.cipher.BlockCiphers
import com.hierynomus.sshj.transport.mac.Macs
import net.schmizz.sshj.transport.verification.PromiscuousVerifier
import net.schmizz.sshj.DefaultConfig
import net.schmizz.sshj.SSHClient
import net.schmizz.sshj.transport.TransportException
import net.schmizz.sshj.userauth.UserAuthException
import spock.lang.Unroll
class IntegrationSpec extends IntegrationBaseSpec {
@Unroll
def "should accept correct key for #signatureName"() {
given:
def config = new DefaultConfig()
config.setKeyAlgorithms(Collections.singletonList(signatureFactory))
SSHClient sshClient = new SSHClient(config)
sshClient.addHostKeyVerifier(fingerprint) // test-containers/ssh_host_ecdsa_key's fingerprint
when:
sshClient.connect(SERVER_IP, DOCKER_PORT)
then:
sshClient.isConnected()
where:
signatureFactory << [KeyAlgorithms.ECDSASHANistp256(), KeyAlgorithms.EdDSA25519()]
fingerprint << ["d3:6a:a9:52:05:ab:b5:48:dd:73:60:18:0c:3a:f0:a3", "dc:68:38:ce:fc:6f:2c:d6:6d:6b:34:eb:5c:f0:41:6a"]
signatureName = signatureFactory.getName()
}
def "should decline wrong key"() throws IOException {
given:
SSHClient sshClient = new SSHClient(new DefaultConfig())
sshClient.addHostKeyVerifier("d4:6a:a9:52:05:ab:b5:48:dd:73:60:18:0c:3a:f0:a3")
when:
sshClient.connect(SERVER_IP, DOCKER_PORT)
then:
thrown(TransportException.class)
}
@Unroll
def "should authenticate with key #key"() {
given:
SSHClient client = getConnectedClient()
when:
def keyProvider = passphrase != null ? client.loadKeys("src/itest/resources/keyfiles/$key", passphrase) : client.loadKeys("src/itest/resources/keyfiles/$key")
client.authPublickey(USERNAME, keyProvider)
then:
client.isAuthenticated()
where:
key | passphrase
// "id_ecdsa_nistp256" | null // TODO: Need to improve PKCS8 key support.
"id_ecdsa_opensshv1" | null
"id_ed25519_opensshv1" | null
"id_ed25519_opensshv1_aes256cbc.pem" | "foobar"
"id_ed25519_opensshv1_protected" | "sshjtest"
"id_rsa" | null
"id_rsa_opensshv1" | null
"id_ecdsa_nistp384_opensshv1" | null
"id_ecdsa_nistp521_opensshv1" | null
}
def "should not authenticate with wrong key"() {
given:
SSHClient client = getConnectedClient()
when:
client.authPublickey("sshj", "src/itest/resources/keyfiles/id_unknown_key")
then:
thrown(UserAuthException.class)
!client.isAuthenticated()
}
def "should correctly connect using parameters in #670"() {
given:
def config = new DefaultConfig()
// config.setKeyAlgorithms(Collections.singletonList(KeyAlgorithms.SSHDSA())) // Can't get openssh to offer ssh-dss
config.setKeyExchangeFactories(DHGroups.Group1SHA1())
config.setCipherFactories(BlockCiphers.TripleDESCBC())
config.setMACFactories(Macs.HMACSHA1())
SSHClient sshClient = new SSHClient(config)
sshClient.addHostKeyVerifier(new PromiscuousVerifier())
when:
sshClient.connect(SERVER_IP, DOCKER_PORT)
then:
sshClient.isConnected()
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.sftp
import com.hierynomus.sshj.IntegrationBaseSpec
import net.schmizz.sshj.SSHClient
import net.schmizz.sshj.sftp.OpenMode
import net.schmizz.sshj.sftp.RemoteFile
import net.schmizz.sshj.sftp.SFTPClient
import java.nio.charset.StandardCharsets
import static org.codehaus.groovy.runtime.IOGroovyMethods.withCloseable
class FileWriteSpec extends IntegrationBaseSpec {
def "should append to file (GH issue #390)"() {
given:
SSHClient client = getConnectedClient()
client.authPublickey("sshj", "src/test/resources/id_rsa")
SFTPClient sftp = client.newSFTPClient()
def file = "/home/sshj/test.txt"
def initialText = "This is the initial text.\n".getBytes(StandardCharsets.UTF_16)
def appendText = "And here's the appended text.\n".getBytes(StandardCharsets.UTF_16)
when:
withCloseable(sftp.open(file, EnumSet.of(OpenMode.WRITE, OpenMode.CREAT))) { RemoteFile initial ->
initial.write(0, initialText, 0, initialText.length)
}
then:
withCloseable(sftp.open(file, EnumSet.of(OpenMode.READ))) { RemoteFile read ->
def bytes = new byte[initialText.length]
read.read(0, bytes, 0, bytes.length)
bytes == initialText
}
when:
withCloseable(sftp.open(file, EnumSet.of(OpenMode.WRITE, OpenMode.APPEND))) { RemoteFile append ->
append.write(0, appendText, 0, appendText.length)
}
then:
withCloseable(sftp.open(file, EnumSet.of(OpenMode.READ))) { RemoteFile read ->
def bytes = new byte[initialText.length + appendText.length]
read.read(0, bytes, 0, bytes.length)
Arrays.copyOfRange(bytes, 0, initialText.length) == initialText
Arrays.copyOfRange(bytes, initialText.length, initialText.length + appendText.length) == appendText
}
cleanup:
sftp.close()
client.close()
}
}

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.signature
import com.hierynomus.sshj.IntegrationBaseSpec
import net.schmizz.sshj.DefaultConfig
import spock.lang.Unroll
class RsaSignatureClientKeySpec extends IntegrationBaseSpec {
@Unroll
def "should correctly connect using publickey auth with RSA key with signature"() {
given:
def client = getConnectedClient(new DefaultConfig())
when:
client.authPublickey(USERNAME, "src/itest/resources/keyfiles/id_rsa2")
then:
client.authenticated
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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 com.hierynomus.sshj.IntegrationBaseSpec
import com.hierynomus.sshj.key.KeyAlgorithms
import net.schmizz.sshj.DefaultConfig
import spock.lang.Unroll
class SignatureSpec extends IntegrationBaseSpec {
@Unroll
def "should correctly connect with #sig Signature"() {
given:
def cfg = new DefaultConfig()
cfg.setKeyAlgorithms(Collections.singletonList(sigFactory))
def client = getConnectedClient(cfg)
when:
client.authPublickey(USERNAME, KEYFILE)
then:
client.authenticated
where:
sigFactory << [KeyAlgorithms.SSHRSA(), KeyAlgorithms.RSASHA256(), KeyAlgorithms.RSASHA512()]
sig = sigFactory.name
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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 com.hierynomus.sshj.IntegrationBaseSpec
import net.schmizz.sshj.DefaultConfig
import spock.lang.Unroll
class CipherSpec extends IntegrationBaseSpec {
@Unroll
def "should correctly connect with #cipher Cipher"() {
given:
def cfg = new DefaultConfig()
cfg.setCipherFactories(cipherFactory)
def client = getConnectedClient(cfg)
when:
client.authPublickey(USERNAME, KEYFILE)
then:
client.authenticated
cleanup:
client.disconnect()
where:
cipherFactory << [BlockCiphers.TripleDESCBC(),
BlockCiphers.BlowfishCBC(),
BlockCiphers.AES128CBC(),
BlockCiphers.AES128CTR(),
BlockCiphers.AES192CBC(),
BlockCiphers.AES192CTR(),
BlockCiphers.AES256CBC(),
BlockCiphers.AES256CTR(),
GcmCiphers.AES128GCM(),
GcmCiphers.AES256GCM()]
cipher = cipherFactory.name
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.kex
import com.hierynomus.sshj.IntegrationBaseSpec
import com.hierynomus.sshj.transport.mac.Macs
import net.schmizz.sshj.DefaultConfig
import net.schmizz.sshj.transport.kex.Curve25519DH
import net.schmizz.sshj.transport.kex.Curve25519SHA256
import net.schmizz.sshj.transport.kex.DH
import net.schmizz.sshj.transport.kex.DHGexSHA1
import net.schmizz.sshj.transport.kex.DHGexSHA256
import net.schmizz.sshj.transport.kex.ECDH
import net.schmizz.sshj.transport.kex.ECDHNistP
import spock.lang.Unroll
class KexSpec extends IntegrationBaseSpec {
@Unroll
def "should correctly connect with #kex Key Exchange"() {
given:
def cfg = new DefaultConfig()
cfg.setKeyExchangeFactories(kexFactory)
def client = getConnectedClient(cfg)
when:
client.authPublickey(USERNAME, KEYFILE)
then:
client.authenticated
where:
kexFactory << [DHGroups.Group1SHA1(),
DHGroups.Group14SHA1(),
DHGroups.Group14SHA256(),
DHGroups.Group16SHA512(),
DHGroups.Group18SHA512(),
new DHGexSHA1.Factory(),
new DHGexSHA256.Factory(),
new Curve25519SHA256.Factory(),
new Curve25519SHA256.FactoryLibSsh(),
new ECDHNistP.Factory256(),
new ECDHNistP.Factory384(),
new ECDHNistP.Factory521()]
kex = kexFactory.name
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.mac
import com.hierynomus.sshj.IntegrationBaseSpec
import net.schmizz.sshj.DefaultConfig
import spock.lang.Unroll
class MacSpec extends IntegrationBaseSpec {
@Unroll
def "should correctly connect with #mac MAC"() {
given:
def cfg = new DefaultConfig()
cfg.setMACFactories(macFactory)
def client = getConnectedClient(cfg)
when:
client.authPublickey(USERNAME, KEYFILE)
then:
client.authenticated
cleanup:
client.disconnect()
where:
macFactory << [Macs.HMACRIPEMD160(), Macs.HMACRIPEMD160OpenSsh(), Macs.HMACSHA2256(), Macs.HMACSHA2512()]
mac = macFactory.name
}
@Unroll
def "should correctly connect with Encrypt-Then-Mac #mac MAC"() {
given:
def cfg = new DefaultConfig()
cfg.setMACFactories(macFactory)
def client = getConnectedClient(cfg)
when:
client.authPublickey(USERNAME, KEYFILE)
then:
client.authenticated
cleanup:
client.disconnect()
where:
macFactory << [Macs.HMACRIPEMD160Etm(), Macs.HMACSHA2256Etm(), Macs.HMACSHA2512Etm()]
mac = macFactory.name
}
}

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJUMlsSlXqCZmCjlN4kV7hzP+p9pu0fwJ8r4m1qle58SoAoGCCqGSM49
AwEHoUQDQgAE4RBy+jCJXeKB1E7uso+tmtqjWEJCucLi2CzGpIl1AJsAEj68et1s
lF9Zk25KTjxoC0BEnMlWaSf+vrcQ8mCSHw==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,10 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQTL30WEnuOFUBsMXsTjIm3DN/n1nlD9
Y6waHzsRQ0Ua80RfHSv75ZdrL6kz1zEZyE509VKHphHAeTh7bx+Ic34fxxXg8SeUu1J3GM
aApU0mvDHjBRtmY/QqFGbNUh28EhoAAADYHWlHLx1pRy8AAAATZWNkc2Etc2hhMi1uaXN0
cDM4NAAAAAhuaXN0cDM4NAAAAGEEy99FhJ7jhVAbDF7E4yJtwzf59Z5Q/WOsGh87EUNFGv
NEXx0r++WXay+pM9cxGchOdPVSh6YRwHk4e28fiHN+H8cV4PEnlLtSdxjGgKVNJrwx4wUb
ZmP0KhRmzVIdvBIaAAAAMQD3sx28SrtkuhN+Yu06BAoFLMMgneIqguM3jowaz0LWfP1Nhx
Rnh9tNKM6YYvygCggAAAAPZmhlbm5la2VATGFwdG9w
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1,12 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS
1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQB6rlGIJFPcCa3MQ1lbXarX6n+kgQ3
Tw0ccA5ezgqIVdlDbtinYycEo/I9H7D3jHR40or/Tgpx2K1YpUPluVluaucBl8JNdKCHFd
CSbHKISwNJ0u5iopwa8VMFR5zWWzxMRXIonJxAK3GEW9Qbk+xxfIX47kkqVktK6G+pJaEk
ov41e2QAAAEQwljQZcJY0GUAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ
AAAIUEAeq5RiCRT3AmtzENZW12q1+p/pIEN08NHHAOXs4KiFXZQ27Yp2MnBKPyPR+w94x0
eNKK/04KcditWKVD5blZbmrnAZfCTXSghxXQkmxyiEsDSdLuYqKcGvFTBUec1ls8TEVyKJ
ycQCtxhFvUG5PscXyF+O5JKlZLSuhvqSWhJKL+NXtkAAAAQVXt20tSeLzMU1U2nMv8CEEY
Oyl1WIkGAcRatDBAfsE0+NcJ/eSbPXywWAqCzOElQ5ftNFz9t1kNXwW5qiLaaIBpAAAAD2
ZoZW5uZWtlQExhcHRvcAECAwQ=
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1,9 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQR0ImZtMAW5iPIKIQPzfYq9TvnoIpC+
kvRY2UvBh28eK0xyNVfr218cdjvWxVrXqdTxW+IqMLWZMX+oL0YxpC+jAAAAsD+6Oow/uj
qMAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHQiZm0wBbmI8goh
A/N9ir1O+egikL6S9FjZS8GHbx4rTHI1V+vbXxx2O9bFWtep1PFb4iowtZkxf6gvRjGkL6
MAAAAgXNC11pInVAOd3xNphiHMoISeitf6h1IKbDM+niLrL5kAAAAXYWp2YW5lcnBASGVp
bWRhbGwubG9jYWwB
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAwHSYkZJATPMgvLHkxKAJ9j38Gyyq5HGoWdMcT6FiAiQAAAJDimgR84poE
fAAAAAtzc2gtZWQyNTUxOQAAACAwHSYkZJATPMgvLHkxKAJ9j38Gyyq5HGoWdMcT6FiAiQ
AAAECmsckQycWnfGQK6XtQpaMGODbAkMQOdJNK6XJSipB7dDAdJiRkkBM8yC8seTEoAn2P
fwbLKrkcahZ0xxPoWICJAAAACXJvb3RAc3NoagECAwQ=
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1,8 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABBLQVXV9f
Wpw8AL9RTpAr//AAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIJ8ww4hJG/gHJYdk
jTTBDF1GNz+228nuWprPV+NbQauAAAAAoGHEO7x3fSRBohvrIR52U4XD3uqRnhrPYm01k1
f4HHNNv46m92Zw6JKIB9Trrvp0sdMI8MVb79bN45rbn6mvpABtWl6T5TOTyMnKzDfAOx9c
FTaasWFmgtgkXOsu5pLrYBAQgCHWbzjjz6KoV1DmD4SAn9Ojf9Oh+YdAEKZcsvklgpu+Kj
nzN/DR0jt7Nzep2kNCLAS24QEkvQeATVSDiL8=
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1,8 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABB/aWL0WG
iYPOTxGlFwvaCNAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIOaWrwt3drIOjeBq
2LSHRavxAT7ja2f+5soOUJl/zKSIAAAAsKplAiFbOhzcOJYFYBYm8sqYbvhPF8jKdQFkbo
LAOeq+vQ0YBV9XUWQQM2tmL+RPjykPJZ2thcHLpVp3PfUEgo4bImCt939b3Ji3cEwD3QuK
MIhjhx1KvSJNF/uhjwPJnttwHG+ld8F5Gv7LpTOUmOzXKGLIgYRuwonhs5ezdNv5ERs+Cq
M9p/SW5ehL5KPJhGa5a+ZQXRojwEH7J4Q5xztH1gviTdIEpFWWQBH8rX6y
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEoAIBAAKCAQEAoZ9l6Tkm2aL1tSBy2yw4xU5s8BE9MfqS/4J7DzvsYJxF6oQm
TIjmStuhH/CT7UjuDtKXdXZUsIhKtafiizxGO8kHSzKDeitpth2RSr8ddMzZKyD6
RNs7MfsgjA3UTtrrSrCXEY6O43S2cnuJrWzkPxtwxaQ3zOvDbS2tiulzyq0VzYmu
hA/a4CyuQtJBuu+P2oqmu6pU/VB6IzONpvBvYbNPsH1WDmP7zko5wHPihXPClizt
spKxS4DRtOZ7BGXyvg44UmIy0Kf4jOkaBV/eCCA4qH7ZHz71/5ceMOpszPcNOEmL
GGYhwI+P3OuGMpkrSAv1f8IY6R8spZNncP6UaQIBIwKCAQBXvO4uJlbrLJQDPYAt
1i1ybGcF+rrR/Q34a2dgCpZDEwFiDTlcv1hxx689OXTf5cMPXGDZXX5udd9p7Wxa
NqnIrvVUtQWLdqcZuEeO+gitHr8IyMJf5Lm8C/u5vl1PYOYhO0qxwmrTP1u6fZPh
zWX2X1p5626/sy+TCisCRDeLRyes+Dtfs3bDjUq+zF3D/DmeYY55LUx0XS27uXNS
QuUDMSnymFyj4o+jPK0q/j5w4bB+0rbsij+EP7S//jOFrSEcZgBhhIj0rHA5fo6w
NrgtgRKD3HKFBM3b4VM8TdMbHsmf+nT9DjiDqcs+IxXMGlb1XTjtQFIN2eyRtNLd
eQ0bAoGBAMwgv3rGytRjVbR4TT77eF81svzitOJWRdfXuKB5gqM3jsPR08f1MEtZ
44kaI5ByJ3mBDt/EwNgLRdmBddPrLu3so9VLdRmWKI+KNGxwkcxzJv1xXdicgw+w
S5WgigJryuUbtdylXQTlRArLUKsXULk/MndhGiD+a4fZ3dUtktF9AoGBAMqxh6tr
S0ao0rN4hc9I92gwPubD1+XQr9TJQEEqGv3g5O3BdfDrTvizfaeNArahrIqyO5SK
7iDg0xcHqdxmVmmCJ8CkIWBPXLU6erQ1QNlBJmnzYn5lR0Ksx2h/myjeXztvJKEM
q4xUjAEzWjmwxxU3Y6l3FokvgIU4kOVoE4JdAoGARfyZa+xizHnUPeAae/5yaclE
rnmdGma43En2KGQsyj7vHpEVaSDdW6nKWuRj9wKRMPkMafpQvxnOzjsD06EXZ4RV
bbN4mw7pVcj8B+wUuyAqoAmchMfya8dqXy+6SfkSXS4Sd4knNODkIPVAOqjoegcJ
/QtZamXbuYyGkjuCy3sCgYBLSUEFJ9ohjymwX/cvvAQfYmCBmTLu9b2mzmhSt94j
yI+Lgl8BtnxrANbmdjQ1NLxuB6+61IRVWtIP3kZnzj1aY4sbqq1PqHLkOkrVOFnq
S2YKGJJMND8KIur67ZFm84J1KUgej61uow9uKQRBUEnx8AByJOsdAwPZteys+sVq
7wKBgAc3BL6ttDVYlL8U8fgvTCGuIajItvOQQj1n8RKyRLblYXBKAtY+pbULzmF+
HscRgJMcwEIosEbTzzBNEVQm6dS6R/Q534C00Fpsw1z/PFTI8AOdUzTROGjuN8Fg
YZoqMQLhk/PB8V4l7yJmPrE971RmJBBDlLDt6hZwOYEI2yF4
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,39 @@
-----BEGIN RSA PRIVATE KEY-----
MIIG5QIBAAKCAYEA0MZ2xduy86/VbzZWnOnzSqUVeU7ajzwc3LF9vR9ZbufZdCB8
pYRzpQ4B9v3umDZ3nX9qPM4f2iMVDfiz241SwmvV5s7WiOHPhy3ij5mUpRXOn3a8
byVIjdraaVawL642p98cLKB9WKEjKaDw633aD7xzSIomqQboVZrMHNjvIanyd3U6
j9mnoydXD1cIuceZx4S/Av8IQru9AiZYJ7rAfZwz3ip9YWcgT0yIohDbBSX7fsX2
7KF6txIfRXJCJg0QO0kOYoMQmLYJtkVApwixdV29Vx2g5PBKXDQ12FwGXTnZG36v
YYZ7ng12PV+xMyC1xPLdXnzrNR/lO4BGtT14GYJbwVM3gjBDrceavaayVW4SjFrq
R5XDLjldKAfKtCHEavLv16Df1eAwnPlGAwmODlRqTHvL5oxBQibvNjDzVpvfqEsF
RqP/d4AbYjARsKCkeu3PzUI+rq5AtwZ52XKgGdg13wURoAkIsNXonKo92avLnomq
skdTYpfBEOUMSZO9AgMBAAECggGAadURhH84mft6kKPVCDo4UJCa8CGe/ZkVcHKx
MNvhdC0nuIx3Y1hfXz5YlKJo/tQtkrNyYVyEHQpHtAts8VEUsOYFSrlzW3RMxVPn
U7AhAAar9X41S4p02yQkL9339lOz9SlOmPjKUdFth77EIjxr/ColrpIJwwlzYWHV
MpJttnz2IsRUaXOGXVil82rFS5f5RoDua1BpGZsd1yck7Q7oYUR7rpWPdX7XjBtZ
7/3naRa2BK/J2m6JTKBtJcEj8zIPK4HXVO7NriQvhMyFAc5FRR+0ZQFp0bNdCELT
k7nbDaHL8QPfzRiH9zLHe/WHJKNZxTcXctU1v/aBBNPAwsT4NHLydrtVagzBZ/YO
ZBB1JKfpdmnQ54vNI1jlkNCbhkMNPZuDCCk3l4qq6JLi3DrYYqi1B8qzVxivw8ps
0eNt4tMHqmOGwMBEzaYcAXfn66Lea84+QyGc5ibwPuBPtuQcNvHdY4BzXFerDqDI
i/rdMH0ELvTPbgpgl3SrIqCWCoMpAoHBAPZcpWDK22owtw0D0QDylO/H3rkf3WX5
5bo9FzoKtZdHNhZJUYFPBC26xHKXJgSKh6OuL9IlXtpQD3u4EctBevnJU8OZxKAM
MJZ/vIXxnAGONuhcDs/kns0Bu9QNgdUOdYW1DomNaePQ669awhXtwaxVeBqwl6AT
v6PnlzyRZK9Di/9xwkh/g0h4258ef0grD2oDUIxDvEnm9Ul9mE8MIqUjQw/dfpuA
D2mW0nh+FK861VbGRrlumhr4y33KNIs5SwKBwQDY8WGyGlPvjPBUD4kHaledNCYu
vMBvlo8UKlk9SpcRpHUqOm5IFmKmmLQdEqYip4PULGZVFjbrfil4LKV9pMxtmn56
HKqteoWP1VuqhC1j2RdnX1KuIqB+sv30BkWsrOsOC6YwaDHl5eLPJv0BbFWApBEm
/g2n2wpoHvGr2uSl0+B2mRw/BFcWw3zLcBB6OP/U4hjpPgEfwHLp2tG8DraT/dOm
7o+DYQQz6ACqz8pzrMyzS/6uaR/YK70Q8RKPihcCgcEAliiH4EQkkkfY+oTN+h7h
KnkPRpSmdEZpgCdGJelrHyaXT+QmWoNXz6ubmyCHWpM480ny+covUy8jEMxzhAiI
NQFCHeF2V/q2DrUSqi1GYihVTTD3Ej2NkPSykCAfd0XV2cYucyaPWPz4+it+SrFc
r3Z0uwfRkw8Waod4xcD0tmKcTPkAawHVefG4IvcKq2kbfwlAKg4LEJxF+yIjGGMU
JsUkVeIyDgNy4W+9HxXx85APglFdwB4qra/hD+2UMxubAoHBAIRUeOtS8/AjYFVm
RIepblgN/1xy9k8a35vFWTnxzcSNNIrVqX9/aB2G+Bbj0UNCOz+o9aLhMg7jnhgX
47qIU8pnes6xvcqj+eSKmKeiiK1nNsdvddeSd6PROucnDEkQETE4Gd9dL1K0r2z8
s0ey9VTKv0uxnFLPYcGxXmkd1GrymvC85GXsF9Ni2zSc3vAu5J7Oa7OahsT/dxj+
yQCVWPlc00X4LsJM42tmEUIgDbYRqauUp31r0mjiBSnYYyH7cQKBwQC+2mw3oRsu
La9Yj11WcwWy6in26JyITYmEnfwydDTdX8tn9XdPva94frC/TJkDmoh9gYSNZc8r
zm9y/l9LpO98jIG+jH9wFRKO7xgCffZl4tbvu1DsGbh86IS7gvRbIwN5mnrKC61g
4c/+PYAJnyC7+0oXhY2W7h2STUWi3/AvT/EnGLv7k41+9H3Hj5oqkWEt+DITgBia
sTT3iRK6YVtXBg+AyG7nbobwTtZu98uFBjHwzGaelSPGGiWsUx4/u2Y=
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1 @@
ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgUsee85QZv49JUmGGA6cN852mR2cSsEst9KDH7gk3Lq4AAAADAQABAAABgQDQxnbF27Lzr9VvNlac6fNKpRV5TtqPPBzcsX29H1lu59l0IHylhHOlDgH2/e6YNnedf2o8zh/aIxUN+LPbjVLCa9XmztaI4c+HLeKPmZSlFc6fdrxvJUiN2tppVrAvrjan3xwsoH1YoSMpoPDrfdoPvHNIiiapBuhVmswc2O8hqfJ3dTqP2aejJ1cPVwi5x5nHhL8C/whCu70CJlgnusB9nDPeKn1hZyBPTIiiENsFJft+xfbsoXq3Eh9FckImDRA7SQ5igxCYtgm2RUCnCLF1Xb1XHaDk8EpcNDXYXAZdOdkbfq9hhnueDXY9X7EzILXE8t1efOs1H+U7gEa1PXgZglvBUzeCMEOtx5q9prJVbhKMWupHlcMuOV0oB8q0IcRq8u/XoN/V4DCc+UYDCY4OVGpMe8vmjEFCJu82MPNWm9+oSwVGo/93gBtiMBGwoKR67c/NQj6urkC3BnnZcqAZ2DXfBRGgCQiw1eicqj3Zq8ueiaqyR1Nil8EQ5QxJk70AAAAAAAAAAAAAAAEAAAAJbXlfa2V5X2lkAAAACAAAAARzc2hqAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAGXAAAAB3NzaC1yc2EAAAADAQABAAABgQDN70b/cYHZQMD1YW0mlncXqC2l++sEWrVYlIUCzNxNhRYjI4UmEVEq3ru1h6K3ZVAJi1DcZuf5ne1ZXtwJ1Uw1JA4wGdKw+9TwAb5Gubn+VEowgt62kLAPeChiPucTXD0FDDhIUOBv3KxytdrJIYAtzZT27STsBiDF1+7Ld3wk/1Dg9NAaI6q40PmuicTEACQRHn5snI1t9+LgZTd3/PPE5pjJM0ow9+r6mlUUM5oHCk5sZ8DBuRR1Ram4sxp/LFQM+9feMmW3ZM2C5AN0JG4A7NXnlwiTKmNVrGI0iFucBBKhjxN1qdgBF11/42cCrerC9UW1auTTi9mqwEIqBGL30VOPy+dCPQQViP+C09CBgyr3wpZciPKP1mvmcOkC5FDzKg9e3v1JBq0fqZgwt+PPG8cGnxRCGEQ+ZMLDuAixkQUEwDWeMskHLkbjUEiVZydViCPSzFczGtKatQiQVZA5Zx0Gn2sUaQjykhWzqKNL8oIbolEdkH9ubOZWNi0brzUAAAGUAAAADHJzYS1zaGEyLTUxMgAAAYBxPe4yc3IwnjwULBv1tk3uTr35MKqIiDrIuWX9+7w/EJ9hQPjSZjtiOABP/C63F2c43zvN1XUqJ1Yvrh1dqpI5nIxexMLFRgJrawALHNsc5h5uLBL6q9rgyJsUNWXMgl9nOUGDDh+Jg6yM6SUVd44WuDTbgxtIwc5Uq6fE+HFowM35Xt0u9UEOBqOzpyBNYjNEsCMfPxkbzYGcLW9Y2C28ygrizRn+rhXFG3sQxraiCPVAL+d9NMGV3TaFXScEoCuXKRyHab1ch9g613FBL16k2rxZWoHfwI07bAUrpcv5upR5RMeeYrNmE7mrQ5WHemACd6QJtknPxOfxgAKOck486b29dgAt5C6P81T0mL0+52bu0LkbRYxVEExdeDurvhue2ZzGG11PbEJdLpVbgcPJr7dUkPPG2nPW4JLqqnzlulqu7Me07mgJuVK1OnXUKKziQ8BcDqx6lsdBg/CuKvL4PedFkSh32W+7VIQq7e9sVEV+Q5CngWfr2sYFh3cu3kw= lagunov@unit-1381

View File

@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQxnbF27Lzr9VvNlac6fNKpRV5TtqPPBzcsX29H1lu59l0IHylhHOlDgH2/e6YNnedf2o8zh/aIxUN+LPbjVLCa9XmztaI4c+HLeKPmZSlFc6fdrxvJUiN2tppVrAvrjan3xwsoH1YoSMpoPDrfdoPvHNIiiapBuhVmswc2O8hqfJ3dTqP2aejJ1cPVwi5x5nHhL8C/whCu70CJlgnusB9nDPeKn1hZyBPTIiiENsFJft+xfbsoXq3Eh9FckImDRA7SQ5igxCYtgm2RUCnCLF1Xb1XHaDk8EpcNDXYXAZdOdkbfq9hhnueDXY9X7EzILXE8t1efOs1H+U7gEa1PXgZglvBUzeCMEOtx5q9prJVbhKMWupHlcMuOV0oB8q0IcRq8u/XoN/V4DCc+UYDCY4OVGpMe8vmjEFCJu82MPNWm9+oSwVGo/93gBtiMBGwoKR67c/NQj6urkC3BnnZcqAZ2DXfBRGgCQiw1eicqj3Zq8ueiaqyR1Nil8EQ5QxJk70= lagunov@unit-1381

View File

@@ -0,0 +1,49 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAgEAykcmQLTiSXwIT1OsROmV2OeuL8BKwCN592J+JUxy/W8Xr/SJcung
qjy3FdFm0ldOKc7Z4BZ/TI0+8m/JnF4Xh6SGlhB+evbDKZqTrcn5+KevEnHrlwRssjxjCH
Hzk5J5AEndSWEg+BD5Hfa2Zgs3Md7xJy7vAoZwPxtttcUlUOVQv4w/3PwoDVGsoUPsW5+e
6hyirWcH02ttUJsCGmxmCTcJVY5SkwnXXXlZ2Xyqiqxu3MR0AKbMXdta4TPSE/wv3+GP08
d1lFFXmptImduuaIjx6DwC6iSFkkCFIXkWAMWAEKicEkNDq/TDPF17p9iMt0VEhpOniL6w
rBWzVEbBzbOz7tFJ6WL+hWd7wpBXqf9aQE+n0L2O6QzjlgxylwKw+MGrXPYCFmkAR+98A1
vyoAXJzEUqBloEI7GKiGpj+KFdfh6lCN5UQLF2Wl/nogRrd/twOSnmz9u1CdWFMIcJc7O8
M0ymgrtDmi/oTrD9RdgMQGvfeW4BZLDHdt+uObsd2AiSlxuLBqSdWfx7OPSu9oL/kIy2Vc
V6mOtt3PPtzlIZYsaqBBXeIhu1DHOWuednIf1QPo2rKZi2aBYT8/fWgUVW9aAkj8UsC8Pk
P8Mb+qWZk/teK6k82Nn2q41Od4TPgrFD4e3Z1l4Rhu0bgOcAnXjlzmI7pLH8wKByGYT6k4
EAAAdQ3L5mFty+ZhYAAAAHc3NoLXJzYQAAAgEAykcmQLTiSXwIT1OsROmV2OeuL8BKwCN5
92J+JUxy/W8Xr/SJcungqjy3FdFm0ldOKc7Z4BZ/TI0+8m/JnF4Xh6SGlhB+evbDKZqTrc
n5+KevEnHrlwRssjxjCHHzk5J5AEndSWEg+BD5Hfa2Zgs3Md7xJy7vAoZwPxtttcUlUOVQ
v4w/3PwoDVGsoUPsW5+e6hyirWcH02ttUJsCGmxmCTcJVY5SkwnXXXlZ2Xyqiqxu3MR0AK
bMXdta4TPSE/wv3+GP08d1lFFXmptImduuaIjx6DwC6iSFkkCFIXkWAMWAEKicEkNDq/TD
PF17p9iMt0VEhpOniL6wrBWzVEbBzbOz7tFJ6WL+hWd7wpBXqf9aQE+n0L2O6Qzjlgxylw
Kw+MGrXPYCFmkAR+98A1vyoAXJzEUqBloEI7GKiGpj+KFdfh6lCN5UQLF2Wl/nogRrd/tw
OSnmz9u1CdWFMIcJc7O8M0ymgrtDmi/oTrD9RdgMQGvfeW4BZLDHdt+uObsd2AiSlxuLBq
SdWfx7OPSu9oL/kIy2VcV6mOtt3PPtzlIZYsaqBBXeIhu1DHOWuednIf1QPo2rKZi2aBYT
8/fWgUVW9aAkj8UsC8PkP8Mb+qWZk/teK6k82Nn2q41Od4TPgrFD4e3Z1l4Rhu0bgOcAnX
jlzmI7pLH8wKByGYT6k4EAAAADAQABAAACAEeOg+nAE40LY6UsZHS8bVYeH3ClBcySwELT
hOyM7uDYu/hy+Wy9b8zJTbtaKJWgbPY9RrYPP1lFXk9FXH0EjC5f9XyAuT2mrcO5+yQvn0
5ng3dy9XSnDAzBcAc8yH4cAtInTzD2O0OGPZpr/Hp83Tm3NHg4EjVCedLZUSZMZ7cGaFpa
svzp9wE/M2KZNLP087K+Do5pNEuGZVVugH/4eOApqBOsFWoOwTFADJjzkSEdftp6ZM8WMp
XBU5T3UAnh3M3GbartlJqza9o1tKk5Ham9SFZvZFiQMvBaAr6kpzP+qh86hnuvb/EU1Tw1
ldj6skzjJCq3cTzeuIEn7BiUL1qEECjpjx7OG6L9/lWyOy27nU/tiQ1MCUDMs/u/Kpnm8X
1kvEYzq1iEQVjqEaKHQBA35GB5krXzVLK2XNMYzZDM4+bGbffX04t4CpVbJHY7mFrbO584
JlqsCxKvhDDJpNuWhT4HUrAMPCJRvFC57n12+wjLrDsBKMOGRwo1NqnaR75QOR5gtboav+
6P/o35U/gATyiePDF3HD/213gJcOwRXpH9oFleRStqiU2OsfcULlrjD6gIXCAQOOrt4l15
uEh8fnUdFbgmFfuTapKHHm6nVGs6K0JWpqlqlsiwsJxSBwRhRFO3G/iAsmxKDvWaq1yBIJ
yhDRTeA7fyCw8k+wsBAAABAGeNiRwkVyn/iUA61drLC5Y/0Gd+a540VrLMwyV3LGlDZPH3
RQFHH+HldhLqmp2ikHZWFq36vjTDr/ubCuwQNlJo4TAo5/RQk1/ChBqXj2IdT+vBysH+bK
IuZQoWXsfISMfQ7o+F5vv7WdItS9w44HpXayH12Q8D1Qr4Qnt0CeMIhrrV7MPsGVTIOpOU
FxH4xu9ovBWDnyloC4rWkBmeAzLCFtO1V1iGN7Six/OXvnxnbif+BsfdQt+OxHIYBOue5G
+Dkss+1xR8l8xrZsOpN2uY1QFIaE6UyElFleAEhtYL2vvuXTrL3EJKqRtIcWenL/wxYlkt
X1CJQS02JW+PtNUAAAEBAPWFstL1hWK4Fp5ipJSGSkDNvGGuzamAYEgqr6n5Zzb1R1HPyE
x6uEMB7ELQjOG4FENIQYBBnBRnMOWWFJp0V5UjFKDft1FabLiozqBtLCRnHnIGllFIWJK+
u/h9OL4OWXGUJx2Em4XdJBPqp0g56VI237AsnTbTGS0tGLOErLWbQY7npZeBFct/501RTP
M5i7F0QEDLjEDZbDxvCz8a5tjfvyP1awK2SyluiE4VPeYr5Op1JNPTJMz5U3YFsIZxdZHJ
AK5mX8hNzTHpTApkS7o0DvExn5DVB8OHOQFdc+BjBIqQwa953f3FaAw9V3o6Dt1zXe9OJR
tBUiBeurvDFk0AAAEBANLpAv9NDf3c8k0PAYhwu+SWoo0OclOWQSZes/93UeB0ch57LD+v
KVPR3hw2AzAsgZn/PcMbIC3SPLNnAlNftfTa98avQOEfmYqrH499zVPuMb7fieS/eQZ4LF
rsZ0o+W4CDVmzImgOe1hENWcfSeUKajEwpgtj440mJlBls37G/zHMMe5DkA2TAxKldiHOR
fmHOtFKT3fnKFa6PWbwlLFnWIod4zheWrwV7E1coBhh+CA5SlgQANRFs7J8zxPznOtIK2O
cF2+/92cM0TijlBk8u5jnN44cUmk4V1nYboCVb0JD2B7yF9ZYP6IB03jt5GEZSfHHCrZP8
vCxMmXDxtAUAAAAXYWp2YW5lcnBASGVpbWRhbGwubG9jYWwBAgME
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1,15 @@
-----BEGIN DSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,9B6744BB12A8EA8F
pzZw5s3zDVHYdejZxdTpaRx00Yd1grbJe6mIJGvZRB0Jm0hKXoOX71PUI814mc5+
a5pzbyO98aciL/Eat5m3P692WQ0yOPMuphRnklsM3s4qrCjp2aRRbWvbyV/QV9bp
Xz2yYvNqU3WJC3UJIaFFMvRo/lC/Wsz9OvHSSl3LnsXXhiOCeaE32etoOYdlk9ro
N9NqDdaw28t9//iiHhuQK4afK6TZkU6DatFljJHILCC416Xh9+DDK9E+CDKzmlcw
jSwtzgFKEhgrT0XKoZR9LJZDolT1YpFy7M3cFRYIuYvJfuLcjxVEldJE900QlaJS
ybb6RxV6SRVwQYXTbIClcXes+oNJMv59DivAfajxECQC5sAynW/FnY1sz0igmz6D
scclJuJIbawqiuV/Lv6bvgzMa/ZXL4b9JeJPuQELa7tCpvj4fpNk1IiftYISlwoT
iG5pL8yLhPL4/fxGnKJzUPCA9mbwiloW2cAZZxTd+Utqmhemcl9gF0JGNR2XeYwS
3obEjbkqMF0WR3AcVZU9B5d9SKUaAzTp4vu5yZtNVEIaiVlnI3hMwWMs2Jgahswo
QF9MCPsRYsxLs7/u4a4qoQ==
-----END DSA PRIVATE KEY-----

View File

@@ -0,0 +1,38 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAze9G/3GB2UDA9WFtJpZ3F6gtpfvrBFq1WJSFAszcTYUWIyOFJhFR
Kt67tYeit2VQCYtQ3Gbn+Z3tWV7cCdVMNSQOMBnSsPvU8AG+Rrm5/lRKMILetpCwD3goYj
7nE1w9BQw4SFDgb9yscrXaySGALc2U9u0k7AYgxdfuy3d8JP9Q4PTQGiOquND5ronExAAk
ER5+bJyNbffi4GU3d/zzxOaYyTNKMPfq+ppVFDOaBwpObGfAwbkUdUWpuLMafyxUDPvX3j
Jlt2TNguQDdCRuAOzV55cIkypjVaxiNIhbnAQSoY8TdanYARddf+NnAq3qwvVFtWrk04vZ
qsBCKgRi99FTj8vnQj0EFYj/gtPQgYMq98KWXIjyj9Zr5nDpAuRQ8yoPXt79SQatH6mYML
fjzxvHBp8UQhhEPmTCw7gIsZEFBMA1njLJBy5G41BIlWcnVYgj0sxXMxrSmrUIkFWQOWcd
Bp9rFGkI8pIVs6ijS/KCG6JRHZB/bmzmVjYtG681AAAFiJrvSX6a70l+AAAAB3NzaC1yc2
EAAAGBAM3vRv9xgdlAwPVhbSaWdxeoLaX76wRatViUhQLM3E2FFiMjhSYRUSreu7WHordl
UAmLUNxm5/md7Vle3AnVTDUkDjAZ0rD71PABvka5uf5USjCC3raQsA94KGI+5xNcPQUMOE
hQ4G/crHK12skhgC3NlPbtJOwGIMXX7st3fCT/UOD00BojqrjQ+a6JxMQAJBEefmycjW33
4uBlN3f888TmmMkzSjD36vqaVRQzmgcKTmxnwMG5FHVFqbizGn8sVAz7194yZbdkzYLkA3
QkbgDs1eeXCJMqY1WsYjSIW5wEEqGPE3Wp2AEXXX/jZwKt6sL1RbVq5NOL2arAQioEYvfR
U4/L50I9BBWI/4LT0IGDKvfCllyI8o/Wa+Zw6QLkUPMqD17e/UkGrR+pmDC3488bxwafFE
IYRD5kwsO4CLGRBQTANZ4yyQcuRuNQSJVnJ1WII9LMVzMa0pq1CJBVkDlnHQafaxRpCPKS
FbOoo0vyghuiUR2Qf25s5lY2LRuvNQAAAAMBAAEAAAGABvaYR/rmkRoHbESnFC7yR/J/2K
T0BWmryBr9hGK48EYXwYhp8CeVvwVZA4Jaliju0+PKECnKnj4g0GzMs+hqc0GM2UOGREW/
pX3pmSqeh2MCPzGtpi6uRVeixe+qkJUF2y3WmVtiu2WSzy4m/7YKR4I0D0VlgjWS1h2/DV
I0+GtJqNGeV8Ps+eLXDnfKF3aJwapuS+3fOmCvYzcI8R20gGvrrqH1WEKJx3+AcPZttt86
V6AKfIJtlqmMW5pywuoUveYGDLCbg1oajqh7o06eTiFqZuCzbKjJUahzc1IvjsMRmP8rij
WVAVZdUV5NiLYjmPczxS12zcUCmPJo5geDQLpCJdfgFYWCk9nr08MCLXmD973S4egrfw33
+WMblW7R6vkHFUYK1Nfxe+Ume3mag+KbRJc0fYrO4Y+1BrhnsO5lqRHjkvl4jldYkAoqly
jnbk9PwWn4+u/FZ5mUyP7RCEK4INvXah/dG44GwRfY/OyoeQMM4P0BDedp5pGJn73hAAAA
wQDvs3FzKxF8uZPyDBZjEbn61m6oTVXE9PRl1kSzxD2wPqmZUPr1WtK/1ugWSMBoFTk72J
z5wXfaFVifz7U5EzQ23yZkBN2aL6jzu7H5OcxgZZVS3sL2WYfZ/lRphX0kHYBcM7ZChIbV
sDmheqE0wVTdTP809j1NX/sQOBShVg7vj20VTRYQs7SCBzsPEAmXE6a1haWBKfrZfhPN/3
xZJ162n2FA21LQjDcfHLWeSzSHjzdOK/3YSr/8o7EGqK7iTbYAAADBAPodvvOQvHm0k9Ki
7BzTQCCWCog0jR26rKeH5QlCi6fwmWBFR1vVjrqBRzhPUIH0sml6yOlYqpiKi0cNTZZ3dP
QuUU2U63AnyQyuSTAnOWy9mh9aAguWK4IdtuToH+rJCi4lyy4khFaeyzbbb6iD4HDR/sYF
AARMj/rAHypcnUSwkwSRiRoFy2w/h21roIocgBFfrVJUe1RDHTB9tiDFTqQ/WKWJFPfBSV
I4bqpWlFKFAIkbIaCEe2DIKHMp6ywNJwAAAMEA0sd18i4dOzDt0Sx+aYpK5tcx7G1Oen67
8WddT5bO63R4yQ4gCumiH2GQTaEnQIe9iTZ5hMQiwJJcfP9zI60g0RgMabicAX6TmW6ej8
4ZVfZhkQoCU15Ih4uIuCreSbwo/Q1FT48GA6UScqrDuSzaEenDuWKAv0NWap9B0Rro9eCb
ppaSE8QmSoojWAEAnOjaL/ig7j808xaDlNiMXKnmMdV4Lrj2OzyhqE5LpL7fShqhQ5CryY
l4Kj1BWsuKzJJDAAAAEWxhZ3Vub3ZAdW5pdC0xMzgxAQ==
-----END OPENSSH PRIVATE KEY-----

View File

@@ -15,10 +15,11 @@
*/
package com.hierynomus.sshj.backport;
import net.schmizz.sshj.common.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.nio.charset.Charset;
public class Jdk7HttpProxySocket extends Socket {
@@ -48,7 +49,7 @@ public class Jdk7HttpProxySocket extends Socket {
}
InetSocketAddress isa = (InetSocketAddress) endpoint;
String httpConnect = "CONNECT " + isa.getHostName() + ":" + isa.getPort() + " HTTP/1.0\n\n";
getOutputStream().write(httpConnect.getBytes(Charset.forName("UTF-8")));
getOutputStream().write(httpConnect.getBytes(IOUtils.UTF8));
checkAndFlushProxyResponse();
}
@@ -61,7 +62,7 @@ public class Jdk7HttpProxySocket extends Socket {
throw new SocketException("Empty response from proxy");
}
String proxyResponse = new String(tmpBuffer, 0, len, "UTF-8");
String proxyResponse = new String(tmpBuffer, 0, len, IOUtils.UTF8);
// Expecting HTTP/1.x 200 OK
if (proxyResponse.contains("200")) {

View File

@@ -0,0 +1,31 @@
/*
* 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.common;
public class KeyAlgorithm {
public static final String RSA = "RSA";
public static final String DSA = "DSA";
/** Elliptic curve signature key algorithm for use with BouncyCastle **/
public static final String ECDSA = "ECDSA";
/** General elliptic curve algorithm identifier for use with BouncyCastle **/
public static final String EC_BC = "EC";
/** General elliptic curve algorithm identifier for use with the Android Keystore **/
public static final String EC_KEYSTORE = "EC";
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C)2009 - SSHJ Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hierynomus.sshj.common;
import org.bouncycastle.openssl.EncryptionException;
import java.io.IOException;
/**
* Thrown when a key file could not be decrypted correctly, e.g. if its checkInts differed in the case of an OpenSSH
* key file.
*/
@SuppressWarnings("serial")
public class KeyDecryptionFailedException extends IOException {
public static final String MESSAGE = "Decryption of the key failed. A supplied passphrase may be incorrect.";
public KeyDecryptionFailedException() {
super(MESSAGE);
}
public KeyDecryptionFailedException(EncryptionException cause) {
super(MESSAGE, cause);
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.key;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.common.KeyType;
import net.schmizz.sshj.signature.Signature;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
public class BaseKeyAlgorithm implements KeyAlgorithm {
private final String keyAlgorithm;
private final Factory.Named<Signature> signature;
private final KeyType keyFormat;
public BaseKeyAlgorithm(String keyAlgorithm, Factory.Named<Signature> signature, KeyType keyFormat) {
this.keyAlgorithm = keyAlgorithm;
this.signature = signature;
this.keyFormat = keyFormat;
}
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
keyFormat.putPubKeyIntoBuffer(pk, buf);
}
@Override
public PublicKey readPubKeyFromBuffer(Buffer<?> buf) throws GeneralSecurityException {
return keyFormat.readPubKeyFromBuffer(buf);
}
@Override
public String getKeyAlgorithm() {
return keyAlgorithm;
}
@Override
public KeyType getKeyFormat() {
return keyFormat;
}
@Override
public Signature newSignature() {
return this.signature.create();
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.key;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.common.KeyType;
import net.schmizz.sshj.signature.Signature;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
/**
* In [RFC4252], the concept "public key algorithm" is used to establish
* a relationship between one algorithm name, and:
* <p>
* A. procedures used to generate and validate a private/public
* keypair;
* B. a format used to encode a public key; and
* C. procedures used to calculate, encode, and verify a signature.
*/
public interface KeyAlgorithm {
PublicKey readPubKeyFromBuffer(Buffer<?> buf) throws GeneralSecurityException;
void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf);
String getKeyAlgorithm();
KeyType getKeyFormat();
Signature newSignature();
}

View File

@@ -0,0 +1,65 @@
/*
* 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.key;
import com.hierynomus.sshj.signature.SignatureEdDSA;
import net.schmizz.sshj.common.KeyType;
import net.schmizz.sshj.signature.Signature;
import net.schmizz.sshj.signature.SignatureDSA;
import net.schmizz.sshj.signature.SignatureECDSA;
import net.schmizz.sshj.signature.SignatureRSA;
import java.util.Arrays;
import java.util.List;
public class KeyAlgorithms {
public static List<String> SSH_RSA_SHA2_ALGORITHMS = Arrays.asList("rsa-sha2-512", "rsa-sha2-256");
public static Factory SSHRSA() { return new Factory("ssh-rsa", new SignatureRSA.FactorySSHRSA(), KeyType.RSA); }
public static Factory SSHRSACertV01() { return new Factory("ssh-rsa-cert-v01@openssh.com", new SignatureRSA.FactoryCERT(), KeyType.RSA_CERT); }
public static Factory RSASHA256() { return new Factory("rsa-sha2-256", new SignatureRSA.FactoryRSASHA256(), KeyType.RSA); }
public static Factory RSASHA512() { return new Factory("rsa-sha2-512", new SignatureRSA.FactoryRSASHA512(), KeyType.RSA); }
public static Factory SSHDSA() { return new Factory(KeyType.DSA.toString(), new SignatureDSA.Factory(), KeyType.DSA); }
public static Factory SSHDSSCertV01() { return new Factory(KeyType.DSA_CERT.toString(), new SignatureDSA.Factory(), KeyType.DSA_CERT); }
public static Factory ECDSASHANistp256() { return new Factory(KeyType.ECDSA256.toString(), new SignatureECDSA.Factory256(), KeyType.ECDSA256); }
public static Factory ECDSASHANistp384() { return new Factory(KeyType.ECDSA384.toString(), new SignatureECDSA.Factory384(), KeyType.ECDSA384); }
public static Factory ECDSASHANistp521() { return new Factory(KeyType.ECDSA521.toString(), new SignatureECDSA.Factory521(), KeyType.ECDSA521); }
public static Factory EdDSA25519() { return new Factory(KeyType.ED25519.toString(), new SignatureEdDSA.Factory(), KeyType.ED25519); }
public static class Factory implements net.schmizz.sshj.common.Factory.Named<KeyAlgorithm> {
private final String algorithmName;
private final Named<Signature> signatureFactory;
private final KeyType keyType;
public Factory(String algorithmName, Named<Signature> signatureFactory, KeyType keyType) {
this.algorithmName = algorithmName;
this.signatureFactory = signatureFactory;
this.keyType = keyType;
}
@Override
public String getName() {
return algorithmName;
}
@Override
public KeyAlgorithm create() {
return new BaseKeyAlgorithm(algorithmName, signatureFactory, keyType);
}
}
}

View File

@@ -27,12 +27,13 @@ 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.
*/
@SuppressWarnings("serial")
public class Ed25519PublicKey extends EdDSAPublicKey {
public Ed25519PublicKey(EdDSAPublicKeySpec spec) {
super(spec);
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("Ed25519");
if (!spec.getParams().getCurve().equals(ed25519.getCurve())) {
throw new SSHRuntimeException("Cannot create Ed25519 Public Key from wrong spec");
}

View File

@@ -16,14 +16,16 @@
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.AbstractSignature;
import net.schmizz.sshj.signature.Signature;
import java.security.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
public class SignatureEdDSA implements Signature {
public class SignatureEdDSA extends AbstractSignature {
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Signature> {
@Override
@@ -37,54 +39,18 @@ public class SignatureEdDSA implements Signature {
}
}
final EdDSAEngine engine;
SignatureEdDSA() {
super(getEngine(), KeyType.ED25519.toString());
}
protected SignatureEdDSA() {
private static EdDSAEngine getEngine() {
try {
engine = new EdDSAEngine(MessageDigest.getInstance("SHA-512"));
return 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;
@@ -93,17 +59,9 @@ public class SignatureEdDSA implements 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);
return signature.verify(extractSig(sig, "ssh-ed25519"));
} catch (SignatureException e) {
throw new SSHRuntimeException(e);
} catch (Buffer.BufferException e) {
throw new SSHRuntimeException(e);
}
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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) throws Buffer.BufferException {
byte[] bytes = new byte[lineBuffer.available()];
lineBuffer.readRawBytes(bytes);
String header = new String(bytes, 0, bytes.length - 1);
log.debug("Received header: {}", header);
}
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.info("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.info("Will treat the identification of this server '{}' leniently", ident);
return ident;
}
// 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

@@ -19,23 +19,46 @@ import net.schmizz.sshj.transport.cipher.BlockCipher;
import net.schmizz.sshj.transport.cipher.Cipher;
/**
* All BlockCiphers supported by SSH according to the following RFCs
* 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
* <ul>
* <li>https://tools.ietf.org/html/rfc4344#section-3.1</li>
* <li>https://tools.ietf.org/html/rfc4253#section-6.3</li>
* <li>TODO: https://tools.ietf.org/html/rfc5647</li>
* </ul>
*
* 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.
* Some of the Ciphers are still implemented in net.schmizz.sshj.transport.cipher.*. These are deprecated and scheduled to be removed.
*/
@SuppressWarnings("PMD.MethodNamingConventions")
public class BlockCiphers {
public static final String COUNTER_MODE = "CTR";
public static final String CIPHER_BLOCK_CHAINING_MODE = "CBC";
public static Factory AES128CTR() {
return new Factory(16, 128, "aes128-ctr", "AES", COUNTER_MODE);
}
public static Factory AES192CTR() {
return new Factory(16, 192, "aes192-ctr", "AES", COUNTER_MODE);
}
public static Factory AES256CTR() {
return new Factory(16, 256, "aes256-ctr", "AES", COUNTER_MODE);
}
public static Factory AES128CBC() {
return new Factory(16, 128, "aes128-cbc", "AES", CIPHER_BLOCK_CHAINING_MODE);
}
public static Factory AES192CBC() {
return new Factory(16, 192, "aes192-cbc", "AES", CIPHER_BLOCK_CHAINING_MODE);
}
public static Factory AES256CBC() {
return new Factory(16, 256, "aes256-cbc", "AES", CIPHER_BLOCK_CHAINING_MODE);
}
public static Factory BlowfishCTR() {
return new Factory(8, 256, "blowfish-ctr", "Blowfish", COUNTER_MODE);
}
public static Factory BlowfishCBC() {
return new Factory(8, 128, "blowfish-cbc", "Blowfish", CIPHER_BLOCK_CHAINING_MODE);
}
public static Factory Twofish128CTR() {
return new Factory(16, 128, "twofish128-ctr", "Twofish", COUNTER_MODE);
}
@@ -90,6 +113,9 @@ public class BlockCiphers {
public static Factory TripleDESCTR() {
return new Factory(8, 192, "3des-ctr", "DESede", COUNTER_MODE);
}
public static Factory TripleDESCBC() {
return new Factory(8, 192, "3des-cbc", "DESede", CIPHER_BLOCK_CHAINING_MODE);
}
/** Named factory for BlockCipher */
public static class Factory

View File

@@ -25,6 +25,7 @@ import static com.hierynomus.sshj.transport.cipher.BlockCiphers.COUNTER_MODE;
*
* - http://tools.ietf.org/id/draft-kanno-secsh-camellia-01.txt
*/
@SuppressWarnings("PMD.MethodNamingConventions")
public class ExtendedBlockCiphers {
public static BlockCiphers.Factory Camellia128CTR() {
return new BlockCiphers.Factory(16, 128, "camellia128-ctr", "Camellia", COUNTER_MODE);

View File

@@ -0,0 +1,164 @@
/*
* 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.common.SSHRuntimeException;
import net.schmizz.sshj.transport.cipher.BaseCipher;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
public class GcmCipher extends BaseCipher {
protected int authSize;
protected Mode mode;
protected boolean initialized;
protected CounterGCMParameterSpec parameters;
protected SecretKey secretKey;
public GcmCipher(int ivsize, int authSize, int bsize, String algorithm, String transformation) {
super(ivsize, bsize, algorithm, transformation);
this.authSize = authSize;
}
@Override
public int getAuthenticationTagSize() {
return authSize;
}
protected Cipher getInitializedCipherInstance() throws GeneralSecurityException {
if (!initialized) {
cipher.init(mode == Mode.Encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, secretKey, parameters);
initialized = true;
}
return cipher;
}
@Override
protected void initCipher(Cipher cipher, Mode mode, byte[] key, byte[] iv) throws InvalidKeyException, InvalidAlgorithmParameterException {
this.mode = mode;
this.secretKey = getKeySpec(key);
this.parameters = new CounterGCMParameterSpec(getAuthenticationTagSize() * Byte.SIZE, iv);
cipher.init(getMode(mode), secretKey, parameters);
initialized = true;
}
@Override
public void updateAAD(byte[] data, int offset, int length) {
try {
Cipher cipher = getInitializedCipherInstance();
cipher.updateAAD(data, offset, length);
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException("Error updating data through cipher", e);
}
}
@Override
public void update(byte[] input, int inputOffset, int inputLen) {
if (mode == Mode.Decrypt) {
inputLen += getAuthenticationTagSize();
}
try {
Cipher cipher = getInitializedCipherInstance();
cipher.doFinal(input, inputOffset, inputLen, input, inputOffset);
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException("Error updating data through cipher", e);
}
/*
* As the RFC stated, the IV used in AES-GCM cipher for SSH is a 4-byte constant plus a 8-byte invocation
* counter. After cipher.doFinal() is called, IV invocation counter is increased by 1, and changes to the IV
* requires reinitializing the cipher, so initialized have to be false here, for the next invocation.
*
* Refer to RFC5647, Section 7.1
*/
parameters.incrementCounter();
initialized = false;
}
/**
* Algorithm parameters for AES/GCM that assumes the IV uses an 8-byte counter field as its most significant bytes.
*/
protected static class CounterGCMParameterSpec extends GCMParameterSpec {
protected final byte[] iv;
protected CounterGCMParameterSpec(int tLen, byte[] src) {
super(tLen, src);
if (src.length != 12) {
throw new IllegalArgumentException("GCM nonce must be 12 bytes, but given len=" + src.length);
}
iv = src.clone();
}
protected void incrementCounter() {
int off = iv.length - 8;
long counter = getLong(iv, off, 8);
putLong(addExact(counter, 1L), iv, off, 8);
}
@Override
public byte[] getIV() {
// JCE implementation of GCM will complain if the reference doesn't change between inits
return iv.clone();
}
static long addExact(long var0, long var2) {
long var4 = var0 + var2;
if (((var0 ^ var4) & (var2 ^ var4)) < 0L) {
throw new ArithmeticException("long overflow");
} else {
return var4;
}
}
static long getLong(byte[] buf, int off, int len) {
if (len < 8) {
throw new IllegalArgumentException("Not enough data for a long: required=8, available=" + len);
}
long l = (long) buf[off] << 56;
l |= ((long) buf[off + 1] & 0xff) << 48;
l |= ((long) buf[off + 2] & 0xff) << 40;
l |= ((long) buf[off + 3] & 0xff) << 32;
l |= ((long) buf[off + 4] & 0xff) << 24;
l |= ((long) buf[off + 5] & 0xff) << 16;
l |= ((long) buf[off + 6] & 0xff) << 8;
l |= (long) buf[off + 7] & 0xff;
return l;
}
static int putLong(long value, byte[] buf, int off, int len) {
if (len < 8) {
throw new IllegalArgumentException("Not enough data for a long: required=8, available=" + len);
}
buf[off] = (byte) (value >> 56);
buf[off + 1] = (byte) (value >> 48);
buf[off + 2] = (byte) (value >> 40);
buf[off + 3] = (byte) (value >> 32);
buf[off + 4] = (byte) (value >> 24);
buf[off + 5] = (byte) (value >> 16);
buf[off + 6] = (byte) (value >> 8);
buf[off + 7] = (byte) value;
return 8;
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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;
public class GcmCiphers {
public static final String GALOIS_COUNTER_MODE = "GCM";
public static Factory AES128GCM() {
return new Factory(12, 16, 128, "aes128-gcm@openssh.com", "AES", GALOIS_COUNTER_MODE);
}
public static Factory AES256GCM() {
return new Factory(12, 16, 256, "aes256-gcm@openssh.com", "AES", GALOIS_COUNTER_MODE);
}
/** Named factory for BlockCipher */
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
private int keysize;
private int authSize;
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 authSize, int keysize, String name, String cipher, String mode) {
this.name = name;
this.keysize = keysize;
this.cipher = cipher;
this.mode = mode;
this.ivsize = ivsize;
this.authSize = authSize;
}
@Override
public Cipher create() {
return new GcmCipher(ivsize, authSize, keysize / 8, cipher, cipher + "/" + mode + "/NoPadding");
}
@Override
public String getName() {
return name;
}
@Override
public String toString() {
return getName();
}
}
}

View File

@@ -19,7 +19,6 @@ import net.schmizz.sshj.transport.cipher.BaseCipher;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.SecureRandom;
public class StreamCipher extends BaseCipher {
@@ -29,6 +28,6 @@ public class StreamCipher extends BaseCipher {
@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());
cipher.init(getMode(mode), getKeySpec(key));
}
}

View File

@@ -23,6 +23,7 @@ import net.schmizz.sshj.transport.cipher.Cipher;
* - https://tools.ietf.org/html/rfc4253#section-6.3
* - https://tools.ietf.org/html/rfc4345
*/
@SuppressWarnings("PMD.MethodNamingConventions")
public class StreamCiphers {
public static Factory Arcfour() {

View File

@@ -0,0 +1,44 @@
/*
* 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.kex;
import net.schmizz.sshj.transport.digest.Digest;
import net.schmizz.sshj.transport.kex.AbstractDHG;
import net.schmizz.sshj.transport.kex.DH;
import net.schmizz.sshj.transport.kex.DHBase;
import javax.crypto.spec.DHParameterSpec;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
/**
*
*/
public class DHG extends AbstractDHG {
private BigInteger group;
private BigInteger generator;
public DHG(BigInteger group, BigInteger generator, Digest digest) {
super(new DH(), digest);
this.group = group;
this.generator = generator;
}
@Override
protected void initDH(DHBase dh) throws GeneralSecurityException {
dh.init(new DHParameterSpec(group, generator), trans.getConfig().getRandomFactory());
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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.kex;
import net.schmizz.sshj.transport.digest.Digest;
import net.schmizz.sshj.transport.digest.SHA1;
import net.schmizz.sshj.transport.digest.SHA256;
import net.schmizz.sshj.transport.digest.SHA512;
import net.schmizz.sshj.transport.kex.KeyExchange;
import java.math.BigInteger;
import static net.schmizz.sshj.transport.kex.DHGroupData.*;
/**
* Factory methods for Diffie Hellman KEX algorithms based on MODP groups / Oakley Groups
*
* - https://tools.ietf.org/html/rfc4253
* - https://tools.ietf.org/html/draft-ietf-curdle-ssh-modp-dh-sha2-01
*/
@SuppressWarnings("PMD.MethodNamingConventions")
public class DHGroups {
public static DHGroups.Factory Group1SHA1() {
return new DHGroups.Factory("diffie-hellman-group1-sha1", P1, G, new SHA1.Factory());
}
public static DHGroups.Factory Group14SHA1() {
return new DHGroups.Factory("diffie-hellman-group14-sha1", P14, G, new SHA1.Factory());
}
public static DHGroups.Factory Group14SHA256() {
return new DHGroups.Factory("diffie-hellman-group14-sha256", P14, G, new SHA256.Factory());
}
public static DHGroups.Factory Group15SHA512() {
return new DHGroups.Factory("diffie-hellman-group15-sha512", P15, G, new SHA512.Factory());
}
public static DHGroups.Factory Group16SHA512() {
return new DHGroups.Factory("diffie-hellman-group16-sha512", P16, G, new SHA512.Factory());
}
public static DHGroups.Factory Group17SHA512() {
return new DHGroups.Factory("diffie-hellman-group17-sha512", P17, G, new SHA512.Factory());
}
public static DHGroups.Factory Group18SHA512() {
return new DHGroups.Factory("diffie-hellman-group18-sha512", P18, G, new SHA512.Factory());
}
/**
* Named factory for DHG1 key exchange
*/
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<KeyExchange> {
private String name;
private BigInteger group;
private BigInteger generator;
private Factory.Named<Digest> digestFactory;
public Factory(String name, BigInteger group, BigInteger generator, Named<Digest> digestFactory) {
this.name = name;
this.group = group;
this.generator = generator;
this.digestFactory = digestFactory;
}
@Override
public KeyExchange create() {
return new DHG(group, generator, digestFactory.create());
}
@Override
public String getName() {
return name;
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.kex;
import net.schmizz.sshj.transport.kex.KeyExchange;
/**
* Stub kex algorithm factory that indicates support for SSH2_MSG_EXT_INFO.
* Some servers will not send `rsa-sha2-*` signatures if the client doesn't indicate support.
*
* Note: Since the server sends `ext-info-s` to indicate support, this fake kex algorithm is never negotiated.
*/
public class ExtInfoClientFactory implements net.schmizz.sshj.common.Factory.Named<KeyExchange> {
@Override
public String getName() {
return "ext-info-c";
}
@Override
public KeyExchange create() {
return null;
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.kex;
import net.schmizz.sshj.transport.digest.SHA256;
import net.schmizz.sshj.transport.digest.SHA384;
import net.schmizz.sshj.transport.digest.SHA512;
import static net.schmizz.sshj.transport.kex.DHGroupData.*;
/**
* Set of KEX methods that are not in official RFCs but are supported by some SSH servers.
*/
@SuppressWarnings("PMD.MethodNamingConventions")
public class ExtendedDHGroups {
public static DHGroups.Factory Group14SHA256AtSSH() {
return new DHGroups.Factory("diffie-hellman-group14-sha256@ssh.com", P14, G, new SHA256.Factory());
}
public static DHGroups.Factory Group15SHA256() {
return new DHGroups.Factory("diffie-hellman-group15-sha256", P15, G, new SHA256.Factory());
}
public static DHGroups.Factory Group15SHA256AtSSH() {
return new DHGroups.Factory("diffie-hellman-group15-sha256@ssh.com", P15, G, new SHA256.Factory());
}
public static DHGroups.Factory Group15SHA384AtSSH() {
return new DHGroups.Factory("diffie-hellman-group15-sha384@ssh.com", P15, G, new SHA384.Factory());
}
public static DHGroups.Factory Group16SHA256() {
return new DHGroups.Factory("diffie-hellman-group16-sha256", P16, G, new SHA256.Factory());
}
public static DHGroups.Factory Group16SHA384AtSSH() {
return new DHGroups.Factory("diffie-hellman-group16-sha384@ssh.com", P16, G, new SHA384.Factory());
}
public static DHGroups.Factory Group16SHA512AtSSH() {
return new DHGroups.Factory("diffie-hellman-group16-sha512@ssh.com", P16, G, new SHA512.Factory());
}
public static DHGroups.Factory Group18SHA512AtSSH() {
return new DHGroups.Factory("diffie-hellman-group18-sha512@ssh.com", P18, G, new SHA512.Factory());
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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.mac;
import net.schmizz.sshj.transport.mac.BaseMAC;
import net.schmizz.sshj.transport.mac.MAC;
@SuppressWarnings("PMD.MethodNamingConventions")
public class Macs {
public static Factory HMACMD5() {
return new Factory("hmac-md5", "HmacMD5", 16, 16, false);
}
public static Factory HMACMD596() {
return new Factory("hmac-md5-96", "HmacMD5", 12, 16, false);
}
public static Factory HMACMD5Etm() {
return new Factory("hmac-md5-etm@openssh.com", "HmacMD5", 16, 16, true);
}
public static Factory HMACMD596Etm() {
return new Factory("hmac-md5-96-etm@openssh.com", "HmacMD5", 12, 16, true);
}
public static Factory HMACRIPEMD160() {
return new Factory("hmac-ripemd160", "HMACRIPEMD160", 20, 20, false);
}
public static Factory HMACRIPEMD16096() {
return new Factory("hmac-ripemd160-96", "HMACRIPEMD160", 12, 20, false);
}
public static Factory HMACRIPEMD160Etm() {
return new Factory("hmac-ripemd160-etm@openssh.com", "HMACRIPEMD160", 20, 20, true);
}
public static Factory HMACRIPEMD160OpenSsh() {
return new Factory("hmac-ripemd160@openssh.com", "HMACRIPEMD160", 20, 20, false);
}
public static Factory HMACSHA1() {
return new Factory("hmac-sha1", "HmacSHA1", 20, 20, false);
}
public static Factory HMACSHA196() {
return new Factory("hmac-sha1-96", "HmacSHA1", 12, 20, false);
}
public static Factory HMACSHA1Etm() {
return new Factory("hmac-sha1-etm@openssh.com", "HmacSHA1", 20, 20, true);
}
public static Factory HMACSHA196Etm() {
return new Factory("hmac-sha1-96@openssh.com", "HmacSHA1", 12, 20, true);
}
public static Factory HMACSHA2256() {
return new Factory("hmac-sha2-256", "HmacSHA256", 32, 32, false);
}
public static Factory HMACSHA2256Etm() {
return new Factory("hmac-sha2-256-etm@openssh.com", "HmacSHA256", 32, 32, true);
}
public static Factory HMACSHA2512() {
return new Factory("hmac-sha2-512", "HmacSHA512", 64, 64, false);
}
public static Factory HMACSHA2512Etm() {
return new Factory("hmac-sha2-512-etm@openssh.com", "HmacSHA512", 64, 64, true);
}
public static class Factory implements net.schmizz.sshj.common.Factory.Named<MAC> {
private String name;
private String algorithm;
private int bSize;
private int defBSize;
private final boolean etm;
public Factory(String name, String algorithm, int bSize, int defBSize, boolean etm) {
this.name = name;
this.algorithm = algorithm;
this.bSize = bSize;
this.defBSize = defBSize;
this.etm = etm;
}
@Override
public String getName() {
return name;
}
@Override
public BaseMAC create() {
return new BaseMAC(algorithm, bSize, defBSize, etm);
}
}
}

View File

@@ -0,0 +1,152 @@
/*
* 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.verification;
import net.schmizz.sshj.common.Base64;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.transport.mac.MAC;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import com.hierynomus.sshj.transport.mac.Macs;
public class KnownHostMatchers {
public static HostMatcher createMatcher(String hostEntry) throws SSHException {
if (hostEntry.contains(",")) {
return new AnyHostMatcher(hostEntry);
}
if (hostEntry.startsWith("!")) {
return new NegateHostMatcher(hostEntry);
}
if (hostEntry.startsWith("|1|")) {
return new HashedHostMatcher(hostEntry);
}
if (hostEntry.contains("*") || hostEntry.contains("?")) {
return new WildcardHostMatcher(hostEntry);
}
return new EquiHostMatcher(hostEntry);
}
public interface HostMatcher {
boolean match(String hostname) throws IOException;
}
private static class EquiHostMatcher implements HostMatcher {
private String host;
public EquiHostMatcher(String host) {
this.host = host;
}
@Override
public boolean match(String hostname) {
return host.equals(hostname);
}
}
private static class HashedHostMatcher implements HostMatcher {
private final MAC sha1 = Macs.HMACSHA1().create();
private final String hash;
private final String salt;
private byte[] saltyBytes;
HashedHostMatcher(String hash) throws SSHException {
this.hash = hash;
final String[] hostParts = hash.split("\\|");
if (hostParts.length != 4) {
throw new SSHException("Unrecognized format for hashed hostname");
}
salt = hostParts[2];
}
@Override
public boolean match(String hostname) throws IOException {
return hash.equals(hashHost(hostname));
}
private String hashHost(String host) throws IOException {
sha1.init(getSaltyBytes());
return "|1|" + salt + "|" + Base64.encodeBytes(sha1.doFinal(host.getBytes(IOUtils.UTF8)));
}
private byte[] getSaltyBytes() throws IOException {
if (saltyBytes == null) {
saltyBytes = Base64.decode(salt);
}
return saltyBytes;
}
}
private static class AnyHostMatcher implements HostMatcher {
private final List<HostMatcher> matchers;
AnyHostMatcher(String hostEntry) throws SSHException {
matchers = new ArrayList<HostMatcher>();
for (String subEntry : hostEntry.split(",")) {
matchers.add(KnownHostMatchers.createMatcher(subEntry));
}
}
@Override
public boolean match(String hostname) throws IOException {
for (HostMatcher matcher : matchers) {
if (matcher.match(hostname)) {
return true;
}
}
return false;
}
}
private static class NegateHostMatcher implements HostMatcher {
private final HostMatcher matcher;
NegateHostMatcher(String hostEntry) throws SSHException {
this.matcher = createMatcher(hostEntry.substring(1));
}
@Override
public boolean match(String hostname) throws IOException {
return !matcher.match(hostname);
}
}
private static class WildcardHostMatcher implements HostMatcher {
private final Pattern pattern;
public WildcardHostMatcher(String hostEntry) {
this.pattern = Pattern.compile("^" + hostEntry.replace("[", "\\[").replace("]", "\\]").replace(".", "\\.").replace("*", ".*").replace("?", ".") + "$");
}
@Override
public boolean match(String hostname) throws IOException {
return pattern.matcher(hostname).matches();
}
@Override
public String toString() {
return "WildcardHostMatcher[" + pattern + ']';
}
}
}

View File

@@ -0,0 +1,258 @@
package com.hierynomus.sshj.userauth.certificate;
import java.math.BigInteger;
import java.security.PublicKey;
import java.util.Date;
import java.util.List;
import java.util.Map;
/*
* 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.
*/
/**
* Certificate wrapper for public keys, created to help implement
* protocol described here:
*
* https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD
*
* Consumed primarily by net.shmizz.sshj.common.KeyType
*
* @param <T> inner public key type
*/
public class Certificate<T extends PublicKey> implements PublicKey {
private static final long serialVersionUID = 1L;
private final T publicKey;
private final byte[] nonce;
private final BigInteger serial;
private final long type;
private final String id;
private final List<String> validPrincipals;
private final Date validAfter;
private final Date validBefore;
private final Map<String, String> critOptions;
private final Map<String, String> extensions;
private final byte[] signatureKey;
private final byte[] signature;
Certificate(Builder<T> builder) {
this.publicKey = builder.getPublicKey();
this.nonce = builder.getNonce();
this.serial = builder.getSerial();
this.type = builder.getType();
this.id = builder.getId();
this.validPrincipals = builder.getValidPrincipals();
this.validAfter = builder.getValidAfter();
this.validBefore = builder.getValidBefore();
this.critOptions = builder.getCritOptions();
this.extensions = builder.getExtensions();
this.signatureKey = builder.getSignatureKey();
this.signature = builder.getSignature();
}
public static <P extends PublicKey> Builder<P> getBuilder() {
return new Builder<P>();
}
public byte[] getNonce() {
return nonce;
}
public BigInteger getSerial() {
return serial;
}
public long getType() {
return type;
}
public String getId() {
return id;
}
public List<String> getValidPrincipals() {
return validPrincipals;
}
public Date getValidAfter() {
return validAfter;
}
public Date getValidBefore() {
return validBefore;
}
public Map<String, String> getCritOptions() {
return critOptions;
}
public Map<String, String> getExtensions() {
return extensions;
}
public byte[] getSignatureKey() {
return signatureKey;
}
public byte[] getSignature() {
return signature;
}
public T getKey() {
return publicKey;
}
@Override
public byte[] getEncoded() {
return publicKey.getEncoded();
}
@Override
public String getAlgorithm() {
return publicKey.getAlgorithm();
}
@Override
public String getFormat() {
return publicKey.getFormat();
}
public static class Builder<T extends PublicKey> {
private T publicKey;
private byte[] nonce;
private BigInteger serial;
private long type;
private String id;
private List<String> validPrincipals;
private Date validAfter;
private Date validBefore;
private Map<String, String> critOptions;
private Map<String, String> extensions;
private byte[] signatureKey;
private byte[] signature;
public Certificate<T> build() {
return new Certificate<T>(this);
}
public T getPublicKey() {
return publicKey;
}
public Builder<T> publicKey(T publicKey) {
this.publicKey = publicKey;
return this;
}
public byte[] getNonce() {
return nonce;
}
public Builder<T> nonce(byte[] nonce) {
this.nonce = nonce;
return this;
}
public BigInteger getSerial() {
return serial;
}
public Builder<T> serial(BigInteger serial) {
this.serial = serial;
return this;
}
public long getType() {
return type;
}
public Builder<T> type(long type) {
this.type = type;
return this;
}
public String getId() {
return id;
}
public Builder<T> id(String id) {
this.id = id;
return this;
}
public List<String> getValidPrincipals() {
return validPrincipals;
}
public Builder<T> validPrincipals(List<String> validPrincipals) {
this.validPrincipals = validPrincipals;
return this;
}
public Date getValidAfter() {
return validAfter;
}
public Builder<T> validAfter(Date validAfter) {
this.validAfter = validAfter;
return this;
}
public Date getValidBefore() {
return validBefore;
}
public Builder<T> validBefore(Date validBefore) {
this.validBefore = validBefore;
return this;
}
public Map<String, String> getCritOptions() {
return critOptions;
}
public Builder<T> critOptions(Map<String, String> critOptions) {
this.critOptions = critOptions;
return this;
}
public Map<String, String> getExtensions() {
return extensions;
}
public Builder<T> extensions(Map<String, String> extensions) {
this.extensions = extensions;
return this;
}
public byte[] getSignatureKey() {
return signatureKey;
}
public Builder<T> signatureKey(byte[] signatureKey) {
this.signatureKey = signatureKey;
return this;
}
public byte[] getSignature() {
return signature;
}
public Builder<T> signature(byte[] signature) {
this.signature = signature;
return this;
}
}
}

View File

@@ -0,0 +1,258 @@
/*
* Copyright (C)2009 - SSHJ Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hierynomus.sshj.userauth.keyprovider;
import com.hierynomus.sshj.common.KeyAlgorithm;
import com.hierynomus.sshj.common.KeyDecryptionFailedException;
import com.hierynomus.sshj.transport.cipher.BlockCiphers;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
import net.schmizz.sshj.common.*;
import net.schmizz.sshj.common.Buffer.PlainBuffer;
import net.schmizz.sshj.transport.cipher.Cipher;
import net.schmizz.sshj.userauth.keyprovider.BaseFileKeyProvider;
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
import net.schmizz.sshj.userauth.keyprovider.KeyFormat;
import org.bouncycastle.asn1.nist.NISTNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.mindrot.jbcrypt.BCrypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.util.Arrays;
/**
* Reads a key file in the new OpenSSH format.
* The format is described in the following document: https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
*/
public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
private static final Logger logger = LoggerFactory.getLogger(OpenSSHKeyV1KeyFile.class);
private static final String BEGIN = "-----BEGIN ";
private static final String END = "-----END ";
private static final byte[] AUTH_MAGIC = "openssh-key-v1\0".getBytes();
public static final String OPENSSH_PRIVATE_KEY = "OPENSSH PRIVATE KEY-----";
public static final String BCRYPT = "bcrypt";
public static class Factory
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
@Override
public FileKeyProvider create() {
return new OpenSSHKeyV1KeyFile();
}
@Override
public String getName() {
return KeyFormat.OpenSSHv1.name();
}
}
@Override
protected KeyPair readKeyPair() throws IOException {
BufferedReader reader = new BufferedReader(resource.getReader());
try {
if (!checkHeader(reader)) {
throw new IOException("This key is not in 'openssh-key-v1' format");
}
String keyFile = readKeyFile(reader);
byte[] decode = Base64.decode(keyFile);
PlainBuffer keyBuffer = new PlainBuffer(decode);
return readDecodedKeyPair(keyBuffer);
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e);
} finally {
IOUtils.closeQuietly(reader);
}
}
private KeyPair readDecodedKeyPair(final PlainBuffer keyBuffer) throws IOException, GeneralSecurityException {
byte[] bytes = new byte[AUTH_MAGIC.length];
keyBuffer.readRawBytes(bytes); // byte[] AUTH_MAGIC
if (!ByteArrayUtils.equals(bytes, 0, AUTH_MAGIC, 0, AUTH_MAGIC.length)) {
throw new IOException("This key does not contain the 'openssh-key-v1' format magic header");
}
String cipherName = keyBuffer.readString(); // string ciphername
String kdfName = keyBuffer.readString(); // string kdfname
byte[] kdfOptions = keyBuffer.readBytes(); // string kdfoptions
int nrKeys = keyBuffer.readUInt32AsInt(); // int number of keys N; Should be 1
if (nrKeys != 1) {
throw new IOException("We don't support having more than 1 key in the file (yet).");
}
PublicKey publicKey = readPublicKey(new PlainBuffer(keyBuffer.readBytes())); // string publickey1
PlainBuffer privateKeyBuffer = new PlainBuffer(keyBuffer.readBytes()); // string (possibly) encrypted, padded list of private keys
if ("none".equals(cipherName)) {
logger.debug("Reading unencrypted keypair");
return readUnencrypted(privateKeyBuffer, publicKey);
} else {
logger.info("Keypair is encrypted with: " + cipherName + ", " + kdfName + ", " + Arrays.toString(kdfOptions));
while (true) {
PlainBuffer decryptionBuffer = new PlainBuffer(privateKeyBuffer);
PlainBuffer decrypted = decryptBuffer(decryptionBuffer, cipherName, kdfName, kdfOptions);
try {
return readUnencrypted(decrypted, publicKey);
} catch (KeyDecryptionFailedException e) {
if (pwdf == null || !pwdf.shouldRetry(resource))
throw e;
}
}
// throw new IOException("Cannot read encrypted keypair with " + cipherName + " yet.");
}
}
private PlainBuffer decryptBuffer(PlainBuffer privateKeyBuffer, String cipherName, String kdfName, byte[] kdfOptions) throws IOException {
Cipher cipher = createCipher(cipherName);
initializeCipher(kdfName, kdfOptions, cipher);
byte[] array = privateKeyBuffer.array();
cipher.update(array, 0, privateKeyBuffer.available());
return new PlainBuffer(array);
}
private void initializeCipher(String kdfName, byte[] kdfOptions, Cipher cipher) throws Buffer.BufferException {
if (kdfName.equals(BCRYPT)) {
PlainBuffer opts = new PlainBuffer(kdfOptions);
byte[] passphrase = new byte[0];
if (pwdf != null) {
CharBuffer charBuffer = CharBuffer.wrap(pwdf.reqPassword(null));
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
passphrase = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
Arrays.fill(charBuffer.array(), '\u0000');
Arrays.fill(byteBuffer.array(), (byte) 0);
}
byte[] keyiv = new byte[48];
new BCrypt().pbkdf(passphrase, opts.readBytes(), opts.readUInt32AsInt(), keyiv);
Arrays.fill(passphrase, (byte) 0);
byte[] key = Arrays.copyOfRange(keyiv, 0, 32);
byte[] iv = Arrays.copyOfRange(keyiv, 32, 48);
cipher.init(Cipher.Mode.Decrypt, key, iv);
} else {
throw new IllegalStateException("No support for KDF '" + kdfName + "'.");
}
}
private Cipher createCipher(String cipherName) {
if (cipherName.equals(BlockCiphers.AES256CTR().getName())) {
return BlockCiphers.AES256CTR().create();
} else if (cipherName.equals(BlockCiphers.AES256CBC().getName())) {
return BlockCiphers.AES256CBC().create();
}
throw new IllegalStateException("Cipher '" + cipherName + "' not currently implemented for openssh-key-v1 format");
}
private PublicKey readPublicKey(final PlainBuffer plainBuffer) throws Buffer.BufferException, GeneralSecurityException {
return KeyType.fromString(plainBuffer.readString()).readPubKeyFromBuffer(plainBuffer);
}
private String readKeyFile(final BufferedReader reader) throws IOException {
StringBuilder sb = new StringBuilder();
String line = reader.readLine();
while (!line.startsWith(END)) {
sb.append(line);
line = reader.readLine();
}
return sb.toString();
}
private boolean checkHeader(final BufferedReader reader) throws IOException {
String line = reader.readLine();
while (line != null && !line.startsWith(BEGIN)) {
line = reader.readLine();
}
line = line.substring(BEGIN.length());
return line.startsWith(OPENSSH_PRIVATE_KEY);
}
private KeyPair readUnencrypted(final PlainBuffer keyBuffer, final PublicKey publicKey) throws IOException, GeneralSecurityException {
int privKeyListSize = keyBuffer.available();
if (privKeyListSize % 8 != 0) {
throw new IOException("The private key section must be a multiple of the block size (8)");
}
int checkInt1 = keyBuffer.readUInt32AsInt(); // uint32 checkint1
int checkInt2 = keyBuffer.readUInt32AsInt(); // uint32 checkint2
if (checkInt1 != checkInt2) {
throw new KeyDecryptionFailedException();
}
// The private key section contains both the public key and the private key
String keyType = keyBuffer.readString(); // string keytype
KeyType kt = KeyType.fromString(keyType);
logger.info("Read key type: {}", keyType, kt);
KeyPair kp;
switch (kt) {
case ED25519:
keyBuffer.readBytes(); // string publickey (again...)
keyBuffer.readUInt32(); // length of privatekey+publickey
byte[] privKey = new byte[32];
keyBuffer.readRawBytes(privKey); // string privatekey
keyBuffer.readRawBytes(new byte[32]); // string publickey (again...)
kp = new KeyPair(publicKey, new EdDSAPrivateKey(new EdDSAPrivateKeySpec(privKey, EdDSANamedCurveTable.getByName("Ed25519"))));
break;
case RSA:
BigInteger n = keyBuffer.readMPInt(); // Modulus
keyBuffer.readMPInt(); // Public Exponent
BigInteger d = keyBuffer.readMPInt(); // Private Exponent
keyBuffer.readMPInt(); // iqmp (q^-1 mod p)
keyBuffer.readMPInt(); // p (Prime 1)
keyBuffer.readMPInt(); // q (Prime 2)
kp = new KeyPair(publicKey, SecurityUtils.getKeyFactory(KeyAlgorithm.RSA).generatePrivate(new RSAPrivateKeySpec(n, d)));
break;
case ECDSA256:
kp = new KeyPair(publicKey, createECDSAPrivateKey(kt, keyBuffer, "P-256"));
break;
case ECDSA384:
kp = new KeyPair(publicKey, createECDSAPrivateKey(kt, keyBuffer, "P-384"));
break;
case ECDSA521:
kp = new KeyPair(publicKey, createECDSAPrivateKey(kt, keyBuffer, "P-521"));
break;
default:
throw new IOException("Cannot decode keytype " + keyType + " in openssh-key-v1 files (yet).");
}
keyBuffer.readString(); // string comment
byte[] padding = new byte[keyBuffer.available()];
keyBuffer.readRawBytes(padding); // char[] padding
for (int i = 0; i < padding.length; i++) {
if ((int) padding[i] != i + 1) {
throw new IOException("Padding of key format contained wrong byte at position: " + i);
}
}
return kp;
}
private PrivateKey createECDSAPrivateKey(KeyType kt, PlainBuffer buffer, String name) throws GeneralSecurityException, Buffer.BufferException {
kt.readPubKeyFromBuffer(buffer); // Public key
BigInteger s = new BigInteger(1, buffer.readBytes());
X9ECParameters ecParams = NISTNamedCurves.getByName(name);
ECNamedCurveSpec ecCurveSpec = new ECNamedCurveSpec(name, ecParams.getCurve(), ecParams.getG(), ecParams.getN());
ECPrivateKeySpec pks = new ECPrivateKeySpec(s, ecCurveSpec);
return SecurityUtils.getKeyFactory(KeyAlgorithm.ECDSA).generatePrivate(pks);
}
}

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

@@ -19,23 +19,23 @@ import java.util.Collection;
public class ErrorDeliveryUtil {
public static void alertPromises(Throwable x, Promise... promises) {
for (Promise p : promises)
public static void alertPromises(Throwable x, Promise<?, ?>... promises) {
for (Promise<?, ?> p : promises)
p.deliverError(x);
}
public static void alertPromises(Throwable x, Collection<? extends Promise> promises) {
for (Promise p : promises)
public static void alertPromises(Throwable x, Collection<? extends Promise<?, ?>> promises) {
for (Promise<?, ?> p : promises)
p.deliverError(x);
}
public static void alertEvents(Throwable x, Event... events) {
for (Event e : events)
public static void alertEvents(Throwable x, Event<?>... events) {
for (Event<?> e : events)
e.deliverError(x);
}
public static void alertEvents(Throwable x, Collection<? extends Event> events) {
for (Event e : events)
public static void alertEvents(Throwable x, Collection<? extends Event<?>> events) {
for (Event<?> e : events)
e.deliverError(x);
}

View File

@@ -15,6 +15,8 @@
*/
package net.schmizz.concurrent;
import net.schmizz.sshj.common.LoggerFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@@ -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)}. */

View File

@@ -26,7 +26,7 @@ package net.schmizz.concurrent;
* if (t instanceof SomeException)
* return (SomeException) t;
* else
* return new SomeExcepion(t);
* return new SomeException(t);
* }
* };
* </pre>

View File

@@ -15,8 +15,8 @@
*/
package net.schmizz.concurrent;
import net.schmizz.sshj.common.LoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -32,8 +32,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 +48,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 +59,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

@@ -19,18 +19,18 @@ import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.ConnectionImpl;
import net.schmizz.sshj.transport.TransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class KeepAlive extends Thread {
protected final Logger log = 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);
setDaemon(true);
}
public synchronized int getKeepAliveInterval() {
@@ -65,6 +65,8 @@ public abstract class KeepAlive extends Thread {
}
Thread.sleep(hi * 1000);
}
} catch (InterruptedException e) {
// Interrupt signal may be catched when sleeping.
} catch (Exception e) {
// If we weren't interrupted, kill the transport, then this exception was unexpected.
// Else we're in shutdown-mode already, so don't forcibly kill the transport.

View File

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

@@ -15,12 +15,35 @@
*/
package net.schmizz.sshj;
import com.hierynomus.sshj.key.KeyAlgorithm;
import com.hierynomus.sshj.key.KeyAlgorithms;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.common.SecurityUtils;
import net.schmizz.sshj.transport.random.JCERandom;
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
import java.util.Arrays;
/**
* Registers SpongyCastle as JCE provider.
*/
public class AndroidConfig
extends DefaultConfig {
static {
SecurityUtils.registerSecurityProvider("org.spongycastle.jce.provider.BouncyCastleProvider");
}
@Override
protected void initKeyAlgorithms() {
setKeyAlgorithms(Arrays.<Factory.Named<KeyAlgorithm>>asList(
KeyAlgorithms.EdDSA25519(),
KeyAlgorithms.SSHRSA(),
KeyAlgorithms.SSHDSA()
));
}
@Override
protected void initRandomFactory(boolean ignored) {
setRandomFactory(new SingletonRandomFactory(new JCERandom.Factory()));

View File

@@ -15,8 +15,10 @@
*/
package net.schmizz.sshj;
import com.hierynomus.sshj.key.KeyAlgorithm;
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;
@@ -76,11 +78,11 @@ public interface Config {
Factory<Random> getRandomFactory();
/**
* Retrieve the list of named factories for {@link Signature}
* Retrieve the list of named factories for {@link com.hierynomus.sshj.key.KeyAlgorithm}
*
* @return a list of named {@link Signature} factories
* @return a list of named {@link com.hierynomus.sshj.key.KeyAlgorithm} factories
*/
List<Factory.Named<Signature>> getSignatureFactories();
List<Factory.Named<KeyAlgorithm>> getKeyAlgorithms();
/**
* Returns the software version information for identification during SSH connection initialization. For example,
@@ -131,11 +133,11 @@ public interface Config {
void setRandomFactory(Factory<Random> randomFactory);
/**
* Set the named factories for {@link Signature}.
* Set the named factories for {@link KeyAlgorithm}.
*
* @param signatureFactories a list of named factories
* @param keyAlgorithms a list of named factories
*/
void setSignatureFactories(List<Factory.Named<Signature>> signatureFactories);
void setKeyAlgorithms(List<Factory.Named<KeyAlgorithm>> keyAlgorithms);
/**
* Set the software version information for identification during SSH connection initialization. For example, {@code
@@ -159,7 +161,7 @@ public interface Config {
/**
* 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.
* <strong>NB:</strong> 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.
*
@@ -170,9 +172,19 @@ public interface Config {
/**
* 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.
* <strong>NB:</strong> 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

@@ -15,9 +15,10 @@
*/
package net.schmizz.sshj;
import com.hierynomus.sshj.key.KeyAlgorithm;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.signature.Signature;
import net.schmizz.sshj.common.LoggerFactory;
import net.schmizz.sshj.transport.cipher.Cipher;
import net.schmizz.sshj.transport.compression.Compression;
import net.schmizz.sshj.transport.kex.KeyExchange;
@@ -41,10 +42,11 @@ public class ConfigImpl
private List<Factory.Named<Cipher>> cipherFactories;
private List<Factory.Named<Compression>> compressionFactories;
private List<Factory.Named<MAC>> macFactories;
private List<Factory.Named<Signature>> signatureFactories;
private List<Factory.Named<KeyAlgorithm>> keyAlgorithms;
private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories;
private boolean waitForServerIdentBeforeSendingClientIdent = false;
private LoggerFactory loggerFactory;
@Override
public List<Factory.Named<Cipher>> getCipherFactories() {
@@ -76,11 +78,6 @@ public class ConfigImpl
return randomFactory;
}
@Override
public List<Factory.Named<Signature>> getSignatureFactories() {
return signatureFactories;
}
@Override
public String getVersion() {
return version;
@@ -136,15 +133,6 @@ public class ConfigImpl
this.randomFactory = randomFactory;
}
public void setSignatureFactories(Factory.Named<Signature>... signatureFactories) {
setSignatureFactories(Arrays.asList(signatureFactories));
}
@Override
public void setSignatureFactories(List<Factory.Named<Signature>> signatureFactories) {
this.signatureFactories = signatureFactories;
}
@Override
public void setVersion(String version) {
this.version = version;
@@ -169,4 +157,24 @@ public class ConfigImpl
public void setWaitForServerIdentBeforeSendingClientIdent(boolean waitForServerIdentBeforeSendingClientIdent) {
this.waitForServerIdentBeforeSendingClientIdent = waitForServerIdentBeforeSendingClientIdent;
}
@Override
public List<Factory.Named<KeyAlgorithm>> getKeyAlgorithms() {
return keyAlgorithms;
}
@Override
public void setKeyAlgorithms(List<Factory.Named<KeyAlgorithm>> keyAlgorithms) {
this.keyAlgorithms = keyAlgorithms;
}
@Override
public LoggerFactory getLoggerFactory() {
return loggerFactory;
}
@Override
public void setLoggerFactory(LoggerFactory loggerFactory) {
this.loggerFactory = loggerFactory;
}
}

View File

@@ -15,47 +15,36 @@
*/
package net.schmizz.sshj;
import com.hierynomus.sshj.signature.SignatureEdDSA;
import com.hierynomus.sshj.key.KeyAlgorithm;
import com.hierynomus.sshj.key.KeyAlgorithms;
import com.hierynomus.sshj.transport.cipher.BlockCiphers;
import com.hierynomus.sshj.transport.cipher.GcmCiphers;
import com.hierynomus.sshj.transport.cipher.StreamCiphers;
import com.hierynomus.sshj.transport.kex.DHGroups;
import com.hierynomus.sshj.transport.kex.ExtInfoClientFactory;
import com.hierynomus.sshj.transport.kex.ExtendedDHGroups;
import com.hierynomus.sshj.transport.mac.Macs;
import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile;
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.compression.NoneCompression;
import net.schmizz.sshj.transport.kex.*;
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.Curve25519SHA256;
import net.schmizz.sshj.transport.kex.DHGexSHA1;
import net.schmizz.sshj.transport.kex.DHGexSHA256;
import net.schmizz.sshj.transport.kex.ECDHNistP;
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.PKCS5KeyFile;
import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.image.ByteLookupTable;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
/**
* A {@link net.schmizz.sshj.Config} that is initialized as follows. Items marked with an asterisk are added to the config only if
@@ -63,13 +52,11 @@ import java.util.List;
* <p/>
* <ul>
* <li>{@link net.schmizz.sshj.ConfigImpl#setKeyExchangeFactories Key exchange}: {@link net.schmizz.sshj.transport.kex.DHG14}*, {@link net.schmizz.sshj.transport.kex.DHG1}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setCipherFactories Ciphers} [1]: {@link net.schmizz.sshj.transport.cipher.AES128CTR}, {@link net.schmizz.sshj.transport.cipher.AES192CTR}, {@link net.schmizz.sshj.transport.cipher.AES256CTR},
* {@link
* net.schmizz.sshj.transport.cipher.AES128CBC}, {@link net.schmizz.sshj.transport.cipher.AES192CBC}, {@link net.schmizz.sshj.transport.cipher.AES256CBC}, {@link net.schmizz.sshj.transport.cipher.AES192CBC}, {@link net.schmizz.sshj.transport.cipher.TripleDESCBC}, {@link net.schmizz.sshj.transport.cipher.BlowfishCBC}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setCipherFactories Ciphers}: {@link BlockCiphers}, {@link StreamCiphers} [1]</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setMACFactories MAC}: {@link net.schmizz.sshj.transport.mac.HMACSHA1}, {@link net.schmizz.sshj.transport.mac.HMACSHA196}, {@link net.schmizz.sshj.transport.mac.HMACMD5}, {@link
* net.schmizz.sshj.transport.mac.HMACMD596}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setCompressionFactories Compression}: {@link net.schmizz.sshj.transport.compression.NoneCompression}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setSignatureFactories Signature}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setKeyAlgorithms KeyAlgorithm}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setRandomFactory PRNG}: {@link net.schmizz.sshj.transport.random.BouncyCastleRandom}* or {@link net.schmizz.sshj.transport.random.JCERandom}</li>
* <li>{@link net.schmizz.sshj.ConfigImpl#setFileKeyProviderFactories Key file support}: {@link net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile}*, {@link
* net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile}*</li>
@@ -82,59 +69,112 @@ import java.util.List;
public class DefaultConfig
extends ConfigImpl {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String VERSION = "SSHJ_0_14_0";
private Logger log;
public DefaultConfig() {
setVersion(VERSION);
setLoggerFactory(LoggerFactory.DEFAULT);
setVersion(readVersionFromProperties());
final boolean bouncyCastleRegistered = SecurityUtils.isBouncyCastleRegistered();
initKeyExchangeFactories(bouncyCastleRegistered);
initKeyAlgorithms();
initRandomFactory(bouncyCastleRegistered);
initFileKeyProviderFactories(bouncyCastleRegistered);
initCipherFactories();
initCompressionFactories();
initMACFactories();
initSignatureFactories();
setKeepAliveProvider(KeepAliveProvider.HEARTBEAT);
}
private String readVersionFromProperties() {
try {
Properties properties = new Properties();
properties.load(DefaultConfig.class.getClassLoader().getResourceAsStream("sshj.properties"));
String property = properties.getProperty("sshj.version");
return "SSHJ_" + property.replace('-', '_'); // '-' is a disallowed character, see RFC-4253#section-4.2
} catch (Exception e) {
log.error("Could not read the sshj.properties file, returning an 'unknown' version as fallback.");
return "SSHJ_VERSION_UNKNOWN";
}
}
@Override
public void setLoggerFactory(LoggerFactory loggerFactory) {
super.setLoggerFactory(loggerFactory);
log = loggerFactory.getLogger(getClass());
}
protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) {
if (bouncyCastleRegistered)
setKeyExchangeFactories(new Curve25519SHA256.Factory(),
if (bouncyCastleRegistered) {
setKeyExchangeFactories(
new Curve25519SHA256.Factory(),
new Curve25519SHA256.FactoryLibSsh(),
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());
DHGroups.Group1SHA1(),
DHGroups.Group14SHA1(),
DHGroups.Group14SHA256(),
DHGroups.Group15SHA512(),
DHGroups.Group16SHA512(),
DHGroups.Group17SHA512(),
DHGroups.Group18SHA512(),
ExtendedDHGroups.Group14SHA256AtSSH(),
ExtendedDHGroups.Group15SHA256(),
ExtendedDHGroups.Group15SHA256AtSSH(),
ExtendedDHGroups.Group15SHA384AtSSH(),
ExtendedDHGroups.Group16SHA256(),
ExtendedDHGroups.Group16SHA384AtSSH(),
ExtendedDHGroups.Group16SHA512AtSSH(),
ExtendedDHGroups.Group18SHA512AtSSH(),
new ExtInfoClientFactory());
} else {
setKeyExchangeFactories(DHGroups.Group1SHA1(), new DHGexSHA1.Factory());
}
}
protected void initKeyAlgorithms() {
setKeyAlgorithms(Arrays.<Factory.Named<KeyAlgorithm>>asList(
KeyAlgorithms.EdDSA25519(),
KeyAlgorithms.ECDSASHANistp521(),
KeyAlgorithms.ECDSASHANistp384(),
KeyAlgorithms.ECDSASHANistp256(),
KeyAlgorithms.RSASHA512(),
KeyAlgorithms.RSASHA256(),
KeyAlgorithms.SSHRSACertV01(),
KeyAlgorithms.SSHDSSCertV01(),
KeyAlgorithms.SSHRSA(),
KeyAlgorithms.SSHDSA()));
}
protected void initRandomFactory(boolean bouncyCastleRegistered) {
setRandomFactory(new SingletonRandomFactory(bouncyCastleRegistered
? new BouncyCastleRandom.Factory() : new JCERandom.Factory()));
setRandomFactory(new SingletonRandomFactory(new JCERandom.Factory()));
}
protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) {
if (bouncyCastleRegistered) {
setFileKeyProviderFactories(new PKCS8KeyFile.Factory(), new OpenSSHKeyFile.Factory(), new PuTTYKeyFile.Factory());
setFileKeyProviderFactories(
new OpenSSHKeyV1KeyFile.Factory(),
new PKCS8KeyFile.Factory(),
new PKCS5KeyFile.Factory(),
new OpenSSHKeyFile.Factory(),
new PuTTYKeyFile.Factory());
}
}
protected void initCipherFactories() {
List<Factory.Named<Cipher>> avail = new LinkedList<Factory.Named<Cipher>>(Arrays.<Factory.Named<Cipher>>asList(
new AES128CTR.Factory(),
new AES192CTR.Factory(),
new AES256CTR.Factory(),
new AES128CBC.Factory(),
new AES192CBC.Factory(),
new AES256CBC.Factory(),
new TripleDESCBC.Factory(),
new BlowfishCBC.Factory(),
BlockCiphers.AES128CBC(),
BlockCiphers.AES128CTR(),
BlockCiphers.AES192CBC(),
BlockCiphers.AES192CTR(),
BlockCiphers.AES256CBC(),
BlockCiphers.AES256CTR(),
GcmCiphers.AES128GCM(),
GcmCiphers.AES256GCM(),
BlockCiphers.BlowfishCBC(),
BlockCiphers.BlowfishCTR(),
BlockCiphers.Cast128CBC(),
BlockCiphers.Cast128CTR(),
@@ -146,6 +186,7 @@ public class DefaultConfig
BlockCiphers.Serpent192CTR(),
BlockCiphers.Serpent256CBC(),
BlockCiphers.Serpent256CTR(),
BlockCiphers.TripleDESCBC(),
BlockCiphers.TripleDESCTR(),
BlockCiphers.Twofish128CBC(),
BlockCiphers.Twofish128CTR(),
@@ -156,7 +197,8 @@ public class DefaultConfig
BlockCiphers.TwofishCBC(),
StreamCiphers.Arcfour(),
StreamCiphers.Arcfour128(),
StreamCiphers.Arcfour256()));
StreamCiphers.Arcfour256())
);
boolean warn = false;
// Ref. https://issues.apache.org/jira/browse/SSHD-24
@@ -181,18 +223,28 @@ public class DefaultConfig
log.debug("Available cipher factories: {}", avail);
}
protected void initSignatureFactories() {
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(
Macs.HMACSHA1(),
Macs.HMACSHA1Etm(),
Macs.HMACSHA196(),
Macs.HMACSHA196Etm(),
Macs.HMACMD5(),
Macs.HMACMD5Etm(),
Macs.HMACMD596(),
Macs.HMACMD596Etm(),
Macs.HMACSHA2256(),
Macs.HMACSHA2256Etm(),
Macs.HMACSHA2512(),
Macs.HMACSHA2512Etm(),
Macs.HMACRIPEMD160(),
Macs.HMACRIPEMD160Etm(),
Macs.HMACRIPEMD16096(),
Macs.HMACRIPEMD160OpenSsh()
);
}
protected void initCompressionFactories() {
setCompressionFactories(new NoneCompression.Factory());
}
}

View File

@@ -15,16 +15,11 @@
*/
package net.schmizz.sshj;
import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.common.SecurityUtils;
import net.schmizz.sshj.common.*;
import net.schmizz.sshj.connection.Connection;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.ConnectionImpl;
import net.schmizz.sshj.connection.channel.direct.LocalPortForwarder;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.SessionChannel;
import net.schmizz.sshj.connection.channel.direct.SessionFactory;
import net.schmizz.sshj.connection.channel.direct.*;
import net.schmizz.sshj.connection.channel.forwarded.ConnectListener;
import net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder;
import net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder.ForwardedTCPIPChannel;
@@ -40,22 +35,14 @@ 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.FingerprintVerifier;
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.AuthGssApiWithMic;
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;
@@ -63,21 +50,15 @@ 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.nio.charset.Charset;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
/**
* Secure SHell client API.
@@ -128,7 +109,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;
@@ -139,6 +121,11 @@ public class SSHClient
/** {@code ssh-connection} service */
protected final Connection conn;
private final List<LocalPortForwarder> forwarders = new ArrayList<LocalPortForwarder>();
/** character set of the remote machine */
protected Charset remoteCharset = IOUtils.UTF8;
/** Default constructor. Initializes this object using {@link DefaultConfig}. */
public SSHClient() {
this(new DefaultConfig());
@@ -151,6 +138,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());
@@ -177,19 +166,23 @@ public class SSHClient
/**
* Add a {@link HostKeyVerifier} that will verify any host that's able to claim a host key with the given {@code
* fingerprint}, e.g. {@code "4b:69:6c:72:6f:79:20:77:61:73:20:68:65:72:65:21"}
* fingerprint}.
*
* The fingerprint can be specified in either an MD5 colon-delimited format (16 hexadecimal octets, delimited by a colon),
* or in a Base64 encoded format for SHA-1 or SHA-256 fingerprints.
* Valid examples are:
*
* <ul><li>"SHA1:2Fo8c/96zv32xc8GZWbOGYOlRak="</li>
* <li>"SHA256:oQGbQTujGeNIgh0ONthcEpA/BHxtt3rcYY+NxXTxQjs="</li>
* <li>"MD5:d3:5e:40:72:db:08:f1:6d:0c:d7:6d:35:0d:ba:7c:32"</li>
* <li>"d3:5e:40:72:db:08:f1:6d:0c:d7:6d:35:0d:ba:7c:32"</li></ul>
*
* @param fingerprint expected fingerprint in colon-delimited format (16 octets in hex delimited by a colon)
*
* @see SecurityUtils#getFingerprint
*/
public void addHostKeyVerifier(final String fingerprint) {
addHostKeyVerifier(new HostKeyVerifier() {
@Override
public boolean verify(String h, int p, PublicKey k) {
return SecurityUtils.getFingerprint(k).equals(fingerprint);
}
});
addHostKeyVerifier(FingerprintVerifier.getInstance(fingerprint));
}
// FIXME: there are way too many auth... overrides. Better API needed.
@@ -221,8 +214,9 @@ public class SSHClient
public void auth(String username, Iterable<AuthMethod> methods)
throws UserAuthException, TransportException {
checkConnected();
final Deque<UserAuthException> savedEx = new LinkedList<>();
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;
@@ -324,7 +318,7 @@ public class SSHClient
public void authPublickey(String username)
throws UserAuthException, TransportException {
final String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator;
authPublickey(username, base + "id_rsa", base + "id_dsa");
authPublickey(username, base + "id_rsa", base + "id_dsa", base + "id_ed25519", base + "id_ecdsa");
}
/**
@@ -342,7 +336,7 @@ public class SSHClient
*/
public void authPublickey(String username, Iterable<KeyProvider> keyProviders)
throws UserAuthException, TransportException {
final List<AuthMethod> am = new LinkedList<>();
final List<AuthMethod> am = new LinkedList<AuthMethod>();
for (KeyProvider kp : keyProviders)
am.add(new AuthPublickey(kp));
auth(username, am);
@@ -362,8 +356,7 @@ public class SSHClient
* @throws TransportException if there was a transport-layer error
*/
public void authPublickey(String username, KeyProvider... keyProviders)
throws UserAuthException,
TransportException {
throws UserAuthException, TransportException {
authPublickey(username, Arrays.<KeyProvider>asList(keyProviders));
}
@@ -385,7 +378,7 @@ public class SSHClient
*/
public void authPublickey(String username, String... locations)
throws UserAuthException, TransportException {
final List<KeyProvider> keyProviders = new LinkedList<>();
final List<KeyProvider> keyProviders = new LinkedList<KeyProvider>();
for (String loc : locations) {
try {
log.debug("Attempting to load key from: {}", loc);
@@ -415,7 +408,7 @@ public class SSHClient
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<>(Arrays.asList(supportedOids));
List<Oid> oids = new ArrayList<Oid>(Arrays.asList(supportedOids));
oids.add(0, supportedOid);
auth(username, new AuthGssApiWithMic(context, oids));
@@ -431,6 +424,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();
}
@@ -440,6 +441,15 @@ public class SSHClient
return conn;
}
/**
* Returns the character set used to communicate with the remote machine for certain strings (like paths).
*
* @return remote character set
*/
public Charset getRemoteCharset() {
return remoteCharset;
}
/** @return a {@link RemotePortForwarder} that allows requesting remote forwarding over this connection. */
public RemotePortForwarder getRemotePortForwarder() {
synchronized (conn) {
@@ -505,7 +515,7 @@ public class SSHClient
}
/**
* Utility function for createing a {@link KeyProvider} instance from given location on the file system. Creates a
* Utility function for creating a {@link KeyProvider} instance from given location on the file system. Creates a
* one-off {@link PasswordFinder} using {@link PasswordUtils#createOneOff(char[])}, and calls {@link
* #loadKeys(String, PasswordFinder)}.
*
@@ -524,8 +534,13 @@ public class SSHClient
}
/**
* Creates a {@link KeyProvider} instance from given location on the file system. Currently only PKCS8 format
* private key files are supported (OpenSSH uses this format).
* Creates a {@link KeyProvider} instance from given location on the file system. Currently the following private key files are supported:
* <ul>
* <li>PKCS8 (OpenSSH uses this format)</li>
* <li>PKCS5</li>
* <li>Putty keyfile</li>
* <li>openssh-key-v1 (New OpenSSH keyfile format)</li>
* </ul>
* <p/>
*
* @param location the location of the key file
@@ -630,7 +645,7 @@ public class SSHClient
*/
public void loadKnownHosts(File location)
throws IOException {
addHostKeyVerifier(new OpenSSHKnownHosts(location));
addHostKeyVerifier(new OpenSSHKnownHosts(location, loggerFactory));
}
/**
@@ -646,9 +661,25 @@ public class SSHClient
*
* @return a {@link LocalPortForwarder}
*/
public LocalPortForwarder newLocalPortForwarder(LocalPortForwarder.Parameters parameters,
public LocalPortForwarder newLocalPortForwarder(Parameters parameters,
ServerSocket serverSocket) {
return new LocalPortForwarder(conn, parameters, serverSocket);
LocalPortForwarder forwarder = new LocalPortForwarder(conn, parameters, serverSocket, loggerFactory);
forwarders.add(forwarder);
return forwarder;
}
/** Create a {@link DirectConnection} channel that connects to a remote address from the server.
*
* This can be used to open a tunnel to, for example, an HTTP server that is only
* accessible from the SSH server, or opening an SSH connection via a 'jump' server.
*
* @param hostname name of the host to connect to from the server.
* @param port remote port number.
*/
public DirectConnection newDirectConnection(String hostname, int port) throws IOException {
DirectConnection tunnel = new DirectConnection(conn, hostname, port);
tunnel.open();
return tunnel;
}
/**
@@ -675,7 +706,7 @@ public class SSHClient
public SCPFileTransfer newSCPFileTransfer() {
checkConnected();
checkAuthenticated();
return new SCPFileTransfer(this);
return new SCPFileTransfer(this, loggerFactory);
}
/**
@@ -691,6 +722,19 @@ public class SSHClient
return new SFTPClient(new SFTPEngine(this).init());
}
/**
* Stateful FTP client is required in order to connect to Serv-U FTP servers.
* @return Instantiated {@link SFTPClient} implementation.
*
* @throws IOException if there is an error starting the {@code sftp} subsystem
*/
public SFTPClient newStatefulSFTPClient()
throws IOException {
checkConnected();
checkAuthenticated();
return new StatefulSFTPClient(new SFTPEngine(this).init());
}
/**
* Does key re-exchange.
*
@@ -701,19 +745,29 @@ public class SSHClient
doKex();
}
/**
* Sets the character set used to communicate with the remote machine for certain strings (like paths)
*
* @param remoteCharset
* remote character set or {@code null} for default
*/
public void setRemoteCharset(Charset remoteCharset) {
this.remoteCharset = remoteCharset != null ? remoteCharset : IOUtils.UTF8;
}
@Override
public Session startSession()
throws ConnectionException, TransportException {
checkConnected();
checkAuthenticated();
final SessionChannel sess = new SessionChannel(conn);
final SessionChannel sess = new SessionChannel(conn, remoteCharset);
sess.open();
return sess;
}
/**
* Adds {@code zlib} compression to preferred compression algorithms. There is no guarantee that it will be
* successfully negotiatied.
* successfully negotiated.
* <p/>
* If the client is already connected renegotiation is done; otherwise this method simply returns (and compression
* will be negotiated during connection establishment).

View File

@@ -17,6 +17,8 @@ package net.schmizz.sshj;
import com.hierynomus.sshj.backport.JavaVersion;
import com.hierynomus.sshj.backport.Jdk7HttpProxySocket;
import net.schmizz.sshj.connection.channel.Channel;
import net.schmizz.sshj.connection.channel.direct.DirectConnection;
import javax.net.SocketFactory;
import java.io.IOException;
@@ -43,41 +45,28 @@ public abstract class SocketClient {
private int timeout = 0;
private String hostname;
private int port;
private boolean tunneled = false;
SocketClient(int defaultPort) {
this.defaultPort = defaultPort;
}
public void connect(InetAddress host, int port) throws IOException {
socket = socketFactory.createSocket();
socket.connect(new InetSocketAddress(host, port), connectTimeout);
onConnect();
protected InetSocketAddress makeInetSocketAddress(String hostname, int port) {
return new InetSocketAddress(hostname, port);
}
/**
* Connect to a host via a proxy.
* @param host The host address to connect to.
* @param port The port to connect to.
* @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(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, int port) throws IOException {
this.hostname = hostname;
connect(InetAddress.getByName(hostname), port);
public void connect(String hostname, Proxy proxy) throws IOException {
connect(hostname, defaultPort, proxy);
}
/**
@@ -91,30 +80,17 @@ public abstract class SocketClient {
@Deprecated
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)
throws IOException {
socket = socketFactory.createSocket();
socket.bind(new InetSocketAddress(localAddr, localPort));
socket.connect(new InetSocketAddress(host, port), connectTimeout);
this.port = port;
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(makeInetSocketAddress(hostname, port), connectTimeout);
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);
}
/**
* Connect to a host via a proxy.
* @param host The host address to connect to.
@@ -129,14 +105,86 @@ public abstract class SocketClient {
/**
* Connect to a host via a proxy.
* @param hostname The host name to connect to.
* @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(String hostname, Proxy proxy) throws IOException {
connect(hostname, defaultPort, proxy);
public void connect(InetAddress host, int port, Proxy proxy) throws IOException {
this.port = port;
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;
this.port = port;
socket = socketFactory.createSocket();
socket.connect(makeInetSocketAddress(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;
this.port = port;
socket = socketFactory.createSocket();
socket.bind(new InetSocketAddress(localAddr, localPort));
socket.connect(makeInetSocketAddress(hostname, port), connectTimeout);
onConnect();
}
}
public void connectVia(Channel channel, String hostname, int port) throws IOException {
this.hostname = hostname;
this.port = port;
this.input = channel.getInputStream();
this.output = channel.getOutputStream();
this.tunneled = true;
onConnect();
}
/** Connect to a remote address via a direct TCP/IP connection from the server. */
public void connectVia(DirectConnection directConnection) throws IOException {
connectVia(directConnection, directConnection.getRemoteHost(), directConnection.getRemotePort());
}
public void connect(InetAddress host) throws IOException {
connect(host, defaultPort);
}
public void connect(InetAddress host, int port) throws IOException {
this.port = port;
socket = socketFactory.createSocket();
socket.connect(new InetSocketAddress(host, port), connectTimeout);
onConnect();
}
public void connect(InetAddress host, int port, InetAddress localAddr, int localPort)
throws IOException {
this.port = port;
socket = socketFactory.createSocket();
socket.bind(new InetSocketAddress(localAddr, localPort));
socket.connect(new InetSocketAddress(host, port), connectTimeout);
onConnect();
}
public void disconnect() throws IOException {
@@ -155,15 +203,15 @@ public abstract class SocketClient {
}
public boolean isConnected() {
return (socket != null) && socket.isConnected();
return tunneled || ((socket != null) && socket.isConnected());
}
public int getLocalPort() {
return socket.getLocalPort();
return tunneled ? 65536 : socket.getLocalPort();
}
public InetAddress getLocalAddress() {
return socket.getLocalAddress();
return socket == null ? null : socket.getLocalAddress();
}
public String getRemoteHostname() {
@@ -171,11 +219,11 @@ public abstract class SocketClient {
}
public int getRemotePort() {
return socket.getPort();
return socket == null ? this.port : socket.getPort();
}
public InetAddress getRemoteAddress() {
return socket.getInetAddress();
return socket == null ? null : socket.getInetAddress();
}
public void setSocketFactory(SocketFactory factory) {
@@ -219,9 +267,11 @@ public abstract class SocketClient {
}
void onConnect() throws IOException {
socket.setSoTimeout(timeout);
input = socket.getInputStream();
output = socket.getOutputStream();
if (socket != null) {
socket.setSoTimeout(timeout);
input = socket.getInputStream();
output = socket.getOutputStream();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -15,12 +15,13 @@
*/
package net.schmizz.sshj.common;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.util.Arrays;
@SuppressWarnings("serial")
public class Buffer<T extends Buffer<T>> {
public static class BufferException
@@ -55,13 +56,18 @@ public class Buffer<T extends Buffer<T>> {
public static final int DEFAULT_SIZE = 256;
/** The maximum valid size of buffer (i.e. biggest power of two that can be represented as an int - 2^30) */
public static final int MAX_SIZE = (1 << 30);
public static final int MAX_SIZE = (1 << 30);
/** Maximum size of a uint64 */
public static final BigInteger MAX_UINT64_VALUE = BigInteger.ONE
.shiftLeft(64)
.subtract(BigInteger.ONE);
protected static int getNextPowerOf2(int i) {
int j = 1;
while (j < i) {
j <<= 1;
if (j <= 0) throw new IllegalArgumentException("Cannot get next power of 2; "+i+" is too large");
if (j <= 0) throw new IllegalArgumentException("Cannot get next power of 2; "+i+" is too large");
}
return j;
}
@@ -127,8 +133,9 @@ public class Buffer<T extends Buffer<T>> {
protected void ensureAvailable(int a)
throws BufferException {
if (available() < a)
if (available() < a) {
throw new BufferException("Underflow");
}
}
public void ensureCapacity(int capacity) {
@@ -142,7 +149,6 @@ public class Buffer<T extends Buffer<T>> {
/** Compact this {@link SSHPacket} */
public void compact() {
System.err.println("COMPACTING");
if (available() > 0)
System.arraycopy(data, rpos, data, 0, wpos - rpos);
wpos -= rpos;
@@ -241,7 +247,7 @@ public class Buffer<T extends Buffer<T>> {
* @return this
*/
public T putBytes(byte[] b, int off, int len) {
return putUInt32(len - off).putRawBytes(b, off, len);
return putUInt32(len).putRawBytes(b, off, len);
}
public void readRawBytes(byte[] buf)
@@ -311,7 +317,7 @@ public class Buffer<T extends Buffer<T>> {
public T putUInt32(long uint32) {
ensureCapacity(4);
if (uint32 < 0 || uint32 > 0xffffffffL)
throw new RuntimeException("Invalid value: " + uint32);
throw new IllegalArgumentException("Invalid value: " + uint32);
data[wpos++] = (byte) (uint32 >> 24);
data[wpos++] = (byte) (uint32 >> 16);
data[wpos++] = (byte) (uint32 >> 8);
@@ -343,10 +349,31 @@ public class Buffer<T extends Buffer<T>> {
return uint64;
}
@SuppressWarnings("unchecked")
public BigInteger readUInt64AsBigInteger()
throws BufferException {
byte[] magnitude = new byte[8];
readRawBytes(magnitude);
return new BigInteger(1, magnitude);
}
public T putUInt64(long uint64) {
if (uint64 < 0)
throw new RuntimeException("Invalid value: " + uint64);
if (uint64 < 0) {
throw new IllegalArgumentException("Invalid value: " + uint64);
}
return putUInt64Unchecked(uint64);
}
public T putUInt64(BigInteger uint64) {
if (uint64.compareTo(MAX_UINT64_VALUE) > 0 ||
uint64.compareTo(BigInteger.ZERO) < 0) {
throw new IllegalArgumentException("Invalid value: " + uint64);
}
return putUInt64Unchecked(uint64.longValue());
}
@SuppressWarnings("unchecked")
private T putUInt64Unchecked(long uint64) {
ensureCapacity(8);
data[wpos++] = (byte) (uint64 >> 56);
data[wpos++] = (byte) (uint64 >> 48);
data[wpos++] = (byte) (uint64 >> 40);
@@ -361,22 +388,30 @@ public class Buffer<T extends Buffer<T>> {
/**
* Reads an SSH string
*
* @param cs the charset to use for decoding
*
* @return the string as a Java {@code String}
*/
public String readString(Charset cs)
throws BufferException {
int len = readUInt32AsInt();
if (len < 0 || len > 32768) {
throw new BufferException("Bad item length: " + len);
}
ensureAvailable(len);
String s = new String(data, rpos, len, cs);
rpos += len;
return s;
}
/**
* Reads an SSH string using {@code UTF8}
*
* @return the string as a Java {@code String}
*/
public String readString()
throws BufferException {
int len = readUInt32AsInt();
if (len < 0 || len > 32768)
throw new BufferException("Bad item length: " + len);
ensureAvailable(len);
String s;
try {
s = new String(data, rpos, len, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new SSHRuntimeException(e);
}
rpos += len;
return s;
return readString(IOUtils.UTF8);
}
/**
@@ -397,8 +432,12 @@ public class Buffer<T extends Buffer<T>> {
return putBytes(str, offset, len);
}
public T putString(String string, Charset cs) {
return putString(string.getBytes(cs));
}
public T putString(String string) {
return putString(string.getBytes(IOUtils.UTF8));
return putString(string, IOUtils.UTF8);
}
/**
@@ -415,21 +454,26 @@ public class Buffer<T extends Buffer<T>> {
public T putSensitiveString(char[] str) {
if (str == null)
return putString("");
putUInt32(str.length);
ensureCapacity(str.length);
for (char c : str)
data[wpos++] = (byte) c;
Arrays.fill(str, ' ');
// RFC 4252, Section 8 says: passwords should be encoded as UTF-8.
// RFC 4256, Section 3.4 says: keyboard-interactive information responses should be encoded as UTF-8.
byte[] utf8 = ByteArrayUtils.encodeSensitiveStringToUtf8(str);
putUInt32(utf8.length);
ensureCapacity(utf8.length);
for (byte c : utf8)
data[wpos++] = c;
Arrays.fill(utf8, (byte) 0);
return (T) this;
}
public PublicKey readPublicKey()
throws BufferException {
KeyType keyType = KeyType.fromString(readString());
try {
final String type = readString();
return KeyType.fromString(type).readPubKeyFromBuffer(type, this);
return keyType.readPubKeyFromBuffer(this);
} catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e);
} catch (UnsupportedOperationException uoe) {
throw new BufferException("Could not decode keytype " + keyType);
}
}

View File

@@ -15,6 +15,12 @@
*/
package net.schmizz.sshj.common;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.Arrays;
/** Utility functions for byte arrays. */
public class ByteArrayUtils {
@@ -94,4 +100,56 @@ public class ByteArrayUtils {
return sb.toString();
}
public static byte[] parseHex(String hex) {
if (hex == null) {
throw new IllegalArgumentException("Hex string is null");
}
if (hex.length() % 2 != 0) {
throw new IllegalArgumentException("Hex string '" + hex + "' should have even length.");
}
byte[] result = new byte[hex.length() / 2];
for (int i = 0; i < result.length; i++) {
int hi = parseHexDigit(hex.charAt(i * 2)) << 4;
int lo = parseHexDigit(hex.charAt(i * 2 + 1));
result[i] = (byte) (hi + lo);
}
return result;
}
private static int parseHexDigit(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
}
if (c >= 'A' && c <= 'F') {
return c - 'A' + 10;
}
throw new IllegalArgumentException("Digit '" + c + "' out of bounds [0-9a-fA-F]");
}
/**
* Converts a char-array to UTF-8 byte-array and then blanks out source array and all intermediate arrays.
* <p/>
* This is useful when a plaintext password needs to be encoded as UTF-8.
*
* @param str A not-null string as a character array.
*
* @return UTF-8 bytes of the string
*/
public static byte[] encodeSensitiveStringToUtf8(char[] str) {
CharsetEncoder charsetEncoder = Charset.forName("UTF-8").newEncoder();
ByteBuffer utf8Buffer = ByteBuffer.allocate((int) (str.length * charsetEncoder.maxBytesPerChar()));
assert utf8Buffer.hasArray();
charsetEncoder.encode(CharBuffer.wrap(str), utf8Buffer, true);
Arrays.fill(str, ' ');
byte[] utf8Bytes = new byte[utf8Buffer.position()];
System.arraycopy(utf8Buffer.array(), 0, utf8Bytes, 0, utf8Bytes.length);
Arrays.fill(utf8Buffer.array(), (byte) 0);
return utf8Bytes;
}
}

View File

@@ -0,0 +1,114 @@
/*
* 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 com.hierynomus.sshj.common.KeyAlgorithm;
import com.hierynomus.sshj.secg.SecgUtils;
import org.bouncycastle.asn1.nist.NISTNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.ECKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
class ECDSAVariationsAdapter {
private final static String BASE_ALGORITHM_NAME = "ecdsa-sha2-nistp";
private final static Logger log = LoggerFactory.getLogger(ECDSAVariationsAdapter.class);
public final static Map<String, String> SUPPORTED_CURVES = new HashMap<String, String>();
public final static Map<String, String> NIST_CURVES_NAMES = new HashMap<String, String>();
static {
NIST_CURVES_NAMES.put("256", "p-256");
NIST_CURVES_NAMES.put("384", "p-384");
NIST_CURVES_NAMES.put("521", "p-521");
SUPPORTED_CURVES.put("256", "nistp256");
SUPPORTED_CURVES.put("384", "nistp384");
SUPPORTED_CURVES.put("521", "nistp521");
}
static PublicKey readPubKeyFromBuffer(Buffer<?> buf, String variation) throws GeneralSecurityException {
String algorithm = BASE_ALGORITHM_NAME + variation;
if (!SecurityUtils.isBouncyCastleRegistered()) {
throw new GeneralSecurityException("BouncyCastle is required to read a key of type " + algorithm);
}
try {
// final String algo = buf.readString(); it has been already read
final String curveName = buf.readString();
final int keyLen = buf.readUInt32AsInt();
final byte x04 = buf.readByte(); // it must be 0x04, but don't think
// we need that check
final byte[] x = new byte[(keyLen - 1) / 2];
final byte[] y = new byte[(keyLen - 1) / 2];
buf.readRawBytes(x);
buf.readRawBytes(y);
if (log.isDebugEnabled()) {
log.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s",
algorithm, curveName, keyLen, x04, Arrays.toString(x), Arrays.toString(y)));
}
if (!SUPPORTED_CURVES.values().contains(curveName)) {
throw new GeneralSecurityException(String.format("Unknown curve %s", curveName));
}
BigInteger bigX = new BigInteger(1, x);
BigInteger bigY = new BigInteger(1, y);
String name = NIST_CURVES_NAMES.get(variation);
X9ECParameters ecParams = NISTNamedCurves.getByName(name);
ECNamedCurveSpec ecCurveSpec = new ECNamedCurveSpec(name, ecParams.getCurve(), ecParams.getG(), ecParams.getN());
ECPoint p = new ECPoint(bigX, bigY);
ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(p, ecCurveSpec);
KeyFactory keyFactory = KeyFactory.getInstance(KeyAlgorithm.ECDSA);
return keyFactory.generatePublic(publicKeySpec);
} catch (Exception ex) {
throw new GeneralSecurityException(ex);
}
}
static void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
final ECPublicKey ecdsa = (ECPublicKey) pk;
byte[] encoded = SecgUtils.getEncoded(ecdsa.getW(), ecdsa.getParams().getCurve());
buf.putString("nistp" + Integer.toString(fieldSizeFromKey(ecdsa)))
.putBytes(encoded);
}
static boolean isECKeyWithFieldSize(Key key, int fieldSize) {
return (KeyAlgorithm.ECDSA.equals(key.getAlgorithm()) || KeyAlgorithm.EC_KEYSTORE.equals(key.getAlgorithm()))
&& fieldSizeFromKey((ECKey) key) == fieldSize;
}
private static int fieldSizeFromKey(ECKey ecPublicKey) {
return ecPublicKey.getParams().getCurve().getField().getFieldSize();
}
}

View File

@@ -26,7 +26,7 @@ import java.util.List;
public interface Factory<T> {
/**
* Inteface for a named factory. Named factories are simply factories that are identified by a name. Such names are
* Interface for a named factory. Named factories are simply factories that are identified by a name. Such names are
* used mainly in SSH algorithm negotiation.
*
* @param <T> type of object created by this factory

View File

@@ -15,9 +15,6 @@
*/
package net.schmizz.sshj.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
@@ -26,25 +23,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

@@ -15,18 +15,14 @@
*/
package net.schmizz.sshj.common;
import com.hierynomus.sshj.secg.SecgUtils;
import com.hierynomus.sshj.common.KeyAlgorithm;
import com.hierynomus.sshj.signature.Ed25519PublicKey;
import com.hierynomus.sshj.userauth.certificate.Certificate;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.math.GroupElement;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import org.bouncycastle.asn1.nist.NISTNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import net.schmizz.sshj.common.Buffer.BufferException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,19 +31,19 @@ import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.*;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
import java.util.*;
/** Type of key e.g. rsa, dsa */
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 {
@@ -56,29 +52,27 @@ public enum KeyType {
} catch (Buffer.BufferException be) {
throw new GeneralSecurityException(be);
}
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
final KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.RSA);
return keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
}
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
final RSAPublicKey rsaKey = (RSAPublicKey) pk;
buf.putString(sType)
.putMPInt(rsaKey.getPublicExponent()) // e
.putMPInt(rsaKey.getModulus()); // n
buf.putMPInt(rsaKey.getPublicExponent()) // e
.putMPInt(rsaKey.getModulus()); // n
}
@Override
protected boolean isMyType(Key key) {
return (key instanceof RSAPublicKey || key instanceof RSAPrivateKey);
return KeyAlgorithm.RSA.equals(key.getAlgorithm());
}
},
/** 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 {
@@ -89,110 +83,107 @@ public enum KeyType {
} catch (Buffer.BufferException be) {
throw new GeneralSecurityException(be);
}
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
final KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.DSA);
return keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
}
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
final DSAPublicKey dsaKey = (DSAPublicKey) pk;
buf.putString(sType)
.putMPInt(dsaKey.getParams().getP()) // p
.putMPInt(dsaKey.getParams().getQ()) // q
.putMPInt(dsaKey.getParams().getG()) // g
.putMPInt(dsaKey.getY()); // y
buf.putMPInt(dsaKey.getParams().getP()) // p
.putMPInt(dsaKey.getParams().getQ()) // q
.putMPInt(dsaKey.getParams().getG()) // g
.putMPInt(dsaKey.getY()); // y
}
@Override
protected boolean isMyType(Key key) {
return (key instanceof DSAPublicKey || key instanceof DSAPrivateKey);
return KeyAlgorithm.DSA.equals(key.getAlgorithm());
}
},
/** SSH identifier for ECDSA keys */
ECDSA("ecdsa-sha2-nistp256") {
private final Logger log = LoggerFactory.getLogger(getClass());
/** SSH identifier for ECDSA-256 keys */
ECDSA256("ecdsa-sha2-nistp256") {
@Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf)
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
try {
// final String algo = buf.readString(); it has been already read
final String curveName = buf.readString();
final int keyLen = buf.readUInt32AsInt();
final byte x04 = buf.readByte(); // it must be 0x04, but don't think we need that check
final byte[] x = new byte[(keyLen - 1) / 2];
final byte[] y = new byte[(keyLen - 1) / 2];
buf.readRawBytes(x);
buf.readRawBytes(y);
if(log.isDebugEnabled()) {
log.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s",
type,
curveName,
keyLen,
x04,
Arrays.toString(x),
Arrays.toString(y))
);
}
if (!NISTP_CURVE.equals(curveName)) {
throw new GeneralSecurityException(String.format("Unknown curve %s", curveName));
}
BigInteger bigX = new BigInteger(1, x);
BigInteger bigY = new BigInteger(1, y);
X9ECParameters ecParams = NISTNamedCurves.getByName("p-256");
ECPoint pPublicPoint = ecParams.getCurve().createPoint(bigX, bigY);
ECParameterSpec spec = new ECParameterSpec(ecParams.getCurve(),
ecParams.getG(), ecParams.getN());
ECPublicKeySpec publicSpec = new ECPublicKeySpec(pPublicPoint, spec);
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA");
return keyFactory.generatePublic(publicSpec);
} catch (Exception ex) {
throw new GeneralSecurityException(ex);
}
return ECDSAVariationsAdapter.readPubKeyFromBuffer(buf, "256");
}
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
final ECPublicKey ecdsa = (ECPublicKey) pk;
byte[] encoded = SecgUtils.getEncoded(ecdsa.getW(), ecdsa.getParams().getCurve());
buf.putString(sType)
.putString(NISTP_CURVE)
.putBytes(encoded);
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
ECDSAVariationsAdapter.writePubKeyContentsIntoBuffer(pk, buf);
}
@Override
protected boolean isMyType(Key key) {
return ("ECDSA".equals(key.getAlgorithm()));
return ECDSAVariationsAdapter.isECKeyWithFieldSize(key, 256);
}
},
/** SSH identifier for ECDSA-384 keys */
ECDSA384("ecdsa-sha2-nistp384") {
@Override
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
return ECDSAVariationsAdapter.readPubKeyFromBuffer(buf, "384");
}
@Override
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
ECDSAVariationsAdapter.writePubKeyContentsIntoBuffer(pk, buf);
}
@Override
protected boolean isMyType(Key key) {
return ECDSAVariationsAdapter.isECKeyWithFieldSize(key, 384);
}
},
/** SSH identifier for ECDSA-521 keys */
ECDSA521("ecdsa-sha2-nistp521") {
@Override
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
return ECDSAVariationsAdapter.readPubKeyFromBuffer(buf, "521");
}
@Override
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
ECDSAVariationsAdapter.writePubKeyContentsIntoBuffer(pk, buf);
}
@Override
protected boolean isMyType(Key key) {
return ECDSAVariationsAdapter.isECKeyWithFieldSize(key, 521);
}
},
ED25519("ssh-ed25519") {
private final Logger logger = LoggerFactory.getLogger(KeyType.class);
private final Logger log = LoggerFactory.getLogger(KeyType.class);
@Override
public PublicKey readPubKeyFromBuffer(String type, Buffer<?> buf) throws GeneralSecurityException {
public PublicKey readPubKeyFromBuffer(Buffer<?> buf) throws GeneralSecurityException {
try {
final int keyLen = buf.readUInt32AsInt();
final byte[] p = new byte[keyLen];
buf.readRawBytes(p);
if (logger.isDebugEnabled()) {
logger.debug(String.format("Key algo: %s, Key curve: 25519, Key Len: %s\np: %s",
type,
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");
GroupElement point = ed25519.getCurve().createPoint(p, true);
EdDSAPublicKeySpec publicSpec = new EdDSAPublicKeySpec(point, ed25519);
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("Ed25519");
EdDSAPublicKeySpec publicSpec = new EdDSAPublicKeySpec(p, ed25519);
return new Ed25519PublicKey(publicSpec);
} catch (Buffer.BufferException be) {
@@ -201,9 +192,9 @@ public enum KeyType {
}
@Override
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
EdDSAPublicKey key = (EdDSAPublicKey) pk;
buf.putString(sType).putBytes(key.getAbyte());
buf.putBytes(key.getAbyte());
}
@Override
@@ -212,12 +203,60 @@ public enum KeyType {
}
},
/** Signed rsa certificate */
RSA_CERT("ssh-rsa-cert-v01@openssh.com") {
@Override
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
return CertUtils.readPubKey(buf, RSA);
}
@Override
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
CertUtils.writePubKeyContentsIntoBuffer(pk, RSA, buf);
}
@Override
protected boolean isMyType(Key key) {
return CertUtils.isCertificateOfType(key, RSA);
}
@Override
public KeyType getParent() {
return RSA;
}
},
/** Signed dsa certificate */
DSA_CERT("ssh-dss-cert-v01@openssh.com") {
@Override
public PublicKey readPubKeyFromBuffer(Buffer<?> buf)
throws GeneralSecurityException {
return CertUtils.readPubKey(buf, DSA);
}
@Override
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
CertUtils.writePubKeyContentsIntoBuffer(pk, DSA, buf);
}
@Override
protected boolean isMyType(Key key) {
return CertUtils.isCertificateOfType(key, DSA);
}
@Override
public KeyType getParent() {
return KeyType.DSA;
}
},
/** 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
@@ -225,33 +264,53 @@ public enum KeyType {
throw new UnsupportedOperationException("Don't know how to encode key: " + pk);
}
@Override
protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf) {
throw new UnsupportedOperationException("Don't know how to encode key: " + pk);
}
@Override
protected boolean isMyType(Key key) {
return false;
}
};
private static final String NISTP_CURVE = "nistp256";
protected final String sType;
private KeyType(String type) {
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);
protected abstract void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer<?> buf);
public void putPubKeyIntoBuffer(PublicKey pk, Buffer<?> buf) {
writePubKeyContentsIntoBuffer(pk, buf.putString(sType));
}
protected abstract boolean isMyType(Key key);
public static KeyType fromKey(Key key) {
KeyType result = UNKNOWN;
for (KeyType kt : values())
if (kt.isMyType((key)))
return kt;
return UNKNOWN;
if (kt.isMyType((key)) && (result == UNKNOWN || kt.isSubType(result)))
result = kt;
return result;
}
private boolean isSubType(KeyType keyType) {
for (KeyType node = this; node != null; node = node.getParent()) {
if (keyType == node) {
return true;
}
}
return false;
}
public KeyType getParent() {
return null;
}
public static KeyType fromString(String sType) {
@@ -266,4 +325,143 @@ public enum KeyType {
return sType;
}
static class CertUtils {
@SuppressWarnings("unchecked")
static <T extends PublicKey> Certificate<T> readPubKey(Buffer<?> buf, KeyType innerKeyType) throws GeneralSecurityException {
Certificate.Builder<T> builder = Certificate.getBuilder();
try {
builder.nonce(buf.readBytes());
builder.publicKey((T) innerKeyType.readPubKeyFromBuffer(buf));
builder.serial(buf.readUInt64AsBigInteger());
builder.type(buf.readUInt32());
builder.id(buf.readString());
builder.validPrincipals(unpackList(buf.readBytes()));
builder.validAfter(dateFromEpoch(buf.readUInt64AsBigInteger()));
builder.validBefore(dateFromEpoch(buf.readUInt64AsBigInteger()));
builder.critOptions(unpackMap(buf.readBytes()));
builder.extensions(unpackMap(buf.readBytes()));
buf.readString(); // reserved
builder.signatureKey(buf.readBytes());
builder.signature(buf.readBytes());
} catch (Buffer.BufferException be) {
throw new GeneralSecurityException(be);
}
return builder.build();
}
static void writePubKeyContentsIntoBuffer(PublicKey publicKey, KeyType innerKeyType, Buffer<?> buf) {
Certificate<PublicKey> certificate = toCertificate(publicKey);
buf.putBytes(certificate.getNonce());
innerKeyType.writePubKeyContentsIntoBuffer(certificate.getKey(), buf);
buf.putUInt64(certificate.getSerial())
.putUInt32(certificate.getType())
.putString(certificate.getId())
.putBytes(packList(certificate.getValidPrincipals()))
.putUInt64(epochFromDate(certificate.getValidAfter()))
.putUInt64(epochFromDate(certificate.getValidBefore()))
.putBytes(packMap(certificate.getCritOptions()))
.putBytes(packMap(certificate.getExtensions()))
.putString("") // reserved
.putBytes(certificate.getSignatureKey())
.putBytes(certificate.getSignature());
}
static boolean isCertificateOfType(Key key, KeyType innerKeyType) {
if (!(key instanceof Certificate)) {
return false;
}
@SuppressWarnings("unchecked")
Key innerKey = ((Certificate<PublicKey>) key).getKey();
return innerKeyType.isMyType(innerKey);
}
@SuppressWarnings("unchecked")
static Certificate<PublicKey> toCertificate(PublicKey key) {
if (!(key instanceof Certificate)) {
throw new UnsupportedOperationException("Can't convert non-certificate key " +
key.getAlgorithm() + " to certificate");
}
return ((Certificate<PublicKey>) key);
}
private static Date dateFromEpoch(BigInteger seconds) {
BigInteger maxValue = BigInteger.valueOf(Long.MAX_VALUE / 1000);
if (seconds.compareTo(maxValue) > 0) {
return new Date(maxValue.longValue() * 1000);
} else {
return new Date(seconds.longValue() * 1000);
}
}
private static BigInteger epochFromDate(Date date) {
long time = date.getTime() / 1000;
if (time >= Long.MAX_VALUE / 1000) {
// Dealing with the signed longs in Java. Since the protocol requires a unix timestamp in milliseconds,
// and since Java can store numbers not bigger than 2^63-1 as `long`, we can't distinguish dates
// after `new Date(Long.MAX_VALUE / 1000)`. It's unlikely that someone uses certificate valid until
// the 10 January of 294247 year. Supposing that such dates are unlimited.
// OpenSSH expects to see 0xFF_FF_FF_FF_FF_FF_FF_FF in such cases.
return Buffer.MAX_UINT64_VALUE;
} else {
return BigInteger.valueOf(time);
}
}
private static String unpackString(byte[] packedString) throws BufferException {
if (packedString.length == 0) {
return "";
}
return new Buffer.PlainBuffer(packedString).readString();
}
private static List<String> unpackList(byte[] packedString) throws BufferException {
List<String> list = new ArrayList<String>();
Buffer<?> buf = new Buffer.PlainBuffer(packedString);
while (buf.available() > 0) {
list.add(buf.readString());
}
return list;
}
private static Map<String, String> unpackMap(byte[] packedString) throws BufferException {
Map<String, String> map = new LinkedHashMap<String, String>();
Buffer<?> buf = new Buffer.PlainBuffer(packedString);
while (buf.available() > 0) {
String name = buf.readString();
String data = unpackString(buf.readStringAsBytes());
map.put(name, data);
}
return map;
}
private static byte[] packString(String data) {
if (data == null || data.isEmpty()) {
return "".getBytes();
}
return new Buffer.PlainBuffer().putString(data).getCompactData();
}
private static byte[] packList(Iterable<String> strings) {
Buffer<?> buf = new Buffer.PlainBuffer();
for (String string : strings) {
buf.putString(string);
}
return buf.getCompactData();
}
private static byte[] packMap(Map<String, String> map) {
Buffer<?> buf = new Buffer.PlainBuffer();
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys);
for (String key : keys) {
buf.putString(key);
String value = map.get(key);
buf.putString(packString(value));
}
return buf.getCompactData();
}
}
}

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

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