mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4d50c6a24 |
55
.github/workflows/gradle.yml
vendored
55
.github/workflows/gradle.yml
vendored
@@ -1,55 +0,0 @@
|
||||
# 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
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -21,6 +21,3 @@ sshj.jar
|
||||
|
||||
# MacOS X
|
||||
.DS_Store
|
||||
|
||||
# VSCode
|
||||
.metals/
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
11.0
|
||||
30
.travis.yml
Normal file
30
.travis.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
language: java
|
||||
dist: trusty
|
||||
sudo: required
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- openjdk8
|
||||
- oraclejdk9
|
||||
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
|
||||
before_install:
|
||||
- pip install --user codecov
|
||||
|
||||
script:
|
||||
- ./gradlew check
|
||||
- ./gradlew integrationTest
|
||||
|
||||
after_success:
|
||||
- codecov
|
||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"java.checkstyle.configuration": "${workspaceFolder}/gradle/config/checkstyle/checkstyle.xml",
|
||||
"files.watcherExclude": {
|
||||
"**/target": true
|
||||
}
|
||||
}
|
||||
2
NOTICE
2
NOTICE
@@ -15,7 +15,7 @@ The Apache Software Foundation (http://www.apache.org/):
|
||||
== in this case for the SSHD distribution. ==
|
||||
=========================================================================
|
||||
|
||||
This product contains software developed by JCraft,Inc. and subject to
|
||||
This product contains software developped by JCraft,Inc. and subject to
|
||||
the following license:
|
||||
|
||||
Copyright (c) 2002,2003,2004,2005,2006,2007,2008 Atsuhiko Yamanaka, JCraft,Inc.
|
||||
|
||||
72
README.adoc
72
README.adoc
@@ -1,7 +1,7 @@
|
||||
= sshj - SSHv2 library for Java
|
||||
Jeroen van Erp
|
||||
:sshj_groupid: com.hierynomus
|
||||
:sshj_version: 0.31.0
|
||||
:sshj_version: 0.27.0
|
||||
:source-highlighter: pygments
|
||||
|
||||
image:https://api.bintray.com/packages/hierynomus/maven/sshj/images/download.svg[link="https://bintray.com/hierynomus/maven/sshj/_latestVersion"]
|
||||
@@ -64,7 +64,7 @@ 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}`, `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}`
|
||||
`aes{128,192,256}-{cbc,ctr}`, `blowfish-{cbc,ctr}`, `3des-{cbc,ctr}`, `twofish{128,192,256}-{cbc,ctr}`, `twofish-cbc`, `serpent{128,192,256}-{cbc,ctr}`, `idea-{cbc,ctr}`, `cast128-{cbc,ctr}`, `arcfour`, `arcfour{128,256}`
|
||||
SSHJ also supports the following extended (non official) ciphers: `camellia{128,192,256}-{cbc,ctr}`, `camellia{128,192,256}-{cbc,ctr}@openssh.org`
|
||||
|
||||
key exchange::
|
||||
@@ -73,12 +73,12 @@ key exchange::
|
||||
`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:
|
||||
SSHJ also supports the following extended (non official) key exchange algoriths:
|
||||
`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`, `ecdsa-sha2-nistp384`, `ecdsa-sha2-nistp521`, `ssh-ed25519`, `ssh-rsa2-256`, `ssh-rsa2-512`
|
||||
`ssh-rsa`, `ssh-dss`, `ecdsa-sha2-nistp256`, `ecdsa-sha2-nistp384`, `ecdsa-sha2-nistp521`, `ssh-ed25519`
|
||||
|
||||
mac::
|
||||
`hmac-md5`, `hmac-md5-96`, `hmac-sha1`, `hmac-sha1-96`, `hmac-sha2-256`, `hmac-sha2-512`, `hmac-ripemd160`, `hmac-ripemd160@openssh.com`
|
||||
@@ -105,34 +105,6 @@ Issue tracker: https://github.com/hierynomus/sshj/issues
|
||||
Fork away!
|
||||
|
||||
== Release history
|
||||
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.
|
||||
@@ -155,32 +127,32 @@ SSHJ 0.24.0 (2018-04-04)::
|
||||
* 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'
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/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/pulls/341[#341]: Fixed path walking during recursive copy
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/338[#338]: Added ConsolePasswordFinder to read password from stdin
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/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)
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/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
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/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
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/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
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/294[#294]: Reference ED25519 by constant instead of name
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/293[#293], https://github.com/hierynomus/sshj/pulls/295[#295] and https://github.com/hierynomus/sshj/pulls/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
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/291[#291]: Fixed sshj.properties loading and chained exception messages
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/284[#284]: Correctly catch interrupt in keepalive thread
|
||||
* Fixed https://github.com/hierynomus/sshj/issues/292[#292]: Pass the configured RandomFactory to Diffie Hellmann 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)::
|
||||
@@ -189,11 +161,11 @@ SSHJ 0.19.0 (2016-11-25)::
|
||||
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])
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/271[#271]: Load known_hosts without requiring BouncyCastle
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/269[#269]: Brought back Java6 support by popular demand
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/267[#267]: Added support for per connection logging (Fixes https://github.com/hierynomus/sshj/issues/264[#264])
|
||||
* Merged https://github.com/hierynomus/sshj/pulls/262[#262], https://github.com/hierynomus/sshj/pulls/265[#265] and https://github.com/hierynomus/sshj/pulls/266[#266]: Added PKCS5 key file support
|
||||
* Fixed toString of sftp FileAttributes (Fixes https://github.com/hierynomus/sshj/pulls/258[#258])
|
||||
* Fixed https://github.com/hierynomus/sshj/issues/255[#255]: No longer depending on 'privately marked' classes in `net.i2p.crypto.eddsa.math` package, fixes OSGI dependencies
|
||||
SSHJ 0.17.2 (2016-07-07)::
|
||||
* Treating SSH Server identification line ending in '\n' instead of '\r\n' leniently.
|
||||
@@ -203,7 +175,7 @@ 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
|
||||
* Fixed https://github.com/hierynomus/sshj/issues/252[#252] (via: https://github.com/hierynomus/sshj/pulls/253[#253]): Same name subdirs are no longer merged by accident
|
||||
SSHJ 0.16.0 (2016-04-11)::
|
||||
* Fixed https://github.com/hierynomus/sshj/issues/239[#239]: Remote port forwards did not work if you used the empty string as address, or a catch-all address.
|
||||
* Fixed https://github.com/hierynomus/sshj/issues/242[#242]: Added OSGI headers to sources jar manifest
|
||||
|
||||
@@ -17,7 +17,7 @@ configurations {
|
||||
pom
|
||||
}
|
||||
|
||||
def bouncycastleVersion = "1.67"
|
||||
def bouncycastleVersion = "1.50"
|
||||
|
||||
dependencies {
|
||||
compile "org.slf4j:slf4j-api:1.7.7"
|
||||
|
||||
71
build.gradle
71
build.gradle
@@ -6,15 +6,16 @@ plugins {
|
||||
id "java"
|
||||
id "groovy"
|
||||
id "jacoco"
|
||||
id "com.github.blindpirate.osgi" version '0.0.3'
|
||||
id "osgi"
|
||||
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 'pl.allegro.tech.build.axion-release' version '1.9.2'
|
||||
id "com.bmuschko.docker-remote-api" version "3.2.1"
|
||||
id "com.github.hierynomus.license" version "0.12.1"
|
||||
id "com.jfrog.bintray" version "1.8.5"
|
||||
id "com.jfrog.bintray" version "1.7"
|
||||
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'
|
||||
id 'ru.vyarus.animalsniffer' version '1.4.2'
|
||||
}
|
||||
|
||||
group = "com.hierynomus"
|
||||
@@ -38,29 +39,33 @@ repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
|
||||
configurations.compile.transitive = false
|
||||
|
||||
def bouncycastleVersion = "1.68"
|
||||
def bouncycastleVersion = "1.60"
|
||||
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"
|
||||
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||
|
||||
implementation "net.i2p.crypto:eddsa:0.3.0"
|
||||
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"
|
||||
|
||||
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'
|
||||
compile "net.i2p.crypto:eddsa:0.3.0"
|
||||
|
||||
testCompile "junit:junit:4.12"
|
||||
testCompile 'org.spockframework:spock-core:1.3-groovy-2.4'
|
||||
testCompile "org.mockito:mockito-core:2.28.2"
|
||||
testCompile "org.apache.sshd:sshd-core:$sshdVersion"
|
||||
testCompile "org.apache.sshd:sshd-sftp:$sshdVersion"
|
||||
testCompile "org.apache.sshd:sshd-scp:$sshdVersion"
|
||||
testRuntime "ch.qos.logback:logback-classic:1.2.3"
|
||||
testCompile 'org.glassfish.grizzly:grizzly-http-server:2.4.4'
|
||||
testCompile 'org.apache.httpcomponents:httpclient:4.5.9'
|
||||
|
||||
}
|
||||
|
||||
@@ -73,10 +78,6 @@ license {
|
||||
excludes(['**/djb/Curve25519.java', '**/sshj/common/Base64.java', '**/org/mindrot/jbcrypt/*.java'])
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -84,11 +85,6 @@ if (JavaVersion.current().isJava8Compatible()) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
compileJava {
|
||||
options.compilerArgs.addAll(['--release', '7'])
|
||||
}
|
||||
|
||||
task writeSshjVersionProperties {
|
||||
doLast {
|
||||
project.file("${project.buildDir}/resources/main").mkdirs()
|
||||
@@ -133,8 +129,8 @@ sourcesJar {
|
||||
}
|
||||
|
||||
configurations {
|
||||
integrationTestImplementation.extendsFrom testImplementation
|
||||
integrationTestRuntimeOnly.extendsFrom testRuntimeOnly
|
||||
integrationTestCompile.extendsFrom testCompile
|
||||
integrationTestRuntime.extendsFrom testRuntime
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
@@ -227,7 +223,7 @@ if (project.hasProperty("bintrayUsername") && project.hasProperty("bintrayApiKey
|
||||
publications = ["maven"]
|
||||
pkg {
|
||||
repo = "maven"
|
||||
name = "${project.name}"
|
||||
name = project.name
|
||||
licenses = ["Apache-2.0"]
|
||||
vcsUrl = "https://github.com/hierynomus/sshj.git"
|
||||
labels = ["ssh", "sftp", "secure-shell", "network", "file-transfer"]
|
||||
@@ -261,23 +257,22 @@ jacocoTestReport {
|
||||
|
||||
task buildItestImage(type: DockerBuildImage) {
|
||||
inputDir = file('src/itest/docker-image')
|
||||
images.add('sshj/sshd-itest:latest')
|
||||
tag = 'sshj/sshd-itest'
|
||||
}
|
||||
|
||||
task createItestContainer(type: DockerCreateContainer) {
|
||||
dependsOn buildItestImage
|
||||
targetImageId buildItestImage.getImageId()
|
||||
hostConfig.portBindings = ['2222:22']
|
||||
hostConfig.autoRemove = true
|
||||
targetImageId { buildItestImage.getImageId() }
|
||||
portBindings = ['2222:22']
|
||||
}
|
||||
|
||||
task startItestContainer(type: DockerStartContainer) {
|
||||
dependsOn createItestContainer
|
||||
targetContainerId createItestContainer.getContainerId()
|
||||
targetContainerId { createItestContainer.getContainerId() }
|
||||
}
|
||||
|
||||
task stopItestContainer(type: DockerStopContainer) {
|
||||
targetContainerId createItestContainer.getContainerId()
|
||||
targetContainerId { createItestContainer.getContainerId() }
|
||||
}
|
||||
|
||||
task forkedUploadRelease(type: GradleBuild) {
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
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 InMemoryHostKeyVerifier(entry, Charset.defaultCharset()));
|
||||
ssh.connect("localhost");
|
||||
try {
|
||||
ssh.authPublickey(System.getProperty("user.name"));
|
||||
ssh.newSCPFileTransfer().download("test_file", new FileSystemFile("/tmp/"));
|
||||
} finally {
|
||||
ssh.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public static class InMemoryHostKeyVerifier implements HostKeyVerifier {
|
||||
|
||||
private final List<OpenSSHKnownHosts.KnownHostEntry> entries = new ArrayList<OpenSSHKnownHosts.KnownHostEntry>();
|
||||
|
||||
public InMemoryHostKeyVerifier(InputStream inputStream, Charset charset) throws IOException {
|
||||
final OpenSSHKnownHosts.EntryFactory entryFactory = new OpenSSHKnownHosts.EntryFactory();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, charset));
|
||||
while(reader.ready()) {
|
||||
String line = reader.readLine();
|
||||
try {
|
||||
OpenSSHKnownHosts.KnownHostEntry entry = entryFactory.parseEntry(line);
|
||||
if (entry != null) {
|
||||
entries.add(entry);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//log error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(String hostname, int port, PublicKey key) {
|
||||
final KeyType type = KeyType.fromKey(key);
|
||||
if (type == KeyType.UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (OpenSSHKnownHosts.KnownHostEntry e : entries) {
|
||||
try {
|
||||
if (e.appliesTo(type, hostname) && e.verify(key)) {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
//log error
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip
|
||||
distributionSha256Sum=8626cbf206b4e201ade7b87779090690447054bc93f052954c78480fa6ed186e
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
51
gradlew
vendored
51
gradlew
vendored
@@ -1,21 +1,5 @@
|
||||
#!/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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
@@ -44,7 +28,7 @@ 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"'
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
@@ -125,8 +109,8 @@ if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
@@ -154,19 +138,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
(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
|
||||
|
||||
@@ -175,9 +159,14 @@ save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# 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"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
21
gradlew.bat
vendored
21
gradlew.bat
vendored
@@ -1,19 +1,3 @@
|
||||
@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
|
||||
@@ -29,11 +13,8 @@ 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"
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
@@ -7,7 +7,6 @@ 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 \
|
||||
@@ -21,4 +20,4 @@ RUN \
|
||||
chmod 644 /etc/ssh/ssh_host_ed25519_key.pub && \
|
||||
chown -R sshj:sshj /home/sshj
|
||||
|
||||
ENTRYPOINT ["/sbin/tini", "/entrypoint.sh", "-o", "LogLevel=DEBUG2"]
|
||||
ENTRYPOINT ["/sbin/tini", "/entrypoint.sh"]
|
||||
@@ -5,5 +5,3 @@ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ8ww4hJG/gHJYdkjTTBDF1GNz+228nuWprPV+NbQauA
|
||||
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
|
||||
|
||||
@@ -130,7 +130,3 @@ Subsystem sftp /usr/lib/ssh/sftp-server
|
||||
|
||||
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1
|
||||
macs umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-ripemd160-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hmac-ripemd160@openssh.com
|
||||
|
||||
TrustedUserCAKeys /etc/ssh/users_rsa_ca.pub
|
||||
|
||||
Ciphers 3des-cbc,blowfish-cbc,aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
|
||||
@@ -1 +0,0 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDN70b/cYHZQMD1YW0mlncXqC2l++sEWrVYlIUCzNxNhRYjI4UmEVEq3ru1h6K3ZVAJi1DcZuf5ne1ZXtwJ1Uw1JA4wGdKw+9TwAb5Gubn+VEowgt62kLAPeChiPucTXD0FDDhIUOBv3KxytdrJIYAtzZT27STsBiDF1+7Ld3wk/1Dg9NAaI6q40PmuicTEACQRHn5snI1t9+LgZTd3/PPE5pjJM0ow9+r6mlUUM5oHCk5sZ8DBuRR1Ram4sxp/LFQM+9feMmW3ZM2C5AN0JG4A7NXnlwiTKmNVrGI0iFucBBKhjxN1qdgBF11/42cCrerC9UW1auTTi9mqwEIqBGL30VOPy+dCPQQViP+C09CBgyr3wpZciPKP1mvmcOkC5FDzKg9e3v1JBq0fqZgwt+PPG8cGnxRCGEQ+ZMLDuAixkQUEwDWeMskHLkbjUEiVZydViCPSzFczGtKatQiQVZA5Zx0Gn2sUaQjykhWzqKNL8oIbolEdkH9ubOZWNi0brzU= root@sshj
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/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
|
||||
@@ -15,9 +15,10 @@
|
||||
*/
|
||||
package com.hierynomus.sshj
|
||||
|
||||
import com.hierynomus.sshj.key.KeyAlgorithms
|
||||
import com.hierynomus.sshj.signature.SignatureEdDSA
|
||||
import net.schmizz.sshj.DefaultConfig
|
||||
import net.schmizz.sshj.SSHClient
|
||||
import net.schmizz.sshj.signature.SignatureECDSA
|
||||
import net.schmizz.sshj.transport.TransportException
|
||||
import net.schmizz.sshj.userauth.UserAuthException
|
||||
import spock.lang.Unroll
|
||||
@@ -28,7 +29,7 @@ class IntegrationSpec extends IntegrationBaseSpec {
|
||||
def "should accept correct key for #signatureName"() {
|
||||
given:
|
||||
def config = new DefaultConfig()
|
||||
config.setKeyAlgorithms(Collections.singletonList(signatureFactory))
|
||||
config.setSignatureFactories(signatureFactory)
|
||||
SSHClient sshClient = new SSHClient(config)
|
||||
sshClient.addHostKeyVerifier(fingerprint) // test-containers/ssh_host_ecdsa_key's fingerprint
|
||||
|
||||
@@ -39,7 +40,7 @@ class IntegrationSpec extends IntegrationBaseSpec {
|
||||
sshClient.isConnected()
|
||||
|
||||
where:
|
||||
signatureFactory << [KeyAlgorithms.ECDSASHANistp256(), KeyAlgorithms.EdDSA25519()]
|
||||
signatureFactory << [new SignatureECDSA.Factory256(), new SignatureEdDSA.Factory()]
|
||||
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()
|
||||
}
|
||||
@@ -77,8 +78,6 @@ class IntegrationSpec extends IntegrationBaseSpec {
|
||||
"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"() {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,9 @@ package com.hierynomus.sshj.transport.mac
|
||||
|
||||
import com.hierynomus.sshj.IntegrationBaseSpec
|
||||
import net.schmizz.sshj.DefaultConfig
|
||||
import net.schmizz.sshj.transport.mac.HMACRIPEMD160
|
||||
import net.schmizz.sshj.transport.mac.HMACSHA2256
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Unroll
|
||||
|
||||
class MacSpec extends IntegrationBaseSpec {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
|
||||
1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQTL30WEnuOFUBsMXsTjIm3DN/n1nlD9
|
||||
Y6waHzsRQ0Ua80RfHSv75ZdrL6kz1zEZyE509VKHphHAeTh7bx+Ic34fxxXg8SeUu1J3GM
|
||||
aApU0mvDHjBRtmY/QqFGbNUh28EhoAAADYHWlHLx1pRy8AAAATZWNkc2Etc2hhMi1uaXN0
|
||||
cDM4NAAAAAhuaXN0cDM4NAAAAGEEy99FhJ7jhVAbDF7E4yJtwzf59Z5Q/WOsGh87EUNFGv
|
||||
NEXx0r++WXay+pM9cxGchOdPVSh6YRwHk4e28fiHN+H8cV4PEnlLtSdxjGgKVNJrwx4wUb
|
||||
ZmP0KhRmzVIdvBIaAAAAMQD3sx28SrtkuhN+Yu06BAoFLMMgneIqguM3jowaz0LWfP1Nhx
|
||||
Rnh9tNKM6YYvygCggAAAAPZmhlbm5la2VATGFwdG9w
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
@@ -1,12 +0,0 @@
|
||||
-----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-----
|
||||
@@ -1,39 +0,0 @@
|
||||
-----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-----
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQxnbF27Lzr9VvNlac6fNKpRV5TtqPPBzcsX29H1lu59l0IHylhHOlDgH2/e6YNnedf2o8zh/aIxUN+LPbjVLCa9XmztaI4c+HLeKPmZSlFc6fdrxvJUiN2tppVrAvrjan3xwsoH1YoSMpoPDrfdoPvHNIiiapBuhVmswc2O8hqfJ3dTqP2aejJ1cPVwi5x5nHhL8C/whCu70CJlgnusB9nDPeKn1hZyBPTIiiENsFJft+xfbsoXq3Eh9FckImDRA7SQ5igxCYtgm2RUCnCLF1Xb1XHaDk8EpcNDXYXAZdOdkbfq9hhnueDXY9X7EzILXE8t1efOs1H+U7gEa1PXgZglvBUzeCMEOtx5q9prJVbhKMWupHlcMuOV0oB8q0IcRq8u/XoN/V4DCc+UYDCY4OVGpMe8vmjEFCJu82MPNWm9+oSwVGo/93gBtiMBGwoKR67c/NQj6urkC3BnnZcqAZ2DXfBRGgCQiw1eicqj3Zq8ueiaqyR1Nil8EQ5QxJk70= lagunov@unit-1381
|
||||
@@ -1,38 +0,0 @@
|
||||
-----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-----
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* 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";
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ 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) {
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SignatureEdDSA extends AbstractSignature {
|
||||
}
|
||||
|
||||
SignatureEdDSA() {
|
||||
super(getEngine(), KeyType.ED25519.toString());
|
||||
super(getEngine());
|
||||
}
|
||||
|
||||
private static EdDSAEngine getEngine() {
|
||||
|
||||
@@ -79,9 +79,11 @@ public class IdentificationStringParser {
|
||||
}
|
||||
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);
|
||||
log.warn("Server identification has bad line ending, was expecting a '\\r\\n' however got: '{}' (hex: {})", (char) (bytes[bytes.length - 2] & 0xFF), Integer.toHexString(bytes[bytes.length - 2] & 0xFF));
|
||||
log.warn("Will treat the identification of this server '{}' leniently", ident);
|
||||
return ident;
|
||||
// log.error("Data received up til here was: {}", new String(bytes));
|
||||
// throw new TransportException("Incorrect identification: bad line ending: " + ByteArrayUtils.toHex(bytes, 0, bytes.length));
|
||||
}
|
||||
|
||||
// Strip off the \r\n
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ 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
|
||||
* Factory methods for Diffie Hellmann 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
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
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;
|
||||
@@ -113,16 +111,8 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
||||
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;
|
||||
}
|
||||
}
|
||||
PlainBuffer decrypted = decryptBuffer(privateKeyBuffer, cipherName, kdfName, kdfOptions);
|
||||
return readUnencrypted(decrypted, publicKey);
|
||||
// throw new IOException("Cannot read encrypted keypair with " + cipherName + " yet.");
|
||||
}
|
||||
}
|
||||
@@ -143,12 +133,9 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
||||
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);
|
||||
@@ -197,7 +184,7 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
||||
int checkInt1 = keyBuffer.readUInt32AsInt(); // uint32 checkint1
|
||||
int checkInt2 = keyBuffer.readUInt32AsInt(); // uint32 checkint2
|
||||
if (checkInt1 != checkInt2) {
|
||||
throw new KeyDecryptionFailedException();
|
||||
throw new IOException("The checkInts differed, the key was not correctly decoded.");
|
||||
}
|
||||
// The private key section contains both the public key and the private key
|
||||
String keyType = keyBuffer.readString(); // string keytype
|
||||
@@ -220,7 +207,7 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
||||
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)));
|
||||
kp = new KeyPair(publicKey, SecurityUtils.getKeyFactory("RSA").generatePrivate(new RSAPrivateKeySpec(n, d)));
|
||||
break;
|
||||
case ECDSA256:
|
||||
kp = new KeyPair(publicKey, createECDSAPrivateKey(kt, keyBuffer, "P-256"));
|
||||
@@ -252,7 +239,7 @@ public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider {
|
||||
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);
|
||||
return SecurityUtils.getKeyFactory("ECDSA").generatePrivate(pks);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ package net.schmizz.concurrent;
|
||||
* if (t instanceof SomeException)
|
||||
* return (SomeException) t;
|
||||
* else
|
||||
* return new SomeException(t);
|
||||
* return new SomeExcepion(t);
|
||||
* }
|
||||
* };
|
||||
* </pre>
|
||||
|
||||
@@ -30,7 +30,6 @@ public abstract class KeepAlive extends Thread {
|
||||
this.conn = conn;
|
||||
log = conn.getTransport().getConfig().getLoggerFactory().getLogger(getClass());
|
||||
setName(name);
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
public synchronized int getKeepAliveInterval() {
|
||||
|
||||
@@ -15,15 +15,14 @@
|
||||
*/
|
||||
package net.schmizz.sshj;
|
||||
|
||||
import com.hierynomus.sshj.key.KeyAlgorithm;
|
||||
import com.hierynomus.sshj.key.KeyAlgorithms;
|
||||
import net.schmizz.sshj.common.Factory;
|
||||
import com.hierynomus.sshj.signature.SignatureEdDSA;
|
||||
|
||||
import net.schmizz.sshj.common.SecurityUtils;
|
||||
import net.schmizz.sshj.signature.SignatureDSA;
|
||||
import net.schmizz.sshj.signature.SignatureRSA;
|
||||
import net.schmizz.sshj.transport.random.JCERandom;
|
||||
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Registers SpongyCastle as JCE provider.
|
||||
*/
|
||||
@@ -34,14 +33,11 @@ public class AndroidConfig
|
||||
SecurityUtils.registerSecurityProvider("org.spongycastle.jce.provider.BouncyCastleProvider");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void initKeyAlgorithms() {
|
||||
setKeyAlgorithms(Arrays.<Factory.Named<KeyAlgorithm>>asList(
|
||||
KeyAlgorithms.EdDSA25519(),
|
||||
KeyAlgorithms.SSHRSA(),
|
||||
KeyAlgorithms.SSHDSA()
|
||||
));
|
||||
// don't add ECDSA
|
||||
protected void initSignatureFactories() {
|
||||
setSignatureFactories(new SignatureRSA.Factory(), new SignatureDSA.Factory(),
|
||||
// but add EdDSA
|
||||
new SignatureEdDSA.Factory());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
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;
|
||||
@@ -78,11 +77,11 @@ public interface Config {
|
||||
Factory<Random> getRandomFactory();
|
||||
|
||||
/**
|
||||
* Retrieve the list of named factories for {@link com.hierynomus.sshj.key.KeyAlgorithm}
|
||||
* Retrieve the list of named factories for {@link Signature}
|
||||
*
|
||||
* @return a list of named {@link com.hierynomus.sshj.key.KeyAlgorithm} factories
|
||||
* @return a list of named {@link Signature} factories
|
||||
*/
|
||||
List<Factory.Named<KeyAlgorithm>> getKeyAlgorithms();
|
||||
List<Factory.Named<Signature>> getSignatureFactories();
|
||||
|
||||
/**
|
||||
* Returns the software version information for identification during SSH connection initialization. For example,
|
||||
@@ -133,11 +132,11 @@ public interface Config {
|
||||
void setRandomFactory(Factory<Random> randomFactory);
|
||||
|
||||
/**
|
||||
* Set the named factories for {@link KeyAlgorithm}.
|
||||
* Set the named factories for {@link Signature}.
|
||||
*
|
||||
* @param keyAlgorithms a list of named factories
|
||||
* @param signatureFactories a list of named factories
|
||||
*/
|
||||
void setKeyAlgorithms(List<Factory.Named<KeyAlgorithm>> keyAlgorithms);
|
||||
void setSignatureFactories(List<Factory.Named<Signature>> signatureFactories);
|
||||
|
||||
/**
|
||||
* Set the software version information for identification during SSH connection initialization. For example, {@code
|
||||
@@ -161,7 +160,7 @@ public interface Config {
|
||||
/**
|
||||
* Gets whether the client should first wait for a received server ident, before sending the client ident.
|
||||
* <p/>
|
||||
* <strong>NB:</strong> This is non-standard behaviour, and can potentially deadlock if the server also waits on the client ident.
|
||||
* <stong>NB:</stong> This is non-standard behaviour, and can potentially deadlock if the server also waits on the client ident.
|
||||
*
|
||||
* The default value is set to false.
|
||||
*
|
||||
@@ -172,7 +171,7 @@ public interface Config {
|
||||
/**
|
||||
* Sets whether the SSH client should wait for a received server ident, before sending the client ident.
|
||||
* <p/>
|
||||
* <strong>NB:</strong> This is non-standard behaviour, and can potentially deadlock if the server also waits on the client ident.
|
||||
* <stong>NB:</stong> This is non-standard behaviour, and can potentially deadlock if the server also waits on the client ident.
|
||||
|
||||
* @param waitForServerIdentBeforeSendingClientIdent Whether to wait for the server ident.
|
||||
*/
|
||||
|
||||
@@ -15,10 +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;
|
||||
import net.schmizz.sshj.transport.kex.KeyExchange;
|
||||
@@ -42,7 +42,7 @@ 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<KeyAlgorithm>> keyAlgorithms;
|
||||
private List<Factory.Named<Signature>> signatureFactories;
|
||||
private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories;
|
||||
|
||||
private boolean waitForServerIdentBeforeSendingClientIdent = false;
|
||||
@@ -78,6 +78,11 @@ public class ConfigImpl
|
||||
return randomFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Factory.Named<Signature>> getSignatureFactories() {
|
||||
return signatureFactories;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return version;
|
||||
@@ -133,6 +138,15 @@ 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;
|
||||
@@ -158,16 +172,6 @@ public class ConfigImpl
|
||||
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;
|
||||
|
||||
@@ -15,13 +15,10 @@
|
||||
*/
|
||||
package net.schmizz.sshj;
|
||||
|
||||
import com.hierynomus.sshj.key.KeyAlgorithm;
|
||||
import com.hierynomus.sshj.key.KeyAlgorithms;
|
||||
import com.hierynomus.sshj.signature.SignatureEdDSA;
|
||||
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;
|
||||
@@ -29,7 +26,10 @@ 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.transport.cipher.Cipher;
|
||||
import net.schmizz.sshj.signature.SignatureDSA;
|
||||
import net.schmizz.sshj.signature.SignatureECDSA;
|
||||
import net.schmizz.sshj.signature.SignatureRSA;
|
||||
import net.schmizz.sshj.transport.cipher.*;
|
||||
import net.schmizz.sshj.transport.compression.NoneCompression;
|
||||
import net.schmizz.sshj.transport.kex.Curve25519SHA256;
|
||||
import net.schmizz.sshj.transport.kex.DHGexSHA1;
|
||||
@@ -56,7 +56,7 @@ import java.util.*;
|
||||
* <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#setKeyAlgorithms KeyAlgorithm}: {@link net.schmizz.sshj.signature.SignatureRSA}, {@link net.schmizz.sshj.signature.SignatureDSA}</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#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>
|
||||
@@ -76,12 +76,12 @@ public class DefaultConfig
|
||||
setVersion(readVersionFromProperties());
|
||||
final boolean bouncyCastleRegistered = SecurityUtils.isBouncyCastleRegistered();
|
||||
initKeyExchangeFactories(bouncyCastleRegistered);
|
||||
initKeyAlgorithms();
|
||||
initRandomFactory(bouncyCastleRegistered);
|
||||
initFileKeyProviderFactories(bouncyCastleRegistered);
|
||||
initCipherFactories();
|
||||
initCompressionFactories();
|
||||
initMACFactories();
|
||||
initSignatureFactories();
|
||||
setKeepAliveProvider(KeepAliveProvider.HEARTBEAT);
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ public class DefaultConfig
|
||||
|
||||
@Override
|
||||
public void setLoggerFactory(LoggerFactory loggerFactory) {
|
||||
super.setLoggerFactory(loggerFactory);
|
||||
log = loggerFactory.getLogger(getClass());
|
||||
super.setLoggerFactory(loggerFactory);
|
||||
log = loggerFactory.getLogger(getClass());
|
||||
}
|
||||
|
||||
protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) {
|
||||
@@ -127,29 +127,15 @@ public class DefaultConfig
|
||||
ExtendedDHGroups.Group16SHA256(),
|
||||
ExtendedDHGroups.Group16SHA384AtSSH(),
|
||||
ExtendedDHGroups.Group16SHA512AtSSH(),
|
||||
ExtendedDHGroups.Group18SHA512AtSSH(),
|
||||
new ExtInfoClientFactory());
|
||||
ExtendedDHGroups.Group18SHA512AtSSH());
|
||||
} 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(new JCERandom.Factory()));
|
||||
setRandomFactory(new SingletonRandomFactory(bouncyCastleRegistered
|
||||
? new BouncyCastleRandom.Factory() : new JCERandom.Factory()));
|
||||
}
|
||||
|
||||
protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) {
|
||||
@@ -172,8 +158,6 @@ public class DefaultConfig
|
||||
BlockCiphers.AES192CTR(),
|
||||
BlockCiphers.AES256CBC(),
|
||||
BlockCiphers.AES256CTR(),
|
||||
GcmCiphers.AES128GCM(),
|
||||
GcmCiphers.AES256GCM(),
|
||||
BlockCiphers.BlowfishCBC(),
|
||||
BlockCiphers.BlowfishCTR(),
|
||||
BlockCiphers.Cast128CBC(),
|
||||
@@ -223,6 +207,18 @@ public class DefaultConfig
|
||||
log.debug("Available cipher factories: {}", avail);
|
||||
}
|
||||
|
||||
protected void initSignatureFactories() {
|
||||
setSignatureFactories(
|
||||
new SignatureEdDSA.Factory(),
|
||||
new SignatureECDSA.Factory256(),
|
||||
new SignatureECDSA.Factory384(),
|
||||
new SignatureECDSA.Factory521(),
|
||||
new SignatureRSA.Factory(),
|
||||
new SignatureRSA.FactoryCERT(),
|
||||
new SignatureDSA.Factory()
|
||||
);
|
||||
}
|
||||
|
||||
protected void initMACFactories() {
|
||||
setMACFactories(
|
||||
Macs.HMACSHA1(),
|
||||
|
||||
@@ -515,7 +515,7 @@ public class SSHClient
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for creating a {@link KeyProvider} instance from given location on the file system. Creates a
|
||||
* Utility function for createing 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)}.
|
||||
*
|
||||
@@ -722,19 +722,6 @@ 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.
|
||||
*
|
||||
@@ -767,7 +754,7 @@ public class SSHClient
|
||||
|
||||
/**
|
||||
* Adds {@code zlib} compression to preferred compression algorithms. There is no guarantee that it will be
|
||||
* successfully negotiated.
|
||||
* successfully negotiatied.
|
||||
* <p/>
|
||||
* If the client is already connected renegotiation is done; otherwise this method simply returns (and compression
|
||||
* will be negotiated during connection establishment).
|
||||
|
||||
@@ -53,10 +53,6 @@ public abstract class SocketClient {
|
||||
this.defaultPort = defaultPort;
|
||||
}
|
||||
|
||||
protected InetSocketAddress makeInetSocketAddress(String hostname, int port) {
|
||||
return new InetSocketAddress(hostname, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to a host via a proxy.
|
||||
* @param hostname The host name to connect to.
|
||||
@@ -87,7 +83,7 @@ public abstract class SocketClient {
|
||||
} else {
|
||||
socket = new Socket(proxy);
|
||||
}
|
||||
socket.connect(makeInetSocketAddress(hostname, port), connectTimeout);
|
||||
socket.connect(new InetSocketAddress(hostname, port), connectTimeout);
|
||||
onConnect();
|
||||
}
|
||||
|
||||
@@ -135,7 +131,7 @@ public abstract class SocketClient {
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
socket = socketFactory.createSocket();
|
||||
socket.connect(makeInetSocketAddress(hostname, port), connectTimeout);
|
||||
socket.connect(new InetSocketAddress(hostname, port), connectTimeout);
|
||||
onConnect();
|
||||
}
|
||||
}
|
||||
@@ -148,7 +144,7 @@ public abstract class SocketClient {
|
||||
this.port = port;
|
||||
socket = socketFactory.createSocket();
|
||||
socket.bind(new InetSocketAddress(localAddr, localPort));
|
||||
socket.connect(makeInetSocketAddress(hostname, port), connectTimeout);
|
||||
socket.connect(new InetSocketAddress(hostname, port), connectTimeout);
|
||||
onConnect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.schmizz.sshj.common;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Encodes and decodes to and from Base64 notation.</p>
|
||||
* <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
|
||||
@@ -77,7 +76,7 @@ package net.schmizz.sshj.common;
|
||||
* <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>
|
||||
* <li><em>Throws exceptions instead of returning null values.</em> Because some operations
|
||||
* (especially those that may permit the GZIP option) use IO streams, there
|
||||
* is a possibility of an java.io.IOException being thrown. After some discussion and
|
||||
* is a possiblity of an java.io.IOException being thrown. After some discussion and
|
||||
* thought, I've changed the behavior of the methods to throw java.io.IOExceptions
|
||||
* rather than return null if ever there's an error. I think this is more
|
||||
* appropriate, though it will require some changes to your code. Sorry,
|
||||
@@ -477,7 +476,7 @@ public class Base64
|
||||
* anywhere along their length by specifying
|
||||
* <var>srcOffset</var> and <var>destOffset</var>.
|
||||
* This method does not check to make sure your arrays
|
||||
* are large enough to accommodate <var>srcOffset</var> + 3 for
|
||||
* are large enough to accomodate <var>srcOffset</var> + 3 for
|
||||
* the <var>source</var> array or <var>destOffset</var> + 4 for
|
||||
* the <var>destination</var> array.
|
||||
* The actual number of significant bytes in your array is
|
||||
@@ -1008,7 +1007,7 @@ public class Base64
|
||||
* anywhere along their length by specifying
|
||||
* <var>srcOffset</var> and <var>destOffset</var>.
|
||||
* This method does not check to make sure your arrays
|
||||
* are large enough to accommodate <var>srcOffset</var> + 4 for
|
||||
* are large enough to accomodate <var>srcOffset</var> + 4 for
|
||||
* the <var>source</var> array or <var>destOffset</var> + 3 for
|
||||
* the <var>destination</var> array.
|
||||
* This method returns the actual number of bytes that
|
||||
@@ -1360,7 +1359,7 @@ public class Base64
|
||||
@Override
|
||||
public Class<?> resolveClass(java.io.ObjectStreamClass streamClass)
|
||||
throws java.io.IOException, ClassNotFoundException {
|
||||
Class<?> c = Class.forName(streamClass.getName(), false, loader);
|
||||
Class c = Class.forName(streamClass.getName(), false, loader);
|
||||
if( c == null ){
|
||||
return super.resolveClass(streamClass);
|
||||
} else {
|
||||
@@ -1929,7 +1928,7 @@ public class Base64
|
||||
if( suspendEncoding ) {
|
||||
this.out.write( theByte );
|
||||
return;
|
||||
} // end if: suspended
|
||||
} // end if: supsended
|
||||
|
||||
// Encode?
|
||||
if( encode ) {
|
||||
@@ -1984,7 +1983,7 @@ public class Base64
|
||||
if( suspendEncoding ) {
|
||||
this.out.write( theBytes, off, len );
|
||||
return;
|
||||
} // end if: suspended
|
||||
} // end if: supsended
|
||||
|
||||
for( int i = 0; i < len; i++ ) {
|
||||
write( theBytes[ off + i ] );
|
||||
|
||||
@@ -21,7 +21,6 @@ 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
|
||||
@@ -56,10 +55,10 @@ 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
|
||||
private static final BigInteger MAX_UINT64_VALUE = BigInteger.ONE
|
||||
.shiftLeft(64)
|
||||
.subtract(BigInteger.ONE);
|
||||
|
||||
@@ -67,7 +66,7 @@ public class Buffer<T extends Buffer<T>> {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
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;
|
||||
@@ -88,7 +87,7 @@ class ECDSAVariationsAdapter {
|
||||
ECPoint p = new ECPoint(bigX, bigY);
|
||||
ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(p, ecCurveSpec);
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KeyAlgorithm.ECDSA);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA");
|
||||
return keyFactory.generatePublic(publicKeySpec);
|
||||
} catch (Exception ex) {
|
||||
throw new GeneralSecurityException(ex);
|
||||
@@ -104,7 +103,7 @@ class ECDSAVariationsAdapter {
|
||||
}
|
||||
|
||||
static boolean isECKeyWithFieldSize(Key key, int fieldSize) {
|
||||
return (KeyAlgorithm.ECDSA.equals(key.getAlgorithm()) || KeyAlgorithm.EC_KEYSTORE.equals(key.getAlgorithm()))
|
||||
return "ECDSA".equals(key.getAlgorithm())
|
||||
&& fieldSizeFromKey((ECKey) key) == fieldSize;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.util.List;
|
||||
public interface Factory<T> {
|
||||
|
||||
/**
|
||||
* Interface for a named factory. Named factories are simply factories that are identified by a name. Such names are
|
||||
* Inteface 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
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.common;
|
||||
|
||||
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;
|
||||
@@ -31,7 +30,9 @@ import java.security.GeneralSecurityException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.DSAPrivateKey;
|
||||
import java.security.interfaces.DSAPublicKey;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.DSAPublicKeySpec;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
@@ -52,7 +53,7 @@ public enum KeyType {
|
||||
} catch (Buffer.BufferException be) {
|
||||
throw new GeneralSecurityException(be);
|
||||
}
|
||||
final KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.RSA);
|
||||
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
|
||||
return keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
|
||||
}
|
||||
|
||||
@@ -65,7 +66,7 @@ public enum KeyType {
|
||||
|
||||
@Override
|
||||
protected boolean isMyType(Key key) {
|
||||
return KeyAlgorithm.RSA.equals(key.getAlgorithm());
|
||||
return (key instanceof RSAPublicKey || key instanceof RSAPrivateKey);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -83,7 +84,7 @@ public enum KeyType {
|
||||
} catch (Buffer.BufferException be) {
|
||||
throw new GeneralSecurityException(be);
|
||||
}
|
||||
final KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.DSA);
|
||||
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("DSA");
|
||||
return keyFactory.generatePublic(new DSAPublicKeySpec(y, p, q, g));
|
||||
}
|
||||
|
||||
@@ -98,7 +99,7 @@ public enum KeyType {
|
||||
|
||||
@Override
|
||||
protected boolean isMyType(Key key) {
|
||||
return KeyAlgorithm.DSA.equals(key.getAlgorithm());
|
||||
return (key instanceof DSAPublicKey || key instanceof DSAPrivateKey);
|
||||
}
|
||||
|
||||
},
|
||||
@@ -220,11 +221,6 @@ public enum KeyType {
|
||||
protected boolean isMyType(Key key) {
|
||||
return CertUtils.isCertificateOfType(key, RSA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyType getParent() {
|
||||
return RSA;
|
||||
}
|
||||
},
|
||||
|
||||
/** Signed dsa certificate */
|
||||
@@ -244,11 +240,6 @@ public enum KeyType {
|
||||
protected boolean isMyType(Key key) {
|
||||
return CertUtils.isCertificateOfType(key, DSA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyType getParent() {
|
||||
return KeyType.DSA;
|
||||
}
|
||||
},
|
||||
|
||||
/** Unrecognized */
|
||||
@@ -293,24 +284,10 @@ public enum KeyType {
|
||||
protected abstract boolean isMyType(Key key);
|
||||
|
||||
public static KeyType fromKey(Key key) {
|
||||
KeyType result = UNKNOWN;
|
||||
for (KeyType kt : values())
|
||||
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;
|
||||
if (kt.isMyType((key)))
|
||||
return kt;
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public static KeyType fromString(String sType) {
|
||||
@@ -396,18 +373,8 @@ public enum KeyType {
|
||||
}
|
||||
}
|
||||
|
||||
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 long epochFromDate(Date date) {
|
||||
return date.getTime() / 1000;
|
||||
}
|
||||
|
||||
private static String unpackString(byte[] packedString) throws BufferException {
|
||||
|
||||
@@ -25,7 +25,6 @@ public enum Message {
|
||||
DEBUG(4),
|
||||
SERVICE_REQUEST(5),
|
||||
SERVICE_ACCEPT(6),
|
||||
EXT_INFO(7),
|
||||
KEXINIT(20),
|
||||
NEWKEYS(21),
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.io.IOException;
|
||||
* Most exceptions in the {@code net.schmizz.sshj} package are instances of this class. An {@link SSHException} is
|
||||
* itself an {@link IOException} and can be caught like that if this level of granularity is not desired.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SSHException
|
||||
extends IOException {
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package net.schmizz.sshj.common;
|
||||
|
||||
/** Represents unrecoverable exceptions in the {@code net.schmizz.sshj} package. */
|
||||
@SuppressWarnings("serial")
|
||||
public class SSHRuntimeException
|
||||
extends RuntimeException {
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ import javax.crypto.NoSuchPaddingException;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Static utility method relating to security facilities.
|
||||
*/
|
||||
@@ -55,8 +53,8 @@ public class SecurityUtils {
|
||||
public static final String SPONGY_CASTLE = "SC";
|
||||
|
||||
/*
|
||||
* Security provider identifier. null = default JCE
|
||||
*/
|
||||
* Security provider identifier. null = default JCE
|
||||
*/
|
||||
private static String securityProvider = null;
|
||||
|
||||
// relate to BC registration (or SpongyCastle on Android)
|
||||
@@ -67,17 +65,13 @@ public class SecurityUtils {
|
||||
Provider provider = null;
|
||||
try {
|
||||
Class<?> name = Class.forName(providerClassName);
|
||||
provider = (Provider) name.getDeclaredConstructor().newInstance();
|
||||
provider = (Provider) name.newInstance();
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.info("Security Provider class '{}' not found", providerClassName);
|
||||
} catch (InstantiationException e) {
|
||||
LOG.info("Security Provider class '{}' could not be created", providerClassName);
|
||||
} catch (IllegalAccessException e) {
|
||||
LOG.info("Security Provider class '{}' could not be accessed", providerClassName);
|
||||
} catch (InvocationTargetException e) {
|
||||
LOG.info("Security Provider class '{}' could not be created", providerClassName);
|
||||
} catch (NoSuchMethodException e) {
|
||||
LOG.info("Security Provider class '{}' does not have a no-args constructor", providerClassName);
|
||||
}
|
||||
|
||||
if (provider == null) {
|
||||
@@ -249,14 +243,7 @@ public class SecurityUtils {
|
||||
*/
|
||||
public static synchronized boolean isBouncyCastleRegistered() {
|
||||
register();
|
||||
Provider[] providers = Security.getProviders();
|
||||
for (Provider provider : providers) {
|
||||
String name = provider.getName();
|
||||
if (BOUNCY_CASTLE.equals(name) || SPONGY_CASTLE.equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return BOUNCY_CASTLE.equals(securityProvider) || SPONGY_CASTLE.equals(securityProvider);
|
||||
}
|
||||
|
||||
public static synchronized void setRegisterBouncyCastle(boolean registerBouncyCastle) {
|
||||
|
||||
@@ -150,8 +150,7 @@ public final class ChannelOutputStream extends OutputStream implements ErrorNoti
|
||||
}
|
||||
|
||||
private void checkClose() throws SSHException {
|
||||
// Check whether either the Stream is closed, or the underlying channel is closed
|
||||
if (closed || !chan.isOpen()) {
|
||||
if (closed) {
|
||||
if (error != null)
|
||||
throw error;
|
||||
else
|
||||
@@ -161,8 +160,7 @@ public final class ChannelOutputStream extends OutputStream implements ErrorNoti
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
// Not closed yet, and underlying channel is open to flush the data to.
|
||||
if (!closed && chan.isOpen()) {
|
||||
if (!closed) {
|
||||
try {
|
||||
buffer.flush(false);
|
||||
// trans.write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(chan.getRecipient()));
|
||||
|
||||
@@ -28,7 +28,7 @@ import net.schmizz.sshj.transport.TransportException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** Base class for direct channels whose open is initiated by the client. */
|
||||
/** Base class for direct channels whose open is initated by the client. */
|
||||
public abstract class AbstractDirectChannel
|
||||
extends AbstractChannel
|
||||
implements Channel.Direct {
|
||||
|
||||
@@ -20,7 +20,7 @@ import net.schmizz.sshj.connection.Connection;
|
||||
/** A channel for creating a direct TCP/IP connection from the server to a remote address. */
|
||||
public class DirectConnection extends DirectTCPIPChannel {
|
||||
public static final String LOCALHOST = "localhost";
|
||||
public static final int LOCALPORT = 65535;
|
||||
public static final int LOCALPORT = 65536;
|
||||
|
||||
public DirectConnection(Connection conn, String remoteHost, int remotePort) {
|
||||
super(conn, new Parameters(LOCALHOST, LOCALPORT, remoteHost, remotePort));
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.connection.channel.direct;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Parameters {
|
||||
|
||||
private final String localHost;
|
||||
@@ -47,24 +45,4 @@ public class Parameters {
|
||||
return localPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(localHost, localPort, remoteHost, remotePort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) { return true; }
|
||||
if (!(obj instanceof Parameters)) { return false; }
|
||||
Parameters other = (Parameters) obj;
|
||||
return Objects.equals(localHost, other.localHost) && localPort == other.localPort &&
|
||||
Objects.equals(remoteHost, other.remoteHost) && remotePort == other.remotePort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Parameters [localHost=" + localHost + ", localPort=" + localPort + ", "+
|
||||
"remoteHost=" + remoteHost + ", remotePort=" + remotePort + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ public interface Session
|
||||
TransportException;
|
||||
|
||||
/**
|
||||
* Set an environment variable.
|
||||
* Set an enviornment variable.
|
||||
*
|
||||
* @param name name of the variable
|
||||
* @param value value to set
|
||||
|
||||
@@ -28,7 +28,7 @@ public interface ForwardedChannelOpener {
|
||||
/**
|
||||
* Delegates a {@code SSH_MSG_CHANNEL_OPEN} request for the channel type claimed by this opener.
|
||||
*
|
||||
* @param buf {@link SSHPacket} containing the request except for the message identifier and channel type field
|
||||
* @param buf {@link SSHPacket} containg the request except for the message identifier and channel type field
|
||||
*/
|
||||
void handleOpen(SSHPacket buf)
|
||||
throws ConnectionException, TransportException;
|
||||
|
||||
@@ -42,7 +42,6 @@ public class PacketReader extends Thread {
|
||||
log = engine.getLoggerFactory().getLogger(getClass());
|
||||
this.in = engine.getSubsystem().getInputStream();
|
||||
setName("sftp reader");
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
private void readIntoBuffer(byte[] buf, int off, int len)
|
||||
|
||||
@@ -108,14 +108,6 @@ public class SFTPEngine
|
||||
return operativeVersion;
|
||||
}
|
||||
|
||||
public boolean supportsServerExtension(final String extension, final String domain) {
|
||||
return serverExtensions.containsKey(extension + "@" + domain);
|
||||
}
|
||||
|
||||
public String getServerExtensionData(final String extension, final String domain) {
|
||||
return serverExtensions.get(extension + "@" + domain);
|
||||
}
|
||||
|
||||
public Request newExtendedRequest(String reqName) {
|
||||
return newRequest(PacketType.EXTENDED).putString(reqName);
|
||||
}
|
||||
|
||||
@@ -29,26 +29,18 @@ public abstract class AbstractSignature
|
||||
|
||||
@SuppressWarnings("PMD.UnnecessaryFullyQualifiedName")
|
||||
protected final java.security.Signature signature;
|
||||
private final String signatureName;
|
||||
|
||||
protected AbstractSignature(String algorithm, String signatureName) {
|
||||
protected AbstractSignature(String algorithm) {
|
||||
try {
|
||||
this.signature = SecurityUtils.getSignature(algorithm);
|
||||
this.signatureName = signatureName;
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new SSHRuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected AbstractSignature(@SuppressWarnings("PMD.UnnecessaryFullyQualifiedName")
|
||||
java.security.Signature signatureEngine, String signatureName) {
|
||||
java.security.Signature signatureEngine) {
|
||||
this.signature = signatureEngine;
|
||||
this.signatureName = signatureName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignatureName() {
|
||||
return signatureName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,8 +21,6 @@ import java.security.PublicKey;
|
||||
/** Signature interface for SSH used to sign or verify data. Usually wraps a {@code javax.crypto.Signature} object. */
|
||||
public interface Signature {
|
||||
|
||||
String getSignatureName();
|
||||
|
||||
/**
|
||||
* Initialize this signature with the given public key for signature verification.
|
||||
*
|
||||
|
||||
@@ -15,20 +15,15 @@
|
||||
*/
|
||||
package net.schmizz.sshj.signature;
|
||||
|
||||
import com.hierynomus.asn1.encodingrules.der.DEREncoder;
|
||||
import com.hierynomus.asn1.types.ASN1Object;
|
||||
import com.hierynomus.asn1.types.constructed.ASN1Sequence;
|
||||
import com.hierynomus.asn1.types.primitive.ASN1Integer;
|
||||
import net.schmizz.sshj.common.KeyType;
|
||||
import net.schmizz.sshj.common.SSHRuntimeException;
|
||||
import org.bouncycastle.asn1.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.SignatureException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DSA {@link Signature}
|
||||
@@ -55,7 +50,7 @@ public class SignatureDSA
|
||||
}
|
||||
|
||||
public SignatureDSA() {
|
||||
super("SHA1withDSA", KeyType.DSA.toString());
|
||||
super("SHA1withDSA");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,8 +72,8 @@ public class SignatureDSA
|
||||
|
||||
// result must be 40 bytes, but length of r and s may not be 20 bytes
|
||||
|
||||
int r_copylen = Math.min(r.length, 20);
|
||||
int s_copylen = Math.min(s.length, 20);
|
||||
int r_copylen = (r.length < 20) ? r.length : 20;
|
||||
int s_copylen = (s.length < 20) ? s.length : 20;
|
||||
|
||||
System.arraycopy(r, r.length - r_copylen, result, 20 - r_copylen, r_copylen);
|
||||
System.arraycopy(s, s.length - s_copylen, result, 40 - s_copylen, s_copylen);
|
||||
@@ -102,19 +97,18 @@ public class SignatureDSA
|
||||
* Encodes the signature as a DER sequence (ASN.1 format).
|
||||
*/
|
||||
private byte[] asnEncode(byte[] sigBlob) throws IOException {
|
||||
BigInteger r = new BigInteger(1, Arrays.copyOfRange(sigBlob, 0, 20));
|
||||
BigInteger s = new BigInteger(1, Arrays.copyOfRange(sigBlob, 20, 40));
|
||||
byte[] r = new BigInteger(1, Arrays.copyOfRange(sigBlob, 0, 20)).toByteArray();
|
||||
byte[] s = new BigInteger(1, Arrays.copyOfRange(sigBlob, 20, 40)).toByteArray();
|
||||
|
||||
List<ASN1Object> vector = new ArrayList<ASN1Object>();
|
||||
vector.add(new com.hierynomus.asn1.types.primitive.ASN1Integer(r));
|
||||
ASN1EncodableVector vector = new ASN1EncodableVector();
|
||||
vector.add(new ASN1Integer(r));
|
||||
vector.add(new ASN1Integer(s));
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
com.hierynomus.asn1.ASN1OutputStream asn1OutputStream = new com.hierynomus.asn1.ASN1OutputStream(new DEREncoder(), baos);
|
||||
|
||||
asn1OutputStream.writeObject(new ASN1Sequence(vector));
|
||||
asn1OutputStream.flush();
|
||||
ASN1OutputStream asnOS = new ASN1OutputStream(baos);
|
||||
|
||||
asnOS.writeObject(new DERSequence(vector));
|
||||
asnOS.flush();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
@@ -15,23 +15,18 @@
|
||||
*/
|
||||
package net.schmizz.sshj.signature;
|
||||
|
||||
import com.hierynomus.asn1.encodingrules.der.DERDecoder;
|
||||
import com.hierynomus.asn1.encodingrules.der.DEREncoder;
|
||||
import com.hierynomus.asn1.types.ASN1Object;
|
||||
import com.hierynomus.asn1.types.constructed.ASN1Sequence;
|
||||
import com.hierynomus.asn1.types.primitive.ASN1Integer;
|
||||
import net.schmizz.sshj.common.Buffer;
|
||||
import net.schmizz.sshj.common.IOUtils;
|
||||
import net.schmizz.sshj.common.KeyType;
|
||||
import net.schmizz.sshj.common.SSHRuntimeException;
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.ASN1OutputStream;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.SignatureException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** ECDSA {@link Signature} */
|
||||
public class SignatureECDSA extends AbstractSignature {
|
||||
@@ -84,26 +79,30 @@ public class SignatureECDSA extends AbstractSignature {
|
||||
private String keyTypeName;
|
||||
|
||||
public SignatureECDSA(String algorithm, String keyTypeName) {
|
||||
super(algorithm, keyTypeName);
|
||||
super(algorithm);
|
||||
this.keyTypeName = keyTypeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encode(byte[] sig) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(sig);
|
||||
com.hierynomus.asn1.ASN1InputStream asn1InputStream = new com.hierynomus.asn1.ASN1InputStream(new DERDecoder(), bais);
|
||||
try {
|
||||
ASN1Sequence sequence = asn1InputStream.readObject();
|
||||
ASN1Integer r = (ASN1Integer) sequence.get(0);
|
||||
ASN1Integer s = (ASN1Integer) sequence.get(1);
|
||||
Buffer.PlainBuffer buf = new Buffer.PlainBuffer();
|
||||
buf.putMPInt(r.getValue());
|
||||
buf.putMPInt(s.getValue());
|
||||
int rIndex = 3;
|
||||
int rLen = sig[rIndex++] & 0xff;
|
||||
byte[] r = new byte[rLen];
|
||||
System.arraycopy(sig, rIndex, r, 0, r.length);
|
||||
|
||||
return buf.getCompactData();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(asn1InputStream, bais);
|
||||
}
|
||||
int sIndex = rIndex + rLen + 1;
|
||||
int sLen = sig[sIndex++] & 0xff;
|
||||
byte[] s = new byte[sLen];
|
||||
System.arraycopy(sig, sIndex, s, 0, s.length);
|
||||
|
||||
System.arraycopy(sig, 4, r, 0, rLen);
|
||||
System.arraycopy(sig, 6 + rLen, s, 0, sLen);
|
||||
|
||||
Buffer.PlainBuffer buf = new Buffer.PlainBuffer();
|
||||
buf.putMPInt(new BigInteger(r));
|
||||
buf.putMPInt(new BigInteger(s));
|
||||
|
||||
return buf.getCompactData();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,22 +122,19 @@ public class SignatureECDSA extends AbstractSignature {
|
||||
*/
|
||||
private byte[] asnEncode(byte[] sigBlob) throws IOException {
|
||||
Buffer.PlainBuffer sigbuf = new Buffer.PlainBuffer(sigBlob);
|
||||
BigInteger r = sigbuf.readMPInt();
|
||||
BigInteger s = sigbuf.readMPInt();
|
||||
byte[] r = sigbuf.readBytes();
|
||||
byte[] s = sigbuf.readBytes();
|
||||
|
||||
|
||||
List<ASN1Object> vector = new ArrayList<ASN1Object>();
|
||||
ASN1EncodableVector vector = new ASN1EncodableVector();
|
||||
vector.add(new ASN1Integer(r));
|
||||
vector.add(new ASN1Integer(s));
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
com.hierynomus.asn1.ASN1OutputStream asn1OutputStream = new com.hierynomus.asn1.ASN1OutputStream(new DEREncoder(), baos);
|
||||
try {
|
||||
asn1OutputStream.writeObject(new ASN1Sequence(vector));
|
||||
asn1OutputStream.flush();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(asn1OutputStream);
|
||||
}
|
||||
ASN1OutputStream asnOS = new ASN1OutputStream(baos);
|
||||
|
||||
asnOS.writeObject(new DERSequence(vector));
|
||||
asnOS.flush();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,53 +22,26 @@ import net.schmizz.sshj.common.SSHRuntimeException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SignatureException;
|
||||
import java.util.Date;
|
||||
|
||||
/** RSA {@link Signature} */
|
||||
public class SignatureRSA
|
||||
extends AbstractSignature {
|
||||
|
||||
/** A named factory for RSA {@link Signature} */
|
||||
public static class FactorySSHRSA
|
||||
public static class Factory
|
||||
implements net.schmizz.sshj.common.Factory.Named<Signature> {
|
||||
|
||||
@Override
|
||||
public Signature create() {
|
||||
return new SignatureRSA("SHA1withRSA", KeyType.RSA, KeyType.RSA.toString());
|
||||
return new SignatureRSA(KeyType.RSA.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return KeyType.RSA.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/** A named factory for RSA {@link Signature} */
|
||||
public static class FactoryRSASHA256
|
||||
implements net.schmizz.sshj.common.Factory.Named<Signature> {
|
||||
|
||||
@Override
|
||||
public Signature create() {
|
||||
return new SignatureRSA("SHA256withRSA", KeyType.RSA, "rsa-sha2-256");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "rsa-sha2-256";
|
||||
}
|
||||
}
|
||||
/** A named factory for RSA {@link Signature} */
|
||||
public static class FactoryRSASHA512
|
||||
implements net.schmizz.sshj.common.Factory.Named<Signature> {
|
||||
|
||||
@Override
|
||||
public Signature create() {
|
||||
return new SignatureRSA("SHA512withRSA", KeyType.RSA, "rsa-sha2-512");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "rsa-sha2-512";
|
||||
}
|
||||
}
|
||||
|
||||
/** A named factory for RSA {@link Signature} */
|
||||
@@ -77,7 +50,7 @@ public class SignatureRSA
|
||||
|
||||
@Override
|
||||
public Signature create() {
|
||||
return new SignatureRSA("SHA1withRSA", KeyType.RSA_CERT, KeyType.RSA.toString());
|
||||
return new SignatureRSA(KeyType.RSA_CERT.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,19 +60,19 @@ public class SignatureRSA
|
||||
|
||||
}
|
||||
|
||||
private KeyType keyType;
|
||||
private String keyTypeName;
|
||||
|
||||
|
||||
public SignatureRSA(String algorithm, KeyType keyType, String name) {
|
||||
super(algorithm, name);
|
||||
this.keyType = keyType;
|
||||
public SignatureRSA(String keyTypeName) {
|
||||
super("SHA1withRSA");
|
||||
this.keyTypeName = keyTypeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void initVerify(PublicKey publicKey) {
|
||||
try {
|
||||
if (this.keyType.equals(KeyType.RSA_CERT) && publicKey instanceof Certificate) {
|
||||
if (this.keyTypeName.equals(KeyType.RSA_CERT.toString()) && publicKey instanceof Certificate) {
|
||||
signature.initVerify(((Certificate<PublicKey>) publicKey).getKey());
|
||||
} else {
|
||||
signature.initVerify(publicKey);
|
||||
@@ -116,7 +89,7 @@ public class SignatureRSA
|
||||
|
||||
@Override
|
||||
public boolean verify(byte[] sig) {
|
||||
sig = extractSig(sig, getSignatureName());
|
||||
sig = extractSig(sig, KeyType.RSA.toString());
|
||||
try {
|
||||
return signature.verify(sig);
|
||||
} catch (SignatureException e) {
|
||||
|
||||
@@ -45,7 +45,6 @@ abstract class Converter {
|
||||
protected long seq = -1;
|
||||
protected boolean authed;
|
||||
protected boolean etm;
|
||||
protected boolean authMode;
|
||||
|
||||
long getSequenceNumber() {
|
||||
return seq;
|
||||
@@ -58,11 +57,7 @@ abstract class Converter {
|
||||
if (compression != null)
|
||||
compression.init(getCompressionType());
|
||||
this.cipherSize = cipher.getIVSize();
|
||||
this.etm = this.mac != null && mac.isEtm();
|
||||
if(cipher.getAuthenticationTagSize() > 0) {
|
||||
this.cipherSize = cipher.getAuthenticationTagSize();
|
||||
this.authMode = true;
|
||||
}
|
||||
this.etm = mac.isEtm();
|
||||
}
|
||||
|
||||
void setAuthenticated() {
|
||||
|
||||
@@ -70,41 +70,40 @@ final class Decoder
|
||||
*
|
||||
* @return number of bytes needed before further decoding possible
|
||||
*/
|
||||
private int decode() throws SSHException {
|
||||
int need;
|
||||
for(;;) {
|
||||
if (packetLength == -1) { // Waiting for beginning of packet
|
||||
private int decode()
|
||||
throws SSHException {
|
||||
|
||||
if (etm) {
|
||||
return decodeEtm();
|
||||
} else {
|
||||
return decodeMte();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode an Encrypt-Then-Mac packet.
|
||||
*/
|
||||
private int decodeEtm() throws SSHException {
|
||||
int bytesNeeded;
|
||||
while (true) {
|
||||
if (packetLength == -1) {
|
||||
assert inputBuffer.rpos() == 0 : "buffer cleared";
|
||||
need = cipherSize - inputBuffer.available();
|
||||
if (need <= 0) {
|
||||
if (authMode) {
|
||||
packetLength = decryptLengthAAD();
|
||||
} else if (etm) {
|
||||
packetLength = inputBuffer.readUInt32AsInt();
|
||||
checkPacketLength(packetLength);
|
||||
} else {
|
||||
packetLength = decryptLength();
|
||||
}
|
||||
bytesNeeded = 4 - inputBuffer.available();
|
||||
if (bytesNeeded <= 0) {
|
||||
// In Encrypt-Then-Mac, the packetlength is sent unencrypted.
|
||||
packetLength = inputBuffer.readUInt32AsInt();
|
||||
checkPacketLength(packetLength);
|
||||
} else {
|
||||
// Need more data
|
||||
// Needs more data
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
assert inputBuffer.rpos() == 4 : "packet length read";
|
||||
need = (authMode) ? packetLength + cipherSize - inputBuffer.available() : packetLength + (mac != null ? mac.getBlockSize() : 0) - inputBuffer.available();
|
||||
if (need <= 0) {
|
||||
bytesNeeded = packetLength + mac.getBlockSize() - inputBuffer.available();
|
||||
if (bytesNeeded <= 0) {
|
||||
seq = seq + 1 & 0xffffffffL;
|
||||
if (authMode) {
|
||||
cipher.update(inputBuffer.array(), 4, packetLength);
|
||||
} else if (etm) {
|
||||
checkMAC(inputBuffer.array());
|
||||
decryptBuffer(4, packetLength);
|
||||
} else {
|
||||
decryptBuffer(cipherSize, packetLength + 4 - cipherSize); // Decrypt the rest of the payload
|
||||
if (mac != null) {
|
||||
checkMAC(inputBuffer.array());
|
||||
}
|
||||
}
|
||||
checkMAC(inputBuffer.array());
|
||||
decryptBuffer(4, packetLength);
|
||||
inputBuffer.wpos(packetLength + 4 - inputBuffer.readByte());
|
||||
final SSHPacket plain = usingCompression() ? decompressed() : inputBuffer;
|
||||
if (log.isTraceEnabled()) {
|
||||
@@ -119,15 +118,58 @@ final class Decoder
|
||||
}
|
||||
}
|
||||
}
|
||||
return bytesNeeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a Mac-Then-Encrypt packet
|
||||
* @return
|
||||
* @throws SSHException
|
||||
*/
|
||||
private int decodeMte() throws SSHException {
|
||||
int need;
|
||||
|
||||
/* Decoding loop */
|
||||
for (; ; )
|
||||
|
||||
if (packetLength == -1) { // Waiting for beginning of packet
|
||||
assert inputBuffer.rpos() == 0 : "buffer cleared";
|
||||
need = cipherSize - inputBuffer.available();
|
||||
if (need <= 0) {
|
||||
packetLength = decryptLength();
|
||||
} else {
|
||||
// Need more data
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
assert inputBuffer.rpos() == 4 : "packet length read";
|
||||
need = packetLength + (mac != null ? mac.getBlockSize() : 0) - inputBuffer.available();
|
||||
if (need <= 0) {
|
||||
decryptBuffer(cipherSize, packetLength + 4 - cipherSize); // Decrypt the rest of the payload
|
||||
seq = seq + 1 & 0xffffffffL;
|
||||
if (mac != null) {
|
||||
checkMAC(inputBuffer.array());
|
||||
}
|
||||
// Exclude the padding & MAC
|
||||
inputBuffer.wpos(packetLength + 4 - inputBuffer.readByte());
|
||||
final SSHPacket plain = usingCompression() ? decompressed() : inputBuffer;
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Received packet #{}: {}", seq, plain.printHex());
|
||||
}
|
||||
packetHandler.handle(plain.readMessageID(), plain); // Process the decoded packet
|
||||
inputBuffer.clear();
|
||||
packetLength = -1;
|
||||
} else {
|
||||
// Need more data
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return need;
|
||||
}
|
||||
|
||||
private void checkMAC(final byte[] data)
|
||||
throws TransportException {
|
||||
if (mac == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mac.update(seq); // seq num
|
||||
mac.update(data, 0, packetLength + 4); // packetLength+4 = entire packet w/o mac
|
||||
mac.doFinal(macResult, 0); // compute
|
||||
@@ -144,20 +186,6 @@ final class Decoder
|
||||
return uncompressBuffer;
|
||||
}
|
||||
|
||||
private int decryptLengthAAD() throws TransportException {
|
||||
cipher.updateAAD(inputBuffer.array(), 0, 4);
|
||||
|
||||
final int len;
|
||||
try {
|
||||
len = inputBuffer.readUInt32AsInt();
|
||||
} catch (Buffer.BufferException be) {
|
||||
throw new TransportException(be);
|
||||
}
|
||||
checkPacketLength(len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
private int decryptLength()
|
||||
throws TransportException {
|
||||
decryptBuffer(0, cipherSize);
|
||||
@@ -209,9 +237,7 @@ final class Decoder
|
||||
@Override
|
||||
void setAlgorithms(Cipher cipher, MAC mac, Compression compression) {
|
||||
super.setAlgorithms(cipher, mac, compression);
|
||||
if (mac != null) {
|
||||
macResult = new byte[mac.getBlockSize()];
|
||||
}
|
||||
macResult = new byte[mac.getBlockSize()];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.transport;
|
||||
|
||||
import net.schmizz.sshj.common.Buffer;
|
||||
import net.schmizz.sshj.common.LoggerFactory;
|
||||
import net.schmizz.sshj.common.SSHPacket;
|
||||
import net.schmizz.sshj.transport.cipher.Cipher;
|
||||
@@ -84,7 +83,7 @@ final class Encoder
|
||||
|
||||
// Compute padding length
|
||||
int padLen = cipherSize - (lengthWithoutPadding % cipherSize);
|
||||
if (padLen < 4 || (authMode && padLen < cipherSize)) {
|
||||
if (padLen < 4) {
|
||||
padLen += cipherSize;
|
||||
}
|
||||
|
||||
@@ -95,14 +94,6 @@ final class Encoder
|
||||
padLen += cipherSize;
|
||||
packetLen = 1 + payloadSize + padLen;
|
||||
}
|
||||
/*
|
||||
* In AES-GCM ciphers, they require packets must be a multiple of 16 bytes (which is also block size of AES)
|
||||
* as mentioned in RFC5647 Section 7.2. So we are calculating the extra padding as necessary here
|
||||
*/
|
||||
if (authMode && packetLen % cipherSize != 0) {
|
||||
padLen += cipherSize - (packetLen % cipherSize);
|
||||
packetLen = 1 + payloadSize + padLen;
|
||||
}
|
||||
|
||||
final int endOfPadding = startOfPacket + 4 + packetLen;
|
||||
|
||||
@@ -110,7 +101,6 @@ final class Encoder
|
||||
buffer.wpos(startOfPacket);
|
||||
buffer.putUInt32(packetLen);
|
||||
buffer.putByte((byte) padLen);
|
||||
|
||||
// Now wpos will mark end of padding
|
||||
buffer.wpos(endOfPadding);
|
||||
|
||||
@@ -119,17 +109,14 @@ final class Encoder
|
||||
|
||||
seq = seq + 1 & 0xffffffffL;
|
||||
|
||||
if (authMode) {
|
||||
int wpos = buffer.wpos();
|
||||
buffer.wpos(wpos + cipherSize);
|
||||
aeadOutgoingBuffer(buffer, startOfPacket, packetLen);
|
||||
} else if (etm) {
|
||||
if (etm) {
|
||||
cipher.update(buffer.array(), startOfPacket + 4, packetLen);
|
||||
putMAC(buffer, startOfPacket, endOfPadding);
|
||||
} else {
|
||||
if (mac != null) {
|
||||
putMAC(buffer, startOfPacket, endOfPadding);
|
||||
}
|
||||
|
||||
cipher.update(buffer.array(), startOfPacket, 4 + packetLen);
|
||||
}
|
||||
buffer.rpos(startOfPacket); // Make ready-to-read
|
||||
@@ -140,14 +127,6 @@ final class Encoder
|
||||
}
|
||||
}
|
||||
|
||||
protected void aeadOutgoingBuffer(Buffer buf, int offset, int len) {
|
||||
if (cipher == null || cipher.getAuthenticationTagSize() == 0) {
|
||||
throw new IllegalArgumentException("AEAD mode requires an AEAD cipher");
|
||||
}
|
||||
byte[] data = buf.array();
|
||||
cipher.updateWithAAD(data, offset, 4, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
void setAlgorithms(Cipher cipher, MAC mac, Compression compression) {
|
||||
encodeLock.lock();
|
||||
|
||||
@@ -30,7 +30,9 @@ import org.slf4j.Logger;
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@@ -92,7 +94,7 @@ final class KeyExchanger
|
||||
* Add a callback for host key verification.
|
||||
* <p/>
|
||||
* Any of the {@link HostKeyVerifier} implementations added this way can deem a host key to be acceptable, allowing
|
||||
* key exchange to successfully complete. Otherwise, a {@link TransportException} will result during key exchange.
|
||||
* key exchange to successfuly complete. Otherwise, a {@link TransportException} will result during key exchange.
|
||||
*
|
||||
* @param hkv object whose {@link HostKeyVerifier#verify} method will be invoked
|
||||
*/
|
||||
@@ -230,10 +232,6 @@ final class KeyExchanger
|
||||
}
|
||||
kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(),
|
||||
negotiatedAlgs.getKeyExchangeAlgorithm());
|
||||
transport.setHostKeyAlgorithm(Factory.Named.Util.create(transport.getConfig().getKeyAlgorithms(),
|
||||
negotiatedAlgs.getSignatureAlgorithm()));
|
||||
transport.setRSASHA2Support(negotiatedAlgs.getRSASHA2Support());
|
||||
|
||||
try {
|
||||
kex.init(transport,
|
||||
transport.getServerID(), transport.getClientID(),
|
||||
@@ -322,25 +320,13 @@ final class KeyExchanger
|
||||
resizedKey(encryptionKey_S2C, cipher_S2C.getBlockSize(), hash, kex.getK(), kex.getH()),
|
||||
initialIV_S2C);
|
||||
|
||||
/*
|
||||
* For AES-GCM ciphers, MAC will also be AES-GCM, so it is handled by the cipher itself.
|
||||
* In that case, both s2c and c2s MACs are ignored.
|
||||
*
|
||||
* Refer to RFC5647 Section 5.1
|
||||
*/
|
||||
MAC mac_C2S = null;
|
||||
if(cipher_C2S.getAuthenticationTagSize() == 0) {
|
||||
mac_C2S = Factory.Named.Util.create(transport.getConfig().getMACFactories(), negotiatedAlgs
|
||||
.getClient2ServerMACAlgorithm());
|
||||
mac_C2S.init(resizedKey(integrityKey_C2S, mac_C2S.getBlockSize(), hash, kex.getK(), kex.getH()));
|
||||
}
|
||||
final MAC mac_C2S = Factory.Named.Util.create(transport.getConfig().getMACFactories(), negotiatedAlgs
|
||||
.getClient2ServerMACAlgorithm());
|
||||
mac_C2S.init(resizedKey(integrityKey_C2S, mac_C2S.getBlockSize(), hash, kex.getK(), kex.getH()));
|
||||
|
||||
MAC mac_S2C = null;
|
||||
if(cipher_S2C.getAuthenticationTagSize() == 0) {
|
||||
mac_S2C = Factory.Named.Util.create(transport.getConfig().getMACFactories(),
|
||||
negotiatedAlgs.getServer2ClientMACAlgorithm());
|
||||
mac_S2C.init(resizedKey(integrityKey_S2C, mac_S2C.getBlockSize(), hash, kex.getK(), kex.getH()));
|
||||
}
|
||||
final MAC mac_S2C = Factory.Named.Util.create(transport.getConfig().getMACFactories(),
|
||||
negotiatedAlgs.getServer2ClientMACAlgorithm());
|
||||
mac_S2C.init(resizedKey(integrityKey_S2C, mac_S2C.getBlockSize(), hash, kex.getK(), kex.getH()));
|
||||
|
||||
final Compression compression_S2C =
|
||||
Factory.Named.Util.create(transport.getConfig().getCompressionFactories(),
|
||||
|
||||
@@ -26,10 +26,8 @@ public final class NegotiatedAlgorithms {
|
||||
private final String c2sComp;
|
||||
private final String s2cComp;
|
||||
|
||||
private final boolean rsaSHA2Support;
|
||||
|
||||
NegotiatedAlgorithms(String kex, String sig, String c2sCipher, String s2cCipher, String c2sMAC, String s2cMAC,
|
||||
String c2sComp, String s2cComp, boolean rsaSHA2Support) {
|
||||
String c2sComp, String s2cComp) {
|
||||
this.kex = kex;
|
||||
this.sig = sig;
|
||||
this.c2sCipher = c2sCipher;
|
||||
@@ -38,7 +36,6 @@ public final class NegotiatedAlgorithms {
|
||||
this.s2cMAC = s2cMAC;
|
||||
this.c2sComp = c2sComp;
|
||||
this.s2cComp = s2cComp;
|
||||
this.rsaSHA2Support = rsaSHA2Support;
|
||||
}
|
||||
|
||||
public String getKeyExchangeAlgorithm() {
|
||||
@@ -73,10 +70,6 @@ public final class NegotiatedAlgorithms {
|
||||
return s2cComp;
|
||||
}
|
||||
|
||||
public boolean getRSASHA2Support() {
|
||||
return rsaSHA2Support;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ("[ " +
|
||||
@@ -87,8 +80,7 @@ public final class NegotiatedAlgorithms {
|
||||
"c2sMAC=" + c2sMAC + "; " +
|
||||
"s2cMAC=" + s2cMAC + "; " +
|
||||
"c2sComp=" + c2sComp + "; " +
|
||||
"s2cComp=" + s2cComp + "; " +
|
||||
"rsaSHA2Support=" + rsaSHA2Support +
|
||||
"s2cComp=" + s2cComp +
|
||||
" ]");
|
||||
}
|
||||
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
*/
|
||||
package net.schmizz.sshj.transport;
|
||||
|
||||
import com.hierynomus.sshj.key.KeyAlgorithms;
|
||||
import net.schmizz.sshj.Config;
|
||||
import net.schmizz.sshj.common.Buffer;
|
||||
import net.schmizz.sshj.common.Factory;
|
||||
import net.schmizz.sshj.common.Message;
|
||||
import net.schmizz.sshj.common.SSHPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -40,7 +38,7 @@ class Proposal {
|
||||
|
||||
public Proposal(Config config) {
|
||||
kex = Factory.Named.Util.getNames(config.getKeyExchangeFactories());
|
||||
sig = Factory.Named.Util.getNames(config.getKeyAlgorithms());
|
||||
sig = Factory.Named.Util.getNames(config.getSignatureFactories());
|
||||
c2sCipher = s2cCipher = Factory.Named.Util.getNames(config.getCipherFactories());
|
||||
c2sMAC = s2cMAC = Factory.Named.Util.getNames(config.getMACFactories());
|
||||
c2sComp = s2cComp = Factory.Named.Util.getNames(config.getCompressionFactories());
|
||||
@@ -92,7 +90,7 @@ class Proposal {
|
||||
return kex;
|
||||
}
|
||||
|
||||
public List<String> getHostKeyAlgorithms() {
|
||||
public List<String> getSignatureAlgorithms() {
|
||||
return sig;
|
||||
}
|
||||
|
||||
@@ -128,49 +126,31 @@ class Proposal {
|
||||
throws TransportException {
|
||||
return new NegotiatedAlgorithms(
|
||||
firstMatch(this.getKeyExchangeAlgorithms(), other.getKeyExchangeAlgorithms()),
|
||||
firstMatch(this.getHostKeyAlgorithms(), other.getHostKeyAlgorithms()),
|
||||
firstMatch(this.getSignatureAlgorithms(), other.getSignatureAlgorithms()),
|
||||
firstMatch(this.getClient2ServerCipherAlgorithms(), other.getClient2ServerCipherAlgorithms()),
|
||||
firstMatch(this.getServer2ClientCipherAlgorithms(), other.getServer2ClientCipherAlgorithms()),
|
||||
firstMatch(this.getClient2ServerMACAlgorithms(), other.getClient2ServerMACAlgorithms()),
|
||||
firstMatch(this.getServer2ClientMACAlgorithms(), other.getServer2ClientMACAlgorithms()),
|
||||
firstMatch(this.getClient2ServerCompressionAlgorithms(), other.getClient2ServerCompressionAlgorithms()),
|
||||
firstMatch(this.getServer2ClientCompressionAlgorithms(), other.getServer2ClientCompressionAlgorithms()),
|
||||
other.getHostKeyAlgorithms().containsAll(KeyAlgorithms.SSH_RSA_SHA2_ALGORITHMS)
|
||||
firstMatch(this.getServer2ClientCompressionAlgorithms(), other.getServer2ClientCompressionAlgorithms())
|
||||
);
|
||||
}
|
||||
|
||||
private static String firstMatch(List<String> a, List<String> b)
|
||||
throws TransportException {
|
||||
for (String aa : a) {
|
||||
if (b.contains(aa)) {
|
||||
return aa;
|
||||
}
|
||||
}
|
||||
for (String aa : a)
|
||||
for (String bb : b)
|
||||
if (aa.equals(bb))
|
||||
return aa;
|
||||
throw new TransportException("Unable to reach a settlement: " + a + " and " + b);
|
||||
}
|
||||
|
||||
private static List<String> allMatch(List<String> a, List<String> b) throws TransportException {
|
||||
List<String> res = new ArrayList<String>();
|
||||
for (String aa : a) {
|
||||
if (b.contains(aa)) {
|
||||
res.add(aa);
|
||||
}
|
||||
}
|
||||
|
||||
if (res.isEmpty()) {
|
||||
throw new TransportException("Unable to reach a settlement: " + a + " and " + b);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static String toCommaString(List<String> sl) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i = 0;
|
||||
for (String s : sl) {
|
||||
if (i++ != 0) {
|
||||
if (i++ != 0)
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(s);
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
@@ -30,7 +30,6 @@ public final class Reader
|
||||
this.trans = trans;
|
||||
log = trans.getConfig().getLoggerFactory().getLogger(getClass());
|
||||
setName("reader");
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,11 +15,9 @@
|
||||
*/
|
||||
package net.schmizz.sshj.transport;
|
||||
|
||||
import com.hierynomus.sshj.key.KeyAlgorithm;
|
||||
import net.schmizz.sshj.Config;
|
||||
import net.schmizz.sshj.Service;
|
||||
import net.schmizz.sshj.common.DisconnectReason;
|
||||
import net.schmizz.sshj.common.KeyType;
|
||||
import net.schmizz.sshj.common.SSHPacket;
|
||||
import net.schmizz.sshj.common.SSHPacketHandler;
|
||||
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
|
||||
@@ -94,7 +92,7 @@ public interface Transport
|
||||
int getHeartbeatInterval();
|
||||
|
||||
/**
|
||||
* @param interval the interval in seconds, {@code 0} means no heartbeat
|
||||
* @param interval the interval in seconds, {@code 0} means no hearbeat
|
||||
* @deprecated Moved to {@link net.schmizz.keepalive.KeepAlive#getKeepAliveInterval()}. This is accessible through the {@link net.schmizz.sshj.connection.Connection}.
|
||||
* Scheduled to be removed in 0.12.0
|
||||
*/
|
||||
@@ -158,7 +156,7 @@ public interface Transport
|
||||
*
|
||||
* @return the sequence number of the packet sent
|
||||
*
|
||||
* @throws TransportException if an error occurred sending the packet
|
||||
* @throws TransportException if an error occured sending the packet
|
||||
*/
|
||||
long sendUnimplemented()
|
||||
throws TransportException;
|
||||
@@ -237,7 +235,4 @@ public interface Transport
|
||||
* @param e The exception that occurred.
|
||||
*/
|
||||
void die(Exception e);
|
||||
|
||||
KeyAlgorithm getHostKeyAlgorithm();
|
||||
KeyAlgorithm getClientKeyAlgorithm(KeyType keyType) throws TransportException;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.transport;
|
||||
|
||||
import com.hierynomus.sshj.key.KeyAlgorithm;
|
||||
import com.hierynomus.sshj.key.KeyAlgorithms;
|
||||
import com.hierynomus.sshj.transport.IdentificationStringParser;
|
||||
import net.schmizz.concurrent.ErrorDeliveryUtil;
|
||||
import net.schmizz.concurrent.Event;
|
||||
@@ -32,7 +30,6 @@ import org.slf4j.Logger;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@@ -42,7 +39,6 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
public final class TransportImpl
|
||||
implements Transport, DisconnectListener {
|
||||
|
||||
|
||||
private static final class NullService
|
||||
extends AbstractService {
|
||||
|
||||
@@ -90,10 +86,6 @@ public final class TransportImpl
|
||||
|
||||
private final Decoder decoder;
|
||||
|
||||
private KeyAlgorithm hostKeyAlgorithm;
|
||||
|
||||
private boolean rsaSHA2Support;
|
||||
|
||||
private final Event<TransportException> serviceAccept;
|
||||
|
||||
private final Event<TransportException> close;
|
||||
@@ -112,11 +104,6 @@ public final class TransportImpl
|
||||
*/
|
||||
private volatile Service service;
|
||||
|
||||
/**
|
||||
* The next service that will be activated, only set when sending an SSH_MSG_SERVICE_REQUEST
|
||||
*/
|
||||
private volatile Service nextService;
|
||||
|
||||
private DisconnectListener disconnectListener;
|
||||
|
||||
private ConnInfo connInfo;
|
||||
@@ -337,9 +324,8 @@ public final class TransportImpl
|
||||
|
||||
@Override
|
||||
public synchronized void setService(Service service) {
|
||||
if (service == null) {
|
||||
if (service == null)
|
||||
service = nullService;
|
||||
}
|
||||
|
||||
log.debug("Setting active service to {}", service.getName());
|
||||
this.service = service;
|
||||
@@ -351,12 +337,11 @@ public final class TransportImpl
|
||||
serviceAccept.lock();
|
||||
try {
|
||||
serviceAccept.clear();
|
||||
this.nextService = service;
|
||||
sendServiceRequest(service.getName());
|
||||
serviceAccept.await(timeoutMs, TimeUnit.MILLISECONDS);
|
||||
setService(service);
|
||||
} finally {
|
||||
serviceAccept.unlock();
|
||||
this.nextService = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,8 +485,8 @@ public final class TransportImpl
|
||||
* This method is called in the context of the {@link #reader} thread via {@link Decoder#received} when a full
|
||||
* packet has been decoded.
|
||||
*
|
||||
* @param msg the message identifier
|
||||
* @param buf buffer containing rest of the packet
|
||||
* @param msg the message identifer
|
||||
* @param buf buffer containg rest of the packet
|
||||
* @throws SSHException if an error occurs during handling (unrecoverable)
|
||||
*/
|
||||
@Override
|
||||
@@ -511,11 +496,13 @@ public final class TransportImpl
|
||||
|
||||
log.trace("Received packet {}", msg);
|
||||
|
||||
if (msg.geq(50)) { // not a transport layer packet
|
||||
if (msg.geq(50)) // not a transport layer packet
|
||||
service.handle(msg, buf);
|
||||
} else if (msg.in(20, 21) || msg.in(30, 49)) { // kex packet
|
||||
|
||||
else if (msg.in(20, 21) || msg.in(30, 49)) // kex packet
|
||||
kexer.handle(msg, buf);
|
||||
} else {
|
||||
|
||||
else
|
||||
switch (msg) {
|
||||
case DISCONNECT:
|
||||
gotDisconnect(buf);
|
||||
@@ -532,9 +519,6 @@ public final class TransportImpl
|
||||
case SERVICE_ACCEPT:
|
||||
gotServiceAccept();
|
||||
break;
|
||||
case EXT_INFO:
|
||||
log.debug("Received SSH_MSG_EXT_INFO");
|
||||
break;
|
||||
case USERAUTH_BANNER:
|
||||
log.debug("Received USERAUTH_BANNER");
|
||||
break;
|
||||
@@ -542,7 +526,6 @@ public final class TransportImpl
|
||||
sendUnimplemented();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void gotDebug(SSHPacket buf)
|
||||
@@ -575,8 +558,6 @@ public final class TransportImpl
|
||||
if (!serviceAccept.hasWaiters())
|
||||
throw new TransportException(DisconnectReason.PROTOCOL_ERROR,
|
||||
"Got a service accept notification when none was awaited");
|
||||
// Immediately switch to next service to prevent race condition mentioned in #559
|
||||
setService(nextService);
|
||||
serviceAccept.set();
|
||||
} finally {
|
||||
serviceAccept.unlock();
|
||||
@@ -660,30 +641,4 @@ public final class TransportImpl
|
||||
return connInfo;
|
||||
}
|
||||
|
||||
public void setHostKeyAlgorithm(KeyAlgorithm keyAlgorithm) {
|
||||
this.hostKeyAlgorithm = keyAlgorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyAlgorithm getHostKeyAlgorithm() {
|
||||
return this.hostKeyAlgorithm;
|
||||
}
|
||||
|
||||
public void setRSASHA2Support(boolean rsaSHA2Support) {
|
||||
this.rsaSHA2Support = rsaSHA2Support;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyAlgorithm getClientKeyAlgorithm(KeyType keyType) throws TransportException {
|
||||
if (keyType != KeyType.RSA || !rsaSHA2Support) {
|
||||
return Factory.Named.Util.create(getConfig().getKeyAlgorithms(), keyType.toString());
|
||||
}
|
||||
|
||||
List<Factory.Named<KeyAlgorithm>> factories = getConfig().getKeyAlgorithms();
|
||||
if (factories != null)
|
||||
for (Factory.Named<KeyAlgorithm> f : factories)
|
||||
if (f.getName().equals("ssh-rsa") || KeyAlgorithms.SSH_RSA_SHA2_ALGORITHMS.contains(f.getName()))
|
||||
return f.create();
|
||||
throw new TransportException("Cannot find an available KeyAlgorithm for type " + keyType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public abstract class BaseCipher
|
||||
private final String algorithm;
|
||||
private final String transformation;
|
||||
|
||||
protected javax.crypto.Cipher cipher;
|
||||
private javax.crypto.Cipher cipher;
|
||||
|
||||
public BaseCipher(int ivsize, int bsize, String algorithm, String transformation) {
|
||||
this.ivsize = ivsize;
|
||||
@@ -61,11 +61,6 @@ public abstract class BaseCipher
|
||||
return ivsize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAuthenticationTagSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Mode mode, byte[] key, byte[] iv) {
|
||||
key = BaseCipher.resize(key, bsize);
|
||||
@@ -80,7 +75,6 @@ public abstract class BaseCipher
|
||||
}
|
||||
|
||||
protected abstract void initCipher(javax.crypto.Cipher cipher, Mode mode, byte[] key, byte[] iv) throws InvalidKeyException, InvalidAlgorithmParameterException;
|
||||
|
||||
protected SecretKeySpec getKeySpec(byte[] key) {
|
||||
return new SecretKeySpec(key, algorithm);
|
||||
}
|
||||
@@ -98,19 +92,4 @@ public abstract class BaseCipher
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAAD(byte[] data, int offset, int length) {
|
||||
throw new UnsupportedOperationException(getClass() + " does not support AAD operations");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAAD(byte[] data) {
|
||||
updateAAD(data, 0, data.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWithAAD(byte[] input, int offset, int aadLen, int inputLen) {
|
||||
updateAAD(input, offset, aadLen);
|
||||
update(input, offset + aadLen, inputLen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,6 @@ public interface Cipher {
|
||||
/** @return the size of the initialization vector */
|
||||
int getIVSize();
|
||||
|
||||
/** @return Size of the authentication tag (AT) in bytes or 0 if this cipher does not support authentication */
|
||||
int getAuthenticationTagSize();
|
||||
|
||||
/**
|
||||
* Initialize the cipher for encryption or decryption with the given private key and initialization vector
|
||||
*
|
||||
@@ -50,32 +47,4 @@ public interface Cipher {
|
||||
*/
|
||||
void update(byte[] input, int inputOffset, int inputLen);
|
||||
|
||||
/**
|
||||
* Adds the provided input data as additional authenticated data during encryption or decryption.
|
||||
*
|
||||
* @param data The additional data to authenticate
|
||||
* @param offset The offset of the additional data in the buffer
|
||||
* @param length The number of bytes in the buffer to use for authentication
|
||||
*/
|
||||
void updateAAD(byte[] data, int offset, int length);
|
||||
|
||||
/**
|
||||
* Adds the provided input data as additional authenticated data during encryption or decryption.
|
||||
*
|
||||
* @param data The data to authenticate
|
||||
*/
|
||||
void updateAAD(byte[] data);
|
||||
|
||||
/**
|
||||
* Performs in-place authenticated encryption or decryption with additional data (AEAD). Authentication tags are
|
||||
* implicitly appended after the output ciphertext or implicitly verified after the input ciphertext. Header data
|
||||
* indicated by the {@code aadLen} parameter are authenticated but not encrypted/decrypted, while payload data
|
||||
* indicated by the {@code inputLen} parameter are authenticated and encrypted/decrypted.
|
||||
*
|
||||
* @param input The input/output bytes
|
||||
* @param offset The offset of the data in the input buffer
|
||||
* @param aadLen The number of bytes to use as additional authenticated data - starting at offset
|
||||
* @param inputLen The number of bytes to update - starting at offset + aadLen
|
||||
*/
|
||||
void updateWithAAD(byte[] input, int offset, int aadLen, int inputLen);
|
||||
}
|
||||
|
||||
@@ -44,11 +44,6 @@ public class NoneCipher
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAuthenticationTagSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Mode mode, byte[] bytes, byte[] bytes1) {
|
||||
// Nothing to do
|
||||
@@ -59,18 +54,4 @@ public class NoneCipher
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAAD(byte[] data, int offset, int length) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAAD(byte[] data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWithAAD(byte[] input, int offset, int aadLen, int inputLen) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ import java.security.GeneralSecurityException;
|
||||
* Base class for DHG key exchange algorithms. Implementations will only have to configure the required data on the
|
||||
* {@link DH} class in the
|
||||
*/
|
||||
public abstract class AbstractDHG extends AbstractDH {
|
||||
public abstract class AbstractDHG extends AbstractDH
|
||||
implements KeyExchange {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@@ -77,8 +78,8 @@ public abstract class AbstractDHG extends AbstractDH {
|
||||
digest.update(buf.array(), buf.rpos(), buf.available());
|
||||
H = digest.digest();
|
||||
|
||||
|
||||
Signature signature = trans.getHostKeyAlgorithm().newSignature();
|
||||
Signature signature = Factory.Named.Util.create(trans.getConfig().getSignatureFactories(),
|
||||
KeyType.fromKey(hostKey).toString());
|
||||
signature.initVerify(hostKey);
|
||||
signature.update(H, 0, H.length);
|
||||
if (!signature.verify(sig))
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.transport.kex;
|
||||
|
||||
import com.hierynomus.sshj.key.KeyAlgorithm;
|
||||
import net.schmizz.sshj.common.*;
|
||||
import net.schmizz.sshj.signature.Signature;
|
||||
import net.schmizz.sshj.transport.Transport;
|
||||
@@ -31,9 +30,9 @@ import java.security.GeneralSecurityException;
|
||||
public abstract class AbstractDHGex extends AbstractDH {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final int minBits = 1024;
|
||||
private final int maxBits = 8192;
|
||||
private final int preferredBits = 2048;
|
||||
private int minBits = 1024;
|
||||
private int maxBits = 8192;
|
||||
private int preferredBits = 2048;
|
||||
|
||||
public AbstractDHGex(Digest digest) {
|
||||
super(new DH(), digest);
|
||||
@@ -57,12 +56,11 @@ public abstract class AbstractDHGex extends AbstractDH {
|
||||
return parseGexGroup(buffer);
|
||||
case KEX_DH_GEX_REPLY:
|
||||
return parseGexReply(buffer);
|
||||
default:
|
||||
throw new TransportException("Unexpected message " + msg);
|
||||
}
|
||||
} catch (Buffer.BufferException be) {
|
||||
throw new TransportException(be);
|
||||
}
|
||||
throw new TransportException("Unexpected message " + msg);
|
||||
}
|
||||
|
||||
private boolean parseGexReply(SSHPacket buffer) throws Buffer.BufferException, GeneralSecurityException, TransportException {
|
||||
@@ -86,8 +84,8 @@ public abstract class AbstractDHGex extends AbstractDH {
|
||||
.putMPInt(k);
|
||||
digest.update(buf.array(), buf.rpos(), buf.available());
|
||||
H = digest.digest();
|
||||
KeyAlgorithm keyAlgorithm = trans.getHostKeyAlgorithm();
|
||||
Signature signature = keyAlgorithm.newSignature();
|
||||
Signature signature = Factory.Named.Util.create(trans.getConfig().getSignatureFactories(),
|
||||
KeyType.fromKey(hostKey).toString());
|
||||
signature.initVerify(hostKey);
|
||||
signature.update(H, 0, H.length);
|
||||
if (!signature.verify(sig))
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.transport.kex;
|
||||
|
||||
import com.hierynomus.sshj.common.KeyAlgorithm;
|
||||
import net.schmizz.sshj.common.Factory;
|
||||
import net.schmizz.sshj.transport.random.Random;
|
||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||
@@ -32,7 +31,7 @@ public class Curve25519DH extends DHBase {
|
||||
private byte[] secretKey;
|
||||
|
||||
public Curve25519DH() {
|
||||
super(KeyAlgorithm.ECDSA, "ECDH");
|
||||
super("ECDSA", "ECDH");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.transport.kex;
|
||||
|
||||
import com.hierynomus.sshj.common.KeyAlgorithm;
|
||||
import net.schmizz.sshj.common.Factory;
|
||||
import net.schmizz.sshj.common.SecurityUtils;
|
||||
import net.schmizz.sshj.transport.random.Random;
|
||||
@@ -55,7 +54,7 @@ public class ECDH extends DHBase {
|
||||
|
||||
@Override
|
||||
public void computeK(byte[] f) throws GeneralSecurityException {
|
||||
KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.EC_BC);
|
||||
KeyFactory keyFactory = SecurityUtils.getKeyFactory("EC");
|
||||
ECPublicKeySpec keySpec = new ECPublicKeySpec(getDecoded(f, ecParameterSpec.getCurve()), ecParameterSpec);
|
||||
PublicKey yourPubKey = keyFactory.generatePublic(keySpec);
|
||||
agreement.doPhase(yourPubKey, true);
|
||||
|
||||
@@ -19,9 +19,9 @@ import net.schmizz.sshj.transport.digest.Digest;
|
||||
import net.schmizz.sshj.transport.digest.SHA256;
|
||||
import net.schmizz.sshj.transport.digest.SHA384;
|
||||
import net.schmizz.sshj.transport.digest.SHA512;
|
||||
import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
|
||||
public class ECDHNistP extends AbstractDHG {
|
||||
|
||||
@@ -33,7 +33,7 @@ public class ECDHNistP extends AbstractDHG {
|
||||
|
||||
@Override
|
||||
public KeyExchange create() {
|
||||
return new ECDHNistP("secp521r1", new SHA512());
|
||||
return new ECDHNistP("P-521", new SHA512());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,7 +48,7 @@ public class ECDHNistP extends AbstractDHG {
|
||||
|
||||
@Override
|
||||
public KeyExchange create() {
|
||||
return new ECDHNistP("secp384r1", new SHA384());
|
||||
return new ECDHNistP("P-384", new SHA384());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,7 +63,7 @@ public class ECDHNistP extends AbstractDHG {
|
||||
|
||||
@Override
|
||||
public KeyExchange create() {
|
||||
return new ECDHNistP("secp256r1", new SHA256());
|
||||
return new ECDHNistP("P-256", new SHA256());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,7 +79,7 @@ public class ECDHNistP extends AbstractDHG {
|
||||
|
||||
@Override
|
||||
protected void initDH(DHBase dh) throws GeneralSecurityException {
|
||||
dh.init(new ECGenParameterSpec(curve), trans.getConfig().getRandomFactory());
|
||||
dh.init(new ECNamedCurveGenParameterSpec(curve), trans.getConfig().getRandomFactory());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.transport.verification;
|
||||
|
||||
import com.hierynomus.sshj.common.KeyAlgorithm;
|
||||
import com.hierynomus.sshj.transport.verification.KnownHostMatchers;
|
||||
import net.schmizz.sshj.common.*;
|
||||
import org.slf4j.Logger;
|
||||
@@ -41,11 +40,6 @@ public class OpenSSHKnownHosts
|
||||
protected final File khFile;
|
||||
protected final List<KnownHostEntry> entries = new ArrayList<KnownHostEntry>();
|
||||
|
||||
public OpenSSHKnownHosts(Reader reader) throws IOException {
|
||||
this(reader, LoggerFactory.DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
public OpenSSHKnownHosts(File khFile)
|
||||
throws IOException {
|
||||
this(khFile, LoggerFactory.DEFAULT);
|
||||
@@ -56,40 +50,29 @@ public class OpenSSHKnownHosts
|
||||
this.khFile = khFile;
|
||||
log = loggerFactory.getLogger(getClass());
|
||||
if (khFile.exists()) {
|
||||
final EntryFactory entryFactory = new EntryFactory();
|
||||
final BufferedReader br = new BufferedReader(new FileReader(khFile));
|
||||
try {
|
||||
readEntries(br);
|
||||
// Read in the file, storing each line as an entry
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
try {
|
||||
KnownHostEntry entry = entryFactory.parseEntry(line);
|
||||
if (entry != null) {
|
||||
entries.add(entry);
|
||||
}
|
||||
} catch (SSHException ignore) {
|
||||
log.debug("Bad line ({}): {} ", ignore.toString(), line);
|
||||
} catch (SSHRuntimeException ignore) {
|
||||
log.debug("Failed to process line ({}): {} ", ignore.toString(), line);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
IOUtils.closeQuietly(br);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public OpenSSHKnownHosts(Reader reader, LoggerFactory loggerFactory) throws IOException {
|
||||
this.khFile = null;
|
||||
log = loggerFactory.getLogger(getClass());
|
||||
BufferedReader br = new BufferedReader(reader);
|
||||
readEntries(br);
|
||||
}
|
||||
|
||||
private void readEntries(BufferedReader br) throws IOException {
|
||||
final EntryFactory entryFactory = new EntryFactory();
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
try {
|
||||
KnownHostEntry entry = entryFactory.parseEntry(line);
|
||||
if (entry != null) {
|
||||
entries.add(entry);
|
||||
}
|
||||
} catch (SSHException ignore) {
|
||||
log.debug("Bad line ({}): {} ", ignore.toString(), line);
|
||||
} catch (SSHRuntimeException ignore) {
|
||||
log.debug("Failed to process line ({}): {} ", ignore.toString(), line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public File getFile() {
|
||||
return khFile;
|
||||
}
|
||||
@@ -207,7 +190,7 @@ public class OpenSSHKnownHosts
|
||||
* Lines starting with `#' and empty lines are ignored as comments.
|
||||
*/
|
||||
public class EntryFactory {
|
||||
public EntryFactory() {
|
||||
EntryFactory() {
|
||||
}
|
||||
|
||||
public KnownHostEntry parseEntry(String line)
|
||||
@@ -256,7 +239,7 @@ public class OpenSSHKnownHosts
|
||||
final BigInteger e = new BigInteger(split[i++]);
|
||||
final BigInteger n = new BigInteger(split[i++]);
|
||||
try {
|
||||
final KeyFactory keyFactory = SecurityUtils.getKeyFactory(KeyAlgorithm.RSA);
|
||||
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
|
||||
key = keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
|
||||
} catch (Exception ex) {
|
||||
log.error("Error reading entry `{}`, could not create key", line, ex);
|
||||
@@ -404,7 +387,7 @@ public class OpenSSHKnownHosts
|
||||
line.append(" ").append(type.toString());
|
||||
line.append(" ").append(getKeyString(key));
|
||||
|
||||
if (comment != null && !comment.isEmpty()) line.append(" ").append(comment);
|
||||
if (!comment.isEmpty()) line.append(" ").append(comment);
|
||||
|
||||
return line.toString();
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ import net.schmizz.sshj.Service;
|
||||
import net.schmizz.sshj.transport.TransportException;
|
||||
import net.schmizz.sshj.userauth.method.AuthMethod;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/** User authentication API. See RFC 4252. */
|
||||
public interface UserAuth {
|
||||
|
||||
@@ -60,6 +58,6 @@ public interface UserAuth {
|
||||
boolean hadPartialSuccess();
|
||||
|
||||
/** The available authentication methods. This is only defined once an unsuccessful authentication has taken place. */
|
||||
Collection<String> getAllowedMethods();
|
||||
Iterable<String> getAllowedMethods();
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import net.schmizz.sshj.transport.TransportException;
|
||||
import net.schmizz.sshj.userauth.method.AuthMethod;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -100,7 +99,7 @@ public class UserAuthImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getAllowedMethods() {
|
||||
public Iterable<String> getAllowedMethods() {
|
||||
return Collections.unmodifiableList(allowedMethods);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.userauth.keyprovider;
|
||||
|
||||
import com.hierynomus.sshj.common.KeyAlgorithm;
|
||||
import com.hierynomus.sshj.transport.cipher.BlockCiphers;
|
||||
import net.schmizz.sshj.common.Base64;
|
||||
import net.schmizz.sshj.common.ByteArrayUtils;
|
||||
@@ -99,7 +98,7 @@ public class PKCS5KeyFile extends BaseFileKeyProvider {
|
||||
} else if ("DSS".equals(s)) {
|
||||
type = KeyType.DSA;
|
||||
} else {
|
||||
throw new FormatException("Unrecognized PKCS5 key type");
|
||||
throw new FormatException("Unrecognized PKCS5 key type: " + s);
|
||||
}
|
||||
} else {
|
||||
throw new FormatException("Bad header; possibly PKCS8 format?");
|
||||
@@ -109,12 +108,12 @@ public class PKCS5KeyFile extends BaseFileKeyProvider {
|
||||
} else if (type != null) {
|
||||
if (line.startsWith("Proc-Type: ")) {
|
||||
if (!"4,ENCRYPTED".equals(line.substring(11))) {
|
||||
throw new FormatException("Unrecognized Proc-Type");
|
||||
throw new FormatException("Unrecognized Proc-Type: " + line.substring(11));
|
||||
}
|
||||
} else if (line.startsWith("DEK-Info: ")) {
|
||||
int ptr = line.indexOf(",");
|
||||
if (ptr == -1) {
|
||||
throw new FormatException("Unrecognized DEK-Info");
|
||||
throw new FormatException("Unrecognized DEK-Info: " + line.substring(10));
|
||||
} else {
|
||||
String algorithm = line.substring(10, ptr);
|
||||
if ("DES-EDE3-CBC".equals(algorithm)) {
|
||||
@@ -141,7 +140,7 @@ public class PKCS5KeyFile extends BaseFileKeyProvider {
|
||||
ASN1Data asn = new ASN1Data(data = decrypt(Base64.decode(sb.toString()), cipher, iv));
|
||||
switch (type) {
|
||||
case RSA: {
|
||||
KeyFactory factory = KeyFactory.getInstance(KeyAlgorithm.RSA);
|
||||
KeyFactory factory = KeyFactory.getInstance("RSA");
|
||||
asn.readNext();
|
||||
BigInteger modulus = asn.readNext();
|
||||
BigInteger pubExp = asn.readNext();
|
||||
@@ -151,7 +150,7 @@ public class PKCS5KeyFile extends BaseFileKeyProvider {
|
||||
return new KeyPair(pubKey, prvKey);
|
||||
}
|
||||
case DSA: {
|
||||
KeyFactory factory = KeyFactory.getInstance(KeyAlgorithm.DSA);
|
||||
KeyFactory factory = KeyFactory.getInstance("DSA");
|
||||
asn.readNext();
|
||||
BigInteger p = asn.readNext();
|
||||
BigInteger q = asn.readNext();
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.userauth.keyprovider;
|
||||
|
||||
import com.hierynomus.sshj.common.KeyDecryptionFailedException;
|
||||
import net.schmizz.sshj.common.IOUtils;
|
||||
import net.schmizz.sshj.common.SecurityUtils;
|
||||
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
||||
@@ -64,16 +63,12 @@ public class PKCS8KeyFile extends BaseFileKeyProvider {
|
||||
final Object o = r.readObject();
|
||||
|
||||
final JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
|
||||
if (SecurityUtils.getSecurityProvider() != null) {
|
||||
pemConverter.setProvider(SecurityUtils.getSecurityProvider());
|
||||
}
|
||||
pemConverter.setProvider(SecurityUtils.getSecurityProvider());
|
||||
|
||||
if (o instanceof PEMEncryptedKeyPair) {
|
||||
final PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) o;
|
||||
JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder();
|
||||
if (SecurityUtils.getSecurityProvider() != null) {
|
||||
decryptorBuilder.setProvider(SecurityUtils.getSecurityProvider());
|
||||
}
|
||||
decryptorBuilder.setProvider(SecurityUtils.getSecurityProvider());
|
||||
try {
|
||||
passphrase = pwdf == null ? null : pwdf.reqPassword(resource);
|
||||
kp = pemConverter.getKeyPair(encryptedKeyPair.decryptKeyPair(decryptorBuilder.build(passphrase)));
|
||||
@@ -90,7 +85,7 @@ public class PKCS8KeyFile extends BaseFileKeyProvider {
|
||||
if (pwdf != null && pwdf.shouldRetry(resource))
|
||||
continue;
|
||||
else
|
||||
throw new KeyDecryptionFailedException(e);
|
||||
throw e;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(r);
|
||||
}
|
||||
|
||||
@@ -15,21 +15,9 @@
|
||||
*/
|
||||
package net.schmizz.sshj.userauth.keyprovider;
|
||||
|
||||
import com.hierynomus.sshj.common.KeyAlgorithm;
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||
import net.schmizz.sshj.common.Base64;
|
||||
import net.schmizz.sshj.common.Buffer;
|
||||
import net.schmizz.sshj.common.KeyType;
|
||||
import net.schmizz.sshj.common.SecurityUtils;
|
||||
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
||||
import org.bouncycastle.asn1.nist.NISTNamedCurves;
|
||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
@@ -112,21 +100,21 @@ public class PuTTYKeyFile extends BaseFileKeyProvider {
|
||||
|
||||
protected KeyPair readKeyPair() throws IOException {
|
||||
this.parseKeyPair();
|
||||
final Buffer.PlainBuffer publicKeyReader = new Buffer.PlainBuffer(publicKey);
|
||||
final Buffer.PlainBuffer privateKeyReader = new Buffer.PlainBuffer(privateKey);
|
||||
publicKeyReader.readBytes(); // The first part of the payload is a human-readable key format name.
|
||||
if (KeyType.RSA.equals(this.getType())) {
|
||||
final KeyReader publicKeyReader = new KeyReader(publicKey);
|
||||
publicKeyReader.skip(); // skip this
|
||||
// public key exponent
|
||||
BigInteger e = publicKeyReader.readMPInt();
|
||||
BigInteger e = publicKeyReader.readInt();
|
||||
// modulus
|
||||
BigInteger n = publicKeyReader.readMPInt();
|
||||
BigInteger n = publicKeyReader.readInt();
|
||||
|
||||
final KeyReader privateKeyReader = new KeyReader(privateKey);
|
||||
// private key exponent
|
||||
BigInteger d = privateKeyReader.readMPInt();
|
||||
BigInteger d = privateKeyReader.readInt();
|
||||
|
||||
final KeyFactory factory;
|
||||
try {
|
||||
factory = KeyFactory.getInstance(KeyAlgorithm.RSA);
|
||||
factory = KeyFactory.getInstance("RSA");
|
||||
} catch (NoSuchAlgorithmException s) {
|
||||
throw new IOException(s.getMessage(), s);
|
||||
}
|
||||
@@ -140,17 +128,20 @@ public class PuTTYKeyFile extends BaseFileKeyProvider {
|
||||
}
|
||||
}
|
||||
if (KeyType.DSA.equals(this.getType())) {
|
||||
BigInteger p = publicKeyReader.readMPInt();
|
||||
BigInteger q = publicKeyReader.readMPInt();
|
||||
BigInteger g = publicKeyReader.readMPInt();
|
||||
BigInteger y = publicKeyReader.readMPInt();
|
||||
final KeyReader publicKeyReader = new KeyReader(publicKey);
|
||||
publicKeyReader.skip(); // skip this
|
||||
BigInteger p = publicKeyReader.readInt();
|
||||
BigInteger q = publicKeyReader.readInt();
|
||||
BigInteger g = publicKeyReader.readInt();
|
||||
BigInteger y = publicKeyReader.readInt();
|
||||
|
||||
final KeyReader privateKeyReader = new KeyReader(privateKey);
|
||||
// Private exponent from the private key
|
||||
BigInteger x = privateKeyReader.readMPInt();
|
||||
BigInteger x = privateKeyReader.readInt();
|
||||
|
||||
final KeyFactory factory;
|
||||
try {
|
||||
factory = KeyFactory.getInstance(KeyAlgorithm.DSA);
|
||||
factory = KeyFactory.getInstance("DSA");
|
||||
} catch (NoSuchAlgorithmException s) {
|
||||
throw new IOException(s.getMessage(), s);
|
||||
}
|
||||
@@ -162,42 +153,9 @@ public class PuTTYKeyFile extends BaseFileKeyProvider {
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
throw new IOException(String.format("Unknown key type %s", this.getType()));
|
||||
}
|
||||
if (KeyType.ED25519.equals(this.getType())) {
|
||||
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("Ed25519");
|
||||
EdDSAPublicKeySpec publicSpec = new EdDSAPublicKeySpec(publicKeyReader.readBytes(), ed25519);
|
||||
EdDSAPrivateKeySpec privateSpec = new EdDSAPrivateKeySpec(privateKeyReader.readBytes(), ed25519);
|
||||
return new KeyPair(new EdDSAPublicKey(publicSpec), new EdDSAPrivateKey(privateSpec));
|
||||
}
|
||||
final String ecdsaCurve;
|
||||
switch (this.getType()) {
|
||||
case ECDSA256:
|
||||
ecdsaCurve = "P-256";
|
||||
break;
|
||||
case ECDSA384:
|
||||
ecdsaCurve = "P-384";
|
||||
break;
|
||||
case ECDSA521:
|
||||
ecdsaCurve = "P-521";
|
||||
break;
|
||||
default:
|
||||
ecdsaCurve = null;
|
||||
break;
|
||||
}
|
||||
if (ecdsaCurve != null) {
|
||||
BigInteger s = new BigInteger(1, privateKeyReader.readBytes());
|
||||
X9ECParameters ecParams = NISTNamedCurves.getByName(ecdsaCurve);
|
||||
ECNamedCurveSpec ecCurveSpec =
|
||||
new ECNamedCurveSpec(ecdsaCurve, ecParams.getCurve(), ecParams.getG(), ecParams.getN());
|
||||
ECPrivateKeySpec pks = new ECPrivateKeySpec(s, ecCurveSpec);
|
||||
try {
|
||||
PrivateKey privateKey = SecurityUtils.getKeyFactory(KeyAlgorithm.ECDSA).generatePrivate(pks);
|
||||
return new KeyPair(getType().readPubKeyFromBuffer(publicKeyReader), privateKey);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
throw new IOException(String.format("Unknown key type %s", this.getType()));
|
||||
}
|
||||
|
||||
protected void parseKeyPair() throws IOException {
|
||||
@@ -338,4 +296,43 @@ public class PuTTYKeyFile extends BaseFileKeyProvider {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the putty key bit vector, which is an encoded sequence
|
||||
* of {@link java.math.BigInteger}s.
|
||||
*/
|
||||
private final static class KeyReader {
|
||||
private final DataInput di;
|
||||
|
||||
public KeyReader(byte[] key) {
|
||||
this.di = new DataInputStream(new ByteArrayInputStream(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips an integer without reading it.
|
||||
*/
|
||||
public void skip() throws IOException {
|
||||
final int read = di.readInt();
|
||||
if (read != di.skipBytes(read)) {
|
||||
throw new IOException(String.format("Failed to skip %d bytes", read));
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] read() throws IOException {
|
||||
int len = di.readInt();
|
||||
if (len <= 0 || len > 513) {
|
||||
throw new IOException(String.format("Invalid length %d", len));
|
||||
}
|
||||
byte[] r = new byte[len];
|
||||
di.readFully(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next integer.
|
||||
*/
|
||||
public BigInteger readInt() throws IOException {
|
||||
return new BigInteger(read());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
|
||||
/**
|
||||
* Implements the {@code "publickey"} SSH authentication method.
|
||||
* <p/>
|
||||
* Requesting authentication with this method first sends a "feeler" request with just the public key, and if the
|
||||
* Requesteing authentication with this method first sends a "feeler" request with just the public key, and if the
|
||||
* server responds with {@code SSH_MSG_USERAUTH_PK_OK} indicating that the key is acceptable, it proceeds to send a
|
||||
* request signed with the private key. Therefore, private keys are not requested from the associated {@link
|
||||
* KeyProvider} unless needed.
|
||||
|
||||
@@ -15,12 +15,11 @@
|
||||
*/
|
||||
package net.schmizz.sshj.userauth.method;
|
||||
|
||||
import com.hierynomus.sshj.key.KeyAlgorithm;
|
||||
import net.schmizz.sshj.common.Buffer;
|
||||
import net.schmizz.sshj.common.Factory;
|
||||
import net.schmizz.sshj.common.KeyType;
|
||||
import net.schmizz.sshj.common.SSHPacket;
|
||||
import net.schmizz.sshj.signature.Signature;
|
||||
import net.schmizz.sshj.transport.TransportException;
|
||||
import net.schmizz.sshj.userauth.UserAuthException;
|
||||
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
|
||||
|
||||
@@ -48,15 +47,9 @@ public abstract class KeyedAuthMethod
|
||||
}
|
||||
|
||||
// public key as 2 strings: [ key type | key blob ]
|
||||
KeyType keyType = KeyType.fromKey(key);
|
||||
try {
|
||||
KeyAlgorithm ka = params.getTransport().getClientKeyAlgorithm(keyType);
|
||||
reqBuf.putString(ka.getKeyAlgorithm())
|
||||
.putString(new Buffer.PlainBuffer().putPublicKey(key).getCompactData());
|
||||
return reqBuf;
|
||||
} catch (IOException ioe) {
|
||||
throw new UserAuthException("No KeyAlgorithm configured for key " + keyType);
|
||||
}
|
||||
reqBuf.putString(KeyType.fromKey(key).toString())
|
||||
.putString(new Buffer.PlainBuffer().putPublicKey(key).getCompactData());
|
||||
return reqBuf;
|
||||
}
|
||||
|
||||
protected SSHPacket putSig(SSHPacket reqBuf)
|
||||
@@ -68,20 +61,17 @@ public abstract class KeyedAuthMethod
|
||||
throw new UserAuthException("Problem getting private key from " + kProv, ioe);
|
||||
}
|
||||
|
||||
final KeyType kt = KeyType.fromKey(key);
|
||||
Signature signature;
|
||||
try {
|
||||
signature = params.getTransport().getClientKeyAlgorithm(kt).newSignature();
|
||||
} catch (TransportException e) {
|
||||
throw new UserAuthException("No KeyAlgorithm configured for key " + kt);
|
||||
}
|
||||
final String kt = KeyType.fromKey(key).toString();
|
||||
Signature signature = Factory.Named.Util.create(params.getTransport().getConfig().getSignatureFactories(), kt);
|
||||
if (signature == null)
|
||||
throw new UserAuthException("Could not create signature instance for " + kt + " key");
|
||||
|
||||
signature.initSign(key);
|
||||
signature.update(new Buffer.PlainBuffer()
|
||||
.putString(params.getTransport().getSessionID())
|
||||
.putBuffer(reqBuf) // & rest of the data for sig
|
||||
.getCompactData());
|
||||
reqBuf.putSignature(signature.getSignatureName(), signature.encode(signature.sign()));
|
||||
reqBuf.putSignature(kt, signature.encode(signature.sign()));
|
||||
return reqBuf;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package com.hierynomus.sshj.common
|
||||
|
||||
import com.hierynomus.sshj.userauth.certificate.Certificate
|
||||
import net.schmizz.sshj.common.Base64
|
||||
import net.schmizz.sshj.common.Buffer
|
||||
import net.schmizz.sshj.common.KeyType
|
||||
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile
|
||||
import spock.lang.Specification
|
||||
@@ -33,88 +30,16 @@ class KeyTypeSpec extends Specification {
|
||||
|
||||
expect:
|
||||
KeyType.fromKey(kf.getPublic()) == type
|
||||
KeyType.fromKey(kf.getPrivate()) == privateType
|
||||
KeyType.fromKey(kf.getPrivate()) == type
|
||||
|
||||
where:
|
||||
privKey << [
|
||||
"""-----BEGIN EC PRIVATE KEY-----
|
||||
privKey << ["""-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIGhcvG8anyHew/xZJfozh5XIc1kmZZs6o2f0l3KFs4jgoAoGCCqGSM49
|
||||
AwEHoUQDQgAEDUA1JYVD7URSoOGdwPxjea+ETD6IABMD9CWfk3NVTNkdu/Ksn7uX
|
||||
cLTQhx4N16z1IgW2bRbSbsmM++UKXmeWyg==
|
||||
-----END EC PRIVATE KEY-----""",
|
||||
-----END EC PRIVATE KEY-----"""]
|
||||
pubKey << ["""ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBA1ANSWFQ+1EUqDhncD8Y3mvhEw+iAATA/Qln5NzVUzZHbvyrJ+7l3C00IceDdes9SIFtm0W0m7JjPvlCl5nlso= SSH Key"""]
|
||||
type << [KeyType.ECDSA256]
|
||||
|
||||
// ssh-keygen -f ca_key -N '' -t rsa -b 1024 \
|
||||
// && ssh-keygen -f id_rsa_test -N '' -t rsa -b 1024 -m pem \
|
||||
// && cat id_rsa_test
|
||||
"""-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQDNBlUYU5KebH8PBf5i58zFI7xW2CLwUrzKA3949+0wnA9JzrX1
|
||||
XWiVJG3gNgQEgUZIIrPfPAMk9x6hVdBKL9gi3tRUfGTQfQZ7JN9rMFmlbLmEFHd4
|
||||
RY86OHe2h7SO+xfYBieR7aL0DsbwcBZIWm0xlotHzR6d3QodMLYZh0jleQIDAQAB
|
||||
AoGAdzHIRRVJN0tSbxSH+U5T8QS+mSqc3WTslvGDqXtR7SG9jaZciOKeS57bNi+R
|
||||
FGFnz8ZFFnJYTaRRrXArYQYBu/Fp5EtMJQ52G04gGI5mov+4vACaJ3J98wieBMZh
|
||||
miQXZUXjmCIkE+3/SxIIE1Cf2J8Epa012FZ5vcu+kfjOZZECQQDwTm2Hdp8PTpTm
|
||||
BX802Z7zO/ZfW+oGK4LIqvcUqf/2NnA3zpgjAwl9FtxpSzzq4lvcNMTANk3ZkJIg
|
||||
VZsn5Ar9AkEA2moMF2AvWuW7LN5aDKpyPqJJv9fxM1HOkrYWu6aYyl/r5/RaIwSp
|
||||
Bl/5W1Elg5xgYbnms1wtgLIpipfAofoDLQJAG0XrbGpsFwKmJ40MKOViAt0VUzFN
|
||||
WDHr//ZXYIMCx+DZz5uk7KRVmVrU3SZq3YWfQ1jB08bWAxFDZGQS3e4lyQJBANki
|
||||
bkza6ZkjJFax4rIOzS7pZgob4wWTAZum/KinMeSXQc7ChM2ld2gIB705yeKylrrw
|
||||
9qI/NFlqRZQr02z0QS0CQQDVnk224ebhcFlUG6AFcQW/b3O9yqKh6Qj7q9AK5CbV
|
||||
8T8wEvB6yg929UbNSzqtKFHD2+oq/VQF7sym8BTCA9jp
|
||||
-----END RSA PRIVATE KEY-----""",
|
||||
|
||||
// ssh-keygen -f ca_key -N '' -t rsa -b 1024 \
|
||||
// && ssh-keygen -f id_dsa_test -N '' -t dsa -b 1024 -m pem \
|
||||
// && cat id_dsa_test
|
||||
"""-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIBuwIBAAKBgQDCY3/O8Locj4ByO/tFiGi83rQNFlCeD44ZBiZgCMCh687H49OC
|
||||
r1G8Z6Ga55uLp87DXhdEjq8HXgMhDXQakqF5huOyTkPibdsOlv86l3sw8NBBGGMF
|
||||
OE4t6Qj2pVA2YrvUKY7UiyZpOdLVzrXAcouE/32259vDIbX6Y84F+TzZKwIVAOR3
|
||||
zWOxnbR8wR9xKdcMczNlxOtBAoGAVBDn7jKB76oTzcmCnDyoBNISNNiknuhyM0xp
|
||||
hfVMGMgUw72WLWE9k9LYBZMRWBLAeI3C5PuV0cJuSXOz1maY9B+NHr9z7AmMfPF0
|
||||
eK3Fr7IHyr1DcZNZ3yE7UX4UPB/9blgxj/m1/Kvgvl/l9F+wDIH/uAJ+Awuv5a8w
|
||||
jVAaZPcCgYB/vvvduepAMBYSHB3/J7a9GeEAhIlu69fGhiwUmrD1hTWKa4skVKDT
|
||||
PcJ/j1urFglMdh/hKB3DdjT5Fs+95VJYvBBuOwhZ/XwQCQcFLlSXi/CvbaV63f8d
|
||||
f26VSnEypH3G3cmPYfpVcXL63bCb0E4sNJwENM4tQGZa5YGz3CxMdgIVAJUv4z9+
|
||||
2AE1NF07cGZ4Zs9euh9y
|
||||
-----END DSA PRIVATE KEY-----""",
|
||||
]
|
||||
pubKey << [
|
||||
"""ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBA1ANSWFQ+1EUqDhncD8Y3mvhEw+iAATA/Qln5NzVUzZHbvyrJ+7l3C00IceDdes9SIFtm0W0m7JjPvlCl5nlso= SSH Key""",
|
||||
|
||||
// ssh-keygen -s ca_key -I sshj_test -n user -V +240m id_rsa_test.pub \
|
||||
// && cat id_rsa_test-cert.pub
|
||||
"""ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgKXsDoXKTlSaN3N/z6OwYQwCWMAf6N5CidrRJMe+IUOwAAAADAQABAAAAgQDNBlUYU5KebH8PBf5i58zFI7xW2CLwUrzKA3949+0wnA9JzrX1XWiVJG3gNgQEgUZIIrPfPAMk9x6hVdBKL9gi3tRUfGTQfQZ7JN9rMFmlbLmEFHd4RY86OHe2h7SO+xfYBieR7aL0DsbwcBZIWm0xlotHzR6d3QodMLYZh0jleQAAAAAAAAAAAAAAAQAAAAlzc2hqX3Rlc3QAAAAIAAAABHVzZXIAAAAAXuczLAAAAABe52vUAAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAZcAAAAHc3NoLXJzYQAAAAMBAAEAAAGBAN4tykUwkwobduBrqTJW7HNJP1Z6bAhzNNA1P2KY+0aO0iBhISHcaWS0vKsgQ4BYbbVfTkrc0rEuRnajl9PhhEyZgJs8oR7sGndxAlDY6UJH4wSL3j7A+2bogoSbpOfWZiPp/tJohPBvmsN6Uv89Axs0L7V338yH3UE4bX6eIQDZVjKjL7evOYz7sOdV7pUYvgzErqzVxxmF7t/yd61rNOOLm0PY4O1HpW2ZYGGtG8YIC8asFYY2EouLy8OsP2z7U8DLFokTuMsTA6ADN5tYbzBqxUCMsuUPqdGz4xnlTja7jm4FjBFa91KmpQSOWhveaQeb91dwMeomyplYH8W6tkDuXR7acncxYAjB955ws/T9qWrACWFryskUGI1oupM5QVXveO793oWoSqtDi6BOw763Z+7oekmScOOSpeRgsNvSPN+RMyDDuT0Sf4Tc/aLABow6t5UfULAwv9xqLg9QH6CS9ZSkIWNiEOkhCa1uH2srSF6e9m2XN0f5EawZ81EYBQAAAZQAAAAMcnNhLXNoYTItNTEyAAABgFrJp0zHjElwO+PV/hd5zXydySLLKI6A/UzCnCcceSY46oO94Uzn3Bc8UKdxMctlMOG1LGeiuYE/CMMGwnuo1TLWrfY1anVigPx0CrHzjE7ZT4qhCJsVmuwpU3qcZOrom+bDbco2N30/K81rrU5KlmVG6zGHNOpwRr2zRIusXGQ3/e+dOzsMh1cmO/XntGmxWXYPIHs4TUXE1d5C2hZFN1jkBkvlG6n6ZMq7Z+6V5oVc2bqETJv6zxypt1II7l5ObZJP26x75yb4VEbycHLENYSgSVBoN7pyc7QqRYbTnfdxJBKyjDmjOXAMlAzFch5BVHazw1PNS+BkKLZaDb/dlTfeKjDqIywb97zT4XJ70HUTZB3P/q6OwiTtrKOW9no5C9Wka2EkOliNwvsJyxYxNmS8SEzT/Ezk7vhxzS8C17+uBX55o0nJ1bjPw0E02mAoIu5o0sXm/J+3dW+s1TG1XzXdksUthG8EozQfr5M0MuOeONkwebtAo/JzSF73rlGBlA== sshj@example.com""",
|
||||
|
||||
// ssh-keygen -s ca_key -I sshj_test -n user -V +240m id_dsa_test.pub \
|
||||
// && cat id_dsa_test-cert.pub
|
||||
"""ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgOjflXUJk5PKmdg2F4lLYyluqOR+xNAGNoc3SzPBuUKMAAACBAMJjf87wuhyPgHI7+0WIaLzetA0WUJ4PjhkGJmAIwKHrzsfj04KvUbxnoZrnm4unzsNeF0SOrwdeAyENdBqSoXmG47JOQ+Jt2w6W/zqXezDw0EEYYwU4Ti3pCPalUDZiu9QpjtSLJmk50tXOtcByi4T/fbbn28MhtfpjzgX5PNkrAAAAFQDkd81jsZ20fMEfcSnXDHMzZcTrQQAAAIBUEOfuMoHvqhPNyYKcPKgE0hI02KSe6HIzTGmF9UwYyBTDvZYtYT2T0tgFkxFYEsB4jcLk+5XRwm5Jc7PWZpj0H40ev3PsCYx88XR4rcWvsgfKvUNxk1nfITtRfhQ8H/1uWDGP+bX8q+C+X+X0X7AMgf+4An4DC6/lrzCNUBpk9wAAAIB/vvvduepAMBYSHB3/J7a9GeEAhIlu69fGhiwUmrD1hTWKa4skVKDTPcJ/j1urFglMdh/hKB3DdjT5Fs+95VJYvBBuOwhZ/XwQCQcFLlSXi/CvbaV63f8df26VSnEypH3G3cmPYfpVcXL63bCb0E4sNJwENM4tQGZa5YGz3CxMdgAAAAAAAAAAAAAAAQAAAAlzc2hqX3Rlc3QAAAAIAAAABHVzZXIAAAAAXuc3ZAAAAABe52/0AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAZcAAAAHc3NoLXJzYQAAAAMBAAEAAAGBAN4tykUwkwobduBrqTJW7HNJP1Z6bAhzNNA1P2KY+0aO0iBhISHcaWS0vKsgQ4BYbbVfTkrc0rEuRnajl9PhhEyZgJs8oR7sGndxAlDY6UJH4wSL3j7A+2bogoSbpOfWZiPp/tJohPBvmsN6Uv89Axs0L7V338yH3UE4bX6eIQDZVjKjL7evOYz7sOdV7pUYvgzErqzVxxmF7t/yd61rNOOLm0PY4O1HpW2ZYGGtG8YIC8asFYY2EouLy8OsP2z7U8DLFokTuMsTA6ADN5tYbzBqxUCMsuUPqdGz4xnlTja7jm4FjBFa91KmpQSOWhveaQeb91dwMeomyplYH8W6tkDuXR7acncxYAjB955ws/T9qWrACWFryskUGI1oupM5QVXveO793oWoSqtDi6BOw763Z+7oekmScOOSpeRgsNvSPN+RMyDDuT0Sf4Tc/aLABow6t5UfULAwv9xqLg9QH6CS9ZSkIWNiEOkhCa1uH2srSF6e9m2XN0f5EawZ81EYBQAAAZQAAAAMcnNhLXNoYTItNTEyAAABgKlle1p8BfukO4xZAdLNfaH7iPqxvPd34tPeaK8esXlui5ZicjcsXNm92k74VHhFH4vTNmYdF8lqwoiHK6af8eja1W/yvj5lYkZe84K2XGIOZ8UefBT8w9ms1WPgdPtGbznr/uTOhgJr7LrHQDJiGv8wrsaJe3Md59zqIhFrhq/aSkmd/7lpsiPSgxtz/PyxEjquBp+d0qVpWxAqng+rofYMFIau+Ucc6J6JX8xrkDZJ7JBUrzFjNWWrkp3ZJVcxlBnqRtfkrU2t+LpFZEwGUmjmejUz5Ydc0n5GfCe29rhICwAlNStVR/Y/WgTJRWJsaza1ZkitryBozEL/vZNrVB4eQ+G8fUqhdflPzMH1MxQREt97dtZPxbyIxX8mOFYbiIVVH9Ar0h+SLapTc9u6/bw9N4lft7Rkp7yehhvlKd6u+Rls8KgGNcn9SMf4kBSCnfFro1lZLc7z1e87EIdrgoBMc07eAvviqYctXqrz69y90+x5bqEr67V0/MPqA+pM1Q== sshj@example.com""",
|
||||
]
|
||||
|
||||
type << [
|
||||
KeyType.ECDSA256,
|
||||
KeyType.RSA_CERT,
|
||||
KeyType.DSA_CERT,
|
||||
]
|
||||
|
||||
privateType << [
|
||||
KeyType.ECDSA256,
|
||||
KeyType.RSA,
|
||||
KeyType.DSA,
|
||||
]
|
||||
}
|
||||
|
||||
def "should read signed certificate (public)"() {
|
||||
given:
|
||||
def key = """ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg10JjXqWoxeMUyik45jr0cIZ/hFmYZQO27ilcjFHDVpgAAAADAQABAAAAgQCbFJRT+YwxvPCuHjWfEzeMs/Xkp6ay/N9J4XgSgHcyB6yeYw0KMW4Rs6OWJZcvj5ejuUonS9Kbwyf0YaylZxlfxt/K06rtHgKjwY3SSAQz4Y6woo4QI+pNP6SciJ/XymnE8+ZC6bJxwF5VtX1ivPn8o5am6LiDUk7kQoPAkBfs5/IE+w5UvO4zAAAAAQAAAE52YXVsdC1hcHByb2xlLWRiZDY5ZGExNmNiOTYwYjRhYTJkMzdlODcwZTA5OTdkN2M3ZjhhMjVlZTcyYmEwNTU0NTQ0NjBmNDA1YWU3ZjIAAAAPAAAAC2JyZWFrLWdsYXNzAAAAAF7B1hkAAAAAXsHdPwAAAAAAAAASAAAACnBlcm1pdC1wdHkAAAAAAAAAAAAAAhcAAAAHc3NoLXJzYQAAAAMBAAEAAAIBAOZSr+o8qpoAxBByB3dB0uRbaP9TMKU7W/j/RTIrVINeMJFzzkrqX6Bwwvn6+cAUjuLMz7L8H9Wqjivp48XWWPyyYbJ64bPdlPFzAzWbdCfY4Nd2akFLDTKqd5i0+iu+06suMEmvKVMQraNvjPccshrtcQYHTB0qmq6G1PjFaUxMeeSdv+U8+AqKIVMcuvnVfidUnaaVXn3ie9R616l3JwtvW/XS1SeAqrMqovvMMmZrIB9Jq9WPyV5hriYeWwFPbZUhsQsSj78IMxLdp0P318+6LUkuLuGZ9QGrQxWeOM2Y1/4PA3CHUBIRiA7+UGafkwn2y3L9XtxHXdQvcotV1zWq805YDw7frQJTXEI028+NPE0sE0aLbNM8/RibXgukiL8nP9M9ZfSlB8tUDO5Kuq5nWEUQ6hODW+RLf3qQFlCCF1mLy4HnwjY70jyLankVThIK2ZMoUqujVlBo5Fh8ptwzQ+VvJ9EUcz9rnoGtP0qIxutcTROKvUMcCKNimu7K+PP5+U6GJK4UbPqJSKGO7z85BBsNoqU50S2DP7lEhqd/9Ty+zXICu/Fjtio2uM4GfFIFChqTR2QuJ25dw9+v9yCVcqwozWeb0MOLm3i/bpxNqbici8ol1ZNBDyoI9gyi3vuxPkzerse7IplqUraINvXXQxrqR7/WNehayruAwYcNAAACDwAAAAdzc2gtcnNhAAACAMoIDDhDC2TCOEYE46tKL/lD4eODb4MxVJBWxBPcdUtDf24L7TuOoeRAoOIpKtv5JKU2du3ElUMnheyX+3IWuh4H8AuHGU4AyFc+cXvyGNAE7mppUb637cPNCOVgfUdImHtPRiP6MdILFeMAHNPpfkh8i+qqszum2QuukexF+7wieuaaOtlBNeuZ0/2oi6I2KGOzEnL54w0PKXgQY2AVWgeOQ2S7c+XFjxI0ospE0XVjut/Kn1VSK3cO3sI4W14gb9agaF/XTUegtrpHuPvW4Q3OQbbGHG9J/8/WGQB/HlexDkXh2GaNupC4+vwXb4//P1OV9bMUYPqMH6j2DAs8cSMdfh14utmmwrIWIgoKD3Htiby6XDkNs0EQdzPHeVgE6wbL0hO2oV3VRgcQ2CUxD+Z8j/S/q/mWS+PrfMkVBTPFojdrmxy0fJeZnkqhqK/N5+zkcP2RCwPiy2DQ/NOSrpJFqwxSctse7kbrwESdtT4cUIuofN1UOceRBhk2DoSJgLag9JflYeWez6rBW7GzJEtTLbObkRGWacWNZsyVHZlQFd1rhA2+6Yn42FFJQm9E6Eh+Higd2u7HmSrAVKiqZuwdGLCuUut+QhHIShBN0WBQAZTKtvv8/IQGk84jHy7UZeVrmNFM57AsSLIw3kTcebrRP+vFLYPun/KzbnTP3yrC"""
|
||||
def parts = key.split("\\s+")
|
||||
def keyType = KeyType.fromString(parts[0])
|
||||
|
||||
when:
|
||||
def pubKey = new Buffer.PlainBuffer(Base64.decode(parts[1])).readPublicKey()
|
||||
|
||||
then:
|
||||
KeyType.fromKey(pubKey) == keyType
|
||||
pubKey.getClass() == Certificate.class
|
||||
((Certificate)pubKey).getSignature().length > 0
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.signature
|
||||
|
||||
import com.hierynomus.sshj.common.KeyAlgorithm
|
||||
import spock.lang.Unroll;
|
||||
|
||||
import java.math.BigInteger;
|
||||
@@ -48,7 +47,7 @@ import spock.lang.Specification
|
||||
|
||||
class SignatureDSASpec extends Specification {
|
||||
|
||||
def keyFactory = KeyFactory.getInstance(KeyAlgorithm.DSA)
|
||||
def keyFactory = KeyFactory.getInstance("DSA")
|
||||
|
||||
private PublicKey createPublicKey(final byte[] y, final byte[] p, final byte[] q, final byte[] g) throws Exception {
|
||||
final BigInteger publicKey = new BigInteger(y);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user