├── .editorconfig ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── gradle-wrapper-validation.yaml ├── .gitignore ├── LICENSE.txt ├── README.md ├── build.gradle.kts ├── config ├── checkstyle │ ├── checkstyle.xml │ └── suppressions.xml └── quality.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts ├── spotless.xml.prefs └── src ├── main └── java │ └── com │ └── trilead │ └── ssh2 │ ├── AuthAgentCallback.java │ ├── ChannelCondition.java │ ├── Connection.java │ ├── ConnectionInfo.java │ ├── ConnectionMonitor.java │ ├── DHGexParameters.java │ ├── DebugLogger.java │ ├── DynamicPortForwarder.java │ ├── ExtendedServerHostKeyVerifier.java │ ├── ExtensionInfo.java │ ├── HTTPProxyData.java │ ├── HTTPProxyException.java │ ├── InteractiveCallback.java │ ├── KnownHosts.java │ ├── LocalPortForwarder.java │ ├── LocalStreamForwarder.java │ ├── ProxyData.java │ ├── SCPClient.java │ ├── SFTPException.java │ ├── SFTPv3Client.java │ ├── SFTPv3DirectoryEntry.java │ ├── SFTPv3FileAttributes.java │ ├── SFTPv3FileHandle.java │ ├── ServerHostKeyVerifier.java │ ├── Session.java │ ├── StreamGobbler.java │ ├── auth │ ├── AuthenticationManager.java │ └── SignatureProxy.java │ ├── channel │ ├── AuthAgentForwardThread.java │ ├── Channel.java │ ├── ChannelInputStream.java │ ├── ChannelManager.java │ ├── ChannelOutputStream.java │ ├── DynamicAcceptThread.java │ ├── IChannelWorkerThread.java │ ├── LocalAcceptThread.java │ ├── RemoteAcceptThread.java │ ├── RemoteForwardingData.java │ ├── RemoteX11AcceptThread.java │ ├── StreamForwarder.java │ └── X11ServerData.java │ ├── compression │ ├── CompressionFactory.java │ ├── ICompressor.java │ ├── Zlib.java │ └── ZlibOpenSSH.java │ ├── crypto │ ├── Base64.java │ ├── CryptoWishList.java │ ├── KeyMaterial.java │ ├── PEMDecoder.java │ ├── PEMStructure.java │ ├── SimpleDERReader.java │ ├── cipher │ │ ├── AES.java │ │ ├── BlockCipher.java │ │ ├── BlockCipherFactory.java │ │ ├── BlowFish.java │ │ ├── CBCMode.java │ │ ├── CTRMode.java │ │ ├── CipherInputStream.java │ │ ├── CipherOutputStream.java │ │ ├── DES.java │ │ ├── DESede.java │ │ ├── EtmCipher.java │ │ └── NullCipher.java │ ├── dh │ │ ├── Curve25519Exchange.java │ │ ├── DhExchange.java │ │ ├── DhGroupExchange.java │ │ ├── EcDhExchange.java │ │ └── GenericDhExchange.java │ ├── digest │ │ ├── HMAC.java │ │ ├── HashForSSH2Types.java │ │ ├── MAC.java │ │ └── MACs.java │ └── keys │ │ ├── Ed25519KeyFactory.java │ │ ├── Ed25519KeyPairGenerator.java │ │ ├── Ed25519PrivateKey.java │ │ ├── Ed25519Provider.java │ │ └── Ed25519PublicKey.java │ ├── log │ └── Logger.java │ ├── packets │ ├── PacketChannelAuthAgentReq.java │ ├── PacketChannelOpenConfirmation.java │ ├── PacketChannelOpenFailure.java │ ├── PacketChannelTrileadPing.java │ ├── PacketChannelWindowAdjust.java │ ├── PacketDisconnect.java │ ├── PacketExtInfo.java │ ├── PacketGlobalCancelForwardRequest.java │ ├── PacketGlobalForwardRequest.java │ ├── PacketGlobalTrileadPing.java │ ├── PacketIgnore.java │ ├── PacketKexDHInit.java │ ├── PacketKexDHReply.java │ ├── PacketKexDhGexGroup.java │ ├── PacketKexDhGexInit.java │ ├── PacketKexDhGexReply.java │ ├── PacketKexDhGexRequest.java │ ├── PacketKexDhGexRequestOld.java │ ├── PacketKexInit.java │ ├── PacketNewKeys.java │ ├── PacketOpenDirectTCPIPChannel.java │ ├── PacketOpenSessionChannel.java │ ├── PacketServiceAccept.java │ ├── PacketServiceRequest.java │ ├── PacketSessionExecCommand.java │ ├── PacketSessionPtyRequest.java │ ├── PacketSessionPtyResize.java │ ├── PacketSessionStartShell.java │ ├── PacketSessionSubsystemRequest.java │ ├── PacketSessionX11Request.java │ ├── PacketUserauthBanner.java │ ├── PacketUserauthFailure.java │ ├── PacketUserauthInfoRequest.java │ ├── PacketUserauthInfoResponse.java │ ├── PacketUserauthRequestInteractive.java │ ├── PacketUserauthRequestNone.java │ ├── PacketUserauthRequestPassword.java │ ├── PacketUserauthRequestPublicKey.java │ ├── Packets.java │ ├── TypesReader.java │ └── TypesWriter.java │ ├── sftp │ ├── AttrTextHints.java │ ├── AttribBits.java │ ├── AttribFlags.java │ ├── AttribPermissions.java │ ├── AttribTypes.java │ ├── ErrorCodes.java │ ├── OpenFlags.java │ └── Packet.java │ ├── signature │ ├── DSASHA1Verify.java │ ├── ECDSASHA2Verify.java │ ├── Ed25519Verify.java │ ├── RSASHA1Verify.java │ ├── RSASHA256Verify.java │ ├── RSASHA512Verify.java │ └── SSHSignature.java │ ├── transport │ ├── ClientServerHello.java │ ├── KexManager.java │ ├── KexParameters.java │ ├── KexState.java │ ├── MessageHandler.java │ ├── NegotiateException.java │ ├── NegotiatedParameters.java │ ├── TransportConnection.java │ └── TransportManager.java │ └── util │ ├── TimeoutService.java │ └── Tokenizer.java └── test ├── java └── com │ └── trilead │ └── ssh2 │ ├── AsyncSSHCompatibilityTest.java │ ├── DropbearCompatibilityTest.java │ ├── ExtensionInfoTest.java │ ├── KnownHostsTest.java │ ├── OpenSSHCompatibilityTest.java │ ├── PubkeyConstants.java │ ├── SshLogger.java │ ├── TestExtendedHostKeyVerifier.java │ ├── compression │ └── CompressionFactoryTest.java │ ├── crypto │ ├── PEMDecoderTest.java │ ├── SimpleDERReaderTest.java │ ├── cipher │ │ ├── AESCBCTest.java │ │ ├── AESCTRTest.java │ │ └── AESTest.java │ ├── dh │ │ └── Curve25519ExchangeTest.java │ └── keys │ │ ├── Ed25519KeyFactoryTest.java │ │ ├── Ed25519KeyPairGeneratorTest.java │ │ └── IsValidEdDSAKeyPair.java │ ├── packets │ ├── PacketExtInfoTest.java │ ├── PacketsTest.java │ └── TypesReaderTest.java │ ├── signature │ ├── ECDSASHA2VerifyTest.java │ └── Ed25519VerifyTest.java │ └── transport │ └── KexManagerTest.java └── resources ├── asyncssh-server ├── Dockerfile ├── requirements.txt └── server.py ├── com └── trilead │ └── ssh2 │ ├── crypto │ ├── dsa-openssh2-private-key.txt │ ├── dsa-openssh2-private-key.txt.pub │ ├── dsa-private-key.txt │ ├── ecdsa-nistp256-openssh2-private-key.txt │ ├── ecdsa-nistp256-openssh2-private-key.txt.pub │ ├── ecdsa-nistp256-private-key.txt │ ├── ecdsa-nistp384-openssh2-private-key.txt │ ├── ecdsa-nistp384-openssh2-private-key.txt.pub │ ├── ecdsa-nistp384-private-key.txt │ ├── ecdsa-nistp521-openssh2-private-key.txt │ ├── ecdsa-nistp521-openssh2-private-key.txt.pub │ ├── ecdsa-nistp521-private-key.txt │ ├── ed25519-openssh2-private-key.txt │ ├── ed25519-openssh2-private-key.txt.pub │ ├── rsa-openssh2-private-key.txt │ ├── rsa-openssh2-private-key.txt.pub │ └── rsa-private-key.txt │ └── known_hosts ├── dropbear-server ├── Dockerfile └── run.sh ├── logback-test.xml └── openssh-server ├── Dockerfile └── run.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | 3 | [*] 4 | charset=utf-8 5 | end_of_line=lf 6 | insert_final_newline=true 7 | indent_style=space 8 | indent_size=4 9 | 10 | [*.java] 11 | indent_style=tab 12 | tab_width=4 13 | 14 | [{*.cql,*.ddl,*.sql}] 15 | indent_style=space 16 | indent_size=2 17 | 18 | [{*.yml,*.yaml}] 19 | indent_style=space 20 | indent_size=2 21 | 22 | [*.md] 23 | indent_style=space 24 | indent_size=2 25 | 26 | [gradlew] 27 | indent_style = unset 28 | indent_size = unset 29 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | assignees: 9 | - kruton 10 | - package-ecosystem: docker 11 | directory: "/src/test/resources/asyncssh-server" 12 | schedule: 13 | interval: daily 14 | open-pull-requests-limit: 10 15 | assignees: 16 | - kruton 17 | - package-ecosystem: docker 18 | directory: "/src/test/resources/dropbear-server" 19 | schedule: 20 | interval: daily 21 | open-pull-requests-limit: 10 22 | assignees: 23 | - kruton 24 | - package-ecosystem: docker 25 | directory: "/src/test/resources/openssh-server" 26 | schedule: 27 | interval: daily 28 | open-pull-requests-limit: 10 29 | assignees: 30 | - kruton 31 | - package-ecosystem: "github-actions" 32 | directory: "/" # Location of package manifests 33 | schedule: 34 | interval: "weekly" 35 | open-pull-requests-limit: 10 36 | assignees: 37 | - kruton 38 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: Continuous Integration 5 | 6 | on: 7 | push: 8 | branches: '*' 9 | pull_request: 10 | branches: [ main ] 11 | schedule: 12 | - cron: "0 7 * * *" 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | java: [ 11, 17 ] 20 | 21 | steps: 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | - name: Set up JDK ${{ matrix.java }} 24 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 25 | with: 26 | distribution: 'zulu' 27 | java-version: ${{ matrix.java }} 28 | - name: Cache Gradle Home files 29 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 30 | continue-on-error: true 31 | with: 32 | path: ~/.gradle/caches 33 | key: ${{ runner.os }}-gradle-home-examples-${{matrix.gradle_args}}_check-${{ hashFiles('**/*.gradle') }} 34 | - name: Grant execute permission for gradlew 35 | run: chmod +x gradlew 36 | - name: Build with Gradle 37 | run: ./gradlew build jacocoTestReport --info 38 | - name: Upload to Sonatype 39 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' && matrix.java == '11' 40 | run: | 41 | echo "${{ secrets.MAVEN_GPG_PRIVATE_KEY }}" > ~/.gradle/secring.gpg.b64 42 | base64 -d ~/.gradle/secring.gpg.b64 > ~/.gradle/secring.gpg 43 | ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -PsonatypeUsername=${SONATYPE_USERNAME} -PsonatypePassword=${SONATYPE_PASSWORD} -Psigning.keyId=${GPG_KEYID} -Psigning.secretKeyRingFile=$(echo ~/.gradle/secring.gpg) -Psigning.password=${GPG_PASSWORD} 44 | env: 45 | GPG_KEYID: ${{ secrets.MAVEN_GPG_KEYID }} 46 | GPG_PASSWORD: ${{ secrets.MAVEN_GPG_PASSPHRASE }} 47 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} 48 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} 49 | - name: Upload coverate to CodeClimate 50 | uses: paambaati/codeclimate-action@f429536ee076d758a24705203199548125a28ca7 # v9.0.0 51 | env: 52 | CC_TEST_REPORTER_ID: 9c22853d2ecf28aec51c1b578072031a3a655790cffb9fecfed6101920e5446c 53 | JACOCO_SOURCE_PATH: "${{github.workspace}}/src/main/java" 54 | with: 55 | coverageLocations: ${{github.workspace}}/build/reports/jacoco/test/jacocoTestReport.xml:jacoco 56 | -------------------------------------------------------------------------------- /.github/workflows/gradle-wrapper-validation.yaml: -------------------------------------------------------------------------------- 1 | name: "Validate Gradle Wrapper" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | validation: 13 | name: "Validation" 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 17 | - uses: gradle/actions/wrapper-validation@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle files 2 | .gradle 3 | /local.properties 4 | 5 | # IDEA files 6 | /.idea/ 7 | *.iml 8 | *.ipr 9 | *.iws 10 | 11 | # MacOS X stuff 12 | .DS_Store 13 | 14 | # Build output artifacts 15 | /build 16 | 17 | # Testing files 18 | /captures 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ConnectBot's SSH library 2 | [![Build Status](https://github.com/connectbot/sshlib/actions/workflows/ci.yml/badge.svg)](https://github.com/connectbot/sshlib/actions/workflows/ci.yml) 3 | [![Download](https://img.shields.io/maven-central/v/org.connectbot/sshlib)](https://search.maven.org/artifact/org.connectbot/sshlib) 4 | 5 | This is ConnectBot's SSH library. It started as a continuation of the Trilead SSH2 library, 6 | but has had several features added to it since then. 7 | 8 | This library retains its original [3-Clause BSD license]( 9 | https://opensource.org/licenses/BSD-3-Clause). 10 | 11 | ##### Encryption: 12 | * aes256-ctr ([RFC 4344](https://tools.ietf.org/html/rfc4344#section-4)) 13 | * aes128-ctr ([RFC 4344](https://tools.ietf.org/html/rfc4344#section-4)) 14 | * aes256-cbc ([RFC 4253](https://tools.ietf.org/html/rfc4253#section-6.3)) 15 | * aes128-cbc ([RFC 4253](https://tools.ietf.org/html/rfc4253#section-6.3)) 16 | * blowfish-ctr ([RFC 4344](https://tools.ietf.org/html/rfc4344#section-4)) 17 | * blowfish-cbc ([RFC 4253](https://tools.ietf.org/html/rfc4253#section-6.3)) 18 | * 3des-ctr ([RFC 4344](https://tools.ietf.org/html/rfc4344#section-4)) 19 | * 3des-cbc ([RFC 4253](https://tools.ietf.org/html/rfc4253#section-6.3)) 20 | 21 | ##### MACs: 22 | * hmac-sha2-512-etm@openssh.com ([OpenSSH PROTOCOL]( 23 | https://github.com/openssh/openssh-portable/blob/e1b26ce504662a5d5b991091228984ccfd25f280/PROTOCOL#L54)) 24 | * hmac-sha2-256-etm@openssh.com ([OpenSSH PROTOCOL]( 25 | https://github.com/openssh/openssh-portable/blob/e1b26ce504662a5d5b991091228984ccfd25f280/PROTOCOL#L54)) 26 | * hmac-sha1-etm@openssh.com ([OpenSSH PROTOCOL]( 27 | https://github.com/openssh/openssh-portable/blob/e1b26ce504662a5d5b991091228984ccfd25f280/PROTOCOL#L54)) 28 | * hmac-sha2-512 ([RFC 4868](https://tools.ietf.org/html/rfc4868)) 29 | * hmac-sha2-256 ([RFC 4868](https://tools.ietf.org/html/rfc4868)) 30 | * hmac-sha1 ([RFC 4253](https://tools.ietf.org/html/rfc4253#section-6.4)) 31 | 32 | ##### Key support: 33 | * Ed25519 ([RFC 8709](https://tools.ietf.org/html/rfc8709)) 34 | * ECDSA ([RFC 5656](https://tools.ietf.org/html/rfc5656#section-3)) 35 | * RSA ([RFC 4253](https://tools.ietf.org/html/rfc4253#section-6.6)) 36 | 37 | ##### Key exchange: 38 | * ecdh-sha2-nistp521 ([RFC 5656](https://tools.ietf.org/html/rfc5656#section-4)) 39 | * ecdh-sha2-nistp384 ([RFC 5656](https://tools.ietf.org/html/rfc5656#section-4)) 40 | * ecdh-sha2-nistp256 ([RFC 5656](https://tools.ietf.org/html/rfc5656#section-4)) 41 | * curve25519-sha256 ([RFC 8731](https://tools.ietf.org/html/rfc8731)) 42 | * diffie-hellman-group18-sha512 ([RFC 8268](https://tools.ietf.org/html/rfc8268)) 43 | * diffie-hellman-group16-sha512 ([RFC 8268](https://tools.ietf.org/html/rfc8268)) 44 | * diffie-hellman-group14-sha256 ([RFC 8268](https://tools.ietf.org/html/rfc8268)) 45 | * diffie-hellman-group-exchange-sha256 ([RFC 4419](https://tools.ietf.org/html/rfc4419)) 46 | * diffie-hellman-group-exchange-sha1 ([RFC 4419](https://tools.ietf.org/html/rfc4419)) 47 | * diffie-hellman-group14-sha1 ([RFC 4253](https://tools.ietf.org/html/rfc4253#section-8.1)) 48 | * diffie-hellman-group1-sha1 ([RFC 4253](https://tools.ietf.org/html/rfc4253#section-8.1)) 49 | -------------------------------------------------------------------------------- /config/checkstyle/checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /config/checkstyle/suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 30 | 33 | 34 | 35 | 38 | 41 | 44 | 46 | 47 | -------------------------------------------------------------------------------- /config/quality.gradle.kts: -------------------------------------------------------------------------------- 1 | apply(plugin = "checkstyle") 2 | 3 | configure { 4 | toolVersion = "8.14" 5 | } 6 | 7 | tasks.named("check") { 8 | dependsOn("checkstyle") 9 | } 10 | 11 | tasks.register("checkstyle") { 12 | source = fileTree("src/main/java") 13 | exclude("**/gen/**") 14 | 15 | classpath = files() 16 | } 17 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | #Tue, 06 Nov 2018 18:14:48 +0900 2 | # Project-wide Gradle settings. 3 | 4 | # IDE (e.g. Android Studio) users: 5 | # Gradle settings configured through the IDE *will override* 6 | # any settings specified in this file. 7 | 8 | # For more details on how to configure your build environment visit 9 | # http://www.gradle.org/docs/current/userguide/build_environment.html 10 | 11 | # Specifies the JVM arguments used for the daemon process. 12 | # The setting is particularly useful for tweaking memory settings. 13 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 14 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 15 | 16 | # When configured, Gradle will run in incubating parallel mode. 17 | # This option should only be used with decoupled projects. More details, visit 18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 19 | # org.gradle.parallel=true 20 | 21 | version=2.2.26-SNAPSHOT 22 | group=org.connectbot 23 | description=SSH library used in the ConnectBot app 24 | 25 | bintrayUser=dummyUser 26 | bintrayApiKey=dummyApiKey 27 | 28 | officialJdk=openjdk9 29 | gitHubUrl=https\://github.com/connectbot/sshlib 30 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connectbot/sshlib/9d7dd4ec0c7e94099c280932d7d4be2be5f39566/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "sshlib" 2 | -------------------------------------------------------------------------------- /spotless.xml.prefs: -------------------------------------------------------------------------------- 1 | formatCommentText=false 2 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/AuthAgentCallback.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import java.security.KeyPair; 4 | import java.util.Map; 5 | 6 | /** 7 | * AuthAgentCallback. 8 | * 9 | * @author Kenny Root 10 | * @version $Id$ 11 | */ 12 | public interface AuthAgentCallback { 13 | 14 | /** 15 | * @return array of blobs containing the OpenSSH-format encoded public keys 16 | */ 17 | Map retrieveIdentities(); 18 | 19 | /** 20 | * @param pair A RSAPrivateKey, ECPrivateKey, or 21 | * DSAPrivateKey containing a DSA, EC, or RSA private 22 | * and corresponding PublicKey. 23 | * @param comment comment associated with this key 24 | * @param confirmUse whether to prompt before using this key 25 | * @param lifetime lifetime in seconds for key to be remembered 26 | * @return success or failure 27 | */ 28 | boolean addIdentity(KeyPair pair, String comment, boolean confirmUse, int lifetime); 29 | 30 | /** 31 | * @param publicKey byte blob containing the OpenSSH-format encoded public key 32 | * @return success or failure 33 | */ 34 | boolean removeIdentity(byte[] publicKey); 35 | 36 | /** 37 | * @return success or failure 38 | */ 39 | boolean removeAllIdentities(); 40 | 41 | /** 42 | * @param publicKey byte blob containing the OpenSSH-format encoded public key 43 | * @return A RSAPrivateKey or DSAPrivateKey 44 | * containing a DSA or RSA private key of 45 | * the user in Trilead object format. 46 | */ 47 | KeyPair getKeyPair(byte[] publicKey); 48 | 49 | /** 50 | * @return 51 | */ 52 | boolean isAgentLocked(); 53 | 54 | /** 55 | * @param lockPassphrase 56 | */ 57 | boolean setAgentLock(String lockPassphrase); 58 | 59 | /** 60 | * @param unlockPassphrase 61 | * @return 62 | */ 63 | boolean requestAgentUnlock(String unlockPassphrase); 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/ChannelCondition.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * Contains constants that can be used to specify what conditions to wait for on 6 | * a SSH-2 channel (e.g., represented by a {@link Session}). 7 | * 8 | * @see Session#waitForCondition(int, long) 9 | * 10 | * @author Christian Plattner, plattner@trilead.com 11 | * @version $Id: ChannelCondition.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 12 | */ 13 | 14 | public interface ChannelCondition 15 | { 16 | /** 17 | * A timeout has occurred, none of your requested conditions is fulfilled. 18 | * However, other conditions may be true - therefore, NEVER use the "==" 19 | * operator to test for this (or any other) condition. Always use 20 | * something like ((cond & ChannelCondition.CLOSED) != 0). 21 | */ 22 | int TIMEOUT = 1; 23 | 24 | /** 25 | * The underlying SSH-2 channel, however not necessarily the whole connection, 26 | * has been closed. This implies EOF. Note that there may still 27 | * be unread stdout or stderr data in the local window, i.e, STDOUT_DATA 28 | * or/and STDERR_DATA may be set at the same time. 29 | */ 30 | int CLOSED = 2; 31 | 32 | /** 33 | * There is stdout data available that is ready to be consumed. 34 | */ 35 | int STDOUT_DATA = 4; 36 | 37 | /** 38 | * There is stderr data available that is ready to be consumed. 39 | */ 40 | int STDERR_DATA = 8; 41 | 42 | /** 43 | * EOF on has been reached, no more _new_ stdout or stderr data will arrive 44 | * from the remote server. However, there may be unread stdout or stderr 45 | * data, i.e, STDOUT_DATA or/and STDERR_DATA 46 | * may be set at the same time. 47 | */ 48 | int EOF = 16; 49 | 50 | /** 51 | * The exit status of the remote process is available. 52 | * Some servers never send the exist status, or occasionally "forget" to do so. 53 | */ 54 | int EXIT_STATUS = 32; 55 | 56 | /** 57 | * The exit signal of the remote process is available. 58 | */ 59 | int EXIT_SIGNAL = 64; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/ConnectionInfo.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * In most cases you probably do not need the information contained in here. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: ConnectionInfo.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | public class ConnectionInfo 11 | { 12 | /** 13 | * The used key exchange (KEX) algorithm in the latest key exchange. 14 | */ 15 | public String keyExchangeAlgorithm; 16 | 17 | /** 18 | * The currently used crypto algorithm for packets from to the client to the 19 | * server. 20 | */ 21 | public String clientToServerCryptoAlgorithm; 22 | /** 23 | * The currently used crypto algorithm for packets from to the server to the 24 | * client. 25 | */ 26 | public String serverToClientCryptoAlgorithm; 27 | 28 | /** 29 | * The currently used MAC algorithm for packets from to the client to the 30 | * server. 31 | */ 32 | public String clientToServerMACAlgorithm; 33 | /** 34 | * The currently used MAC algorithm for packets from to the server to the 35 | * client. 36 | */ 37 | public String serverToClientMACAlgorithm; 38 | 39 | /** 40 | * The type of the server host key (currently either "ssh-dss" or 41 | * "ssh-rsa"). 42 | */ 43 | public String serverHostKeyAlgorithm; 44 | /** 45 | * The server host key that was sent during the latest key exchange. 46 | */ 47 | public byte[] serverHostKey; 48 | 49 | /** 50 | * Number of kex exchanges performed on this connection so far. 51 | */ 52 | public int keyExchangeCounter = 0; 53 | 54 | /** 55 | * The currently used compression algorithm for packets from the client to 56 | * the server. 57 | */ 58 | public String clientToServerCompressionAlgorithm; 59 | 60 | /** 61 | * The currently used compression algorithm for packets from the server to 62 | * the client. 63 | */ 64 | public String serverToClientCompressionAlgorithm; 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/ConnectionMonitor.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * A ConnectionMonitor is used to get notified when the 6 | * underlying socket of a connection is closed. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: ConnectionMonitor.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 10 | */ 11 | 12 | public interface ConnectionMonitor 13 | { 14 | /** 15 | * This method is called after the connection's underlying 16 | * socket has been closed. E.g., due to the {@link Connection#close()} request of the 17 | * user, if the peer closed the connection, due to a fatal error during connect() 18 | * (also if the socket cannot be established) or if a fatal error occured on 19 | * an established connection. 20 | *

21 | * This is an experimental feature. 22 | *

23 | * You MUST NOT make any assumption about the thread that invokes this method. 24 | *

25 | * Please note: if the connection is not connected (e.g., there was no successful 26 | * connect() call), then the invocation of {@link Connection#close()} will NOT trigger 27 | * this method. 28 | * 29 | * @see Connection#addConnectionMonitor(ConnectionMonitor) 30 | * 31 | * @param reason Includes an indication why the socket was closed. 32 | */ 33 | void connectionLost(Throwable reason); 34 | } -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/DebugLogger.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | /** 4 | * An interface which needs to be implemented if you 5 | * want to capture debugging messages. 6 | * 7 | * @see Connection#enableDebugging(boolean, DebugLogger) 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: DebugLogger.java,v 1.1 2008/03/03 07:01:36 cplattne Exp $ 11 | */ 12 | public interface DebugLogger 13 | { 14 | 15 | /** 16 | * Log a debug message. 17 | * 18 | * @param level 0-99, 99 is a the most verbose level 19 | * @param className the class that generated the message 20 | * @param message the debug message 21 | */ 22 | void log(int level, String className, String message); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/DynamicPortForwarder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007 Kenny Root, Jeffrey Sharkey 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * a.) Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * b.) Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * c.) Neither the name of Trilead nor the names of its contributors may 14 | * be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | package com.trilead.ssh2; 31 | 32 | import java.io.IOException; 33 | import java.net.InetSocketAddress; 34 | 35 | import com.trilead.ssh2.channel.ChannelManager; 36 | import com.trilead.ssh2.channel.DynamicAcceptThread; 37 | 38 | /** 39 | * A DynamicPortForwarder forwards TCP/IP connections to a local 40 | * port via the secure tunnel to another host which is selected via the 41 | * SOCKS protocol. Checkout {@link Connection#createDynamicPortForwarder(int)} 42 | * on how to create one. 43 | * 44 | * @author Kenny Root 45 | * @version $Id: $ 46 | */ 47 | public class DynamicPortForwarder { 48 | ChannelManager cm; 49 | 50 | DynamicAcceptThread dat; 51 | 52 | DynamicPortForwarder(ChannelManager cm, int local_port) 53 | throws IOException 54 | { 55 | this.cm = cm; 56 | 57 | dat = new DynamicAcceptThread(cm, local_port); 58 | dat.setDaemon(true); 59 | dat.start(); 60 | } 61 | 62 | DynamicPortForwarder(ChannelManager cm, InetSocketAddress addr) throws IOException { 63 | this.cm = cm; 64 | 65 | dat = new DynamicAcceptThread(cm, addr); 66 | dat.setDaemon(true); 67 | dat.start(); 68 | } 69 | 70 | /** 71 | * Stop TCP/IP forwarding of newly arriving connections. 72 | * 73 | */ 74 | public void close() { 75 | dat.stopWorking(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/ExtendedServerHostKeyVerifier.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * This extends the {@link ServerHostKeyVerifier} interface by allowing the remote server to indicate it has multiple 7 | * server key algorithms available. After authentication, the {@link #getKnownKeyAlgorithmsForHost(String, int)} method 8 | * may be called and compared against the list of server-controller keys. If a key algorithm has been added then 9 | * {@link #addServerHostKey(String, int, String, byte[])} will be called. If a key algorithm has been removed, then 10 | * {@link #removeServerHostKey(String, int, String, byte[])} will be called. 11 | * 12 | * @author Kenny Root 13 | */ 14 | public abstract class ExtendedServerHostKeyVerifier implements ServerHostKeyVerifier { 15 | /** 16 | * Called during connection to determine which keys are known for this host. 17 | * 18 | * @param hostname the hostname used to create the {@link Connection} object 19 | * @param port the server's remote TCP port 20 | * @return list of hostkey algorithms for the given hostname and port combination 21 | * or {@code null} if none are known. 22 | */ 23 | public abstract List getKnownKeyAlgorithmsForHost(String hostname, int port); 24 | 25 | /** 26 | * After authentication, if the server indicates it no longer uses this key, this method will be called 27 | * for the app to remove its record of it. 28 | * 29 | * @param hostname the hostname used to create the {@link Connection} object 30 | * @param port the server's remote TCP port 31 | * @param serverHostKeyAlgorithm key algorithm of removed key 32 | * @param serverHostKey key data of removed key 33 | */ 34 | public abstract void removeServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, 35 | byte[] serverHostKey); 36 | 37 | /** 38 | * After authentication, if the server indicates it has another keyAlgorithm, this method will be 39 | * called for the app to add it to its record of known keys for this hostname. 40 | * 41 | * @param hostname the hostname used to create the {@link Connection} object 42 | * @param port the server's remote TCP port 43 | * @param keyAlgorithm SSH standard name for the key to be added 44 | * @param serverHostKey SSH encoding of the key data for the key to be added 45 | */ 46 | public abstract void addServerHostKey(String hostname, int port, String keyAlgorithm, byte[] serverHostKey); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/ExtensionInfo.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import com.trilead.ssh2.packets.PacketExtInfo; 4 | import java.util.Collections; 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | /** 9 | * SSH extensions reported by the server 10 | * 11 | * https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info-15 12 | */ 13 | public class ExtensionInfo 14 | { 15 | private final Set signatureAlgorithmsAccepted; 16 | 17 | /** 18 | * @return Signature algorithms that server will accept. If empty, this extension was absent. 19 | */ 20 | public Set getSignatureAlgorithmsAccepted() 21 | { 22 | return signatureAlgorithmsAccepted; 23 | } 24 | 25 | public static ExtensionInfo fromPacketExtInfo(PacketExtInfo packetExtInfo) 26 | { 27 | String rawAlgs = packetExtInfo.getExtNameToValue().get("server-sig-algs"); 28 | if (rawAlgs == null) 29 | { 30 | return new ExtensionInfo(Collections.emptySet()); 31 | } 32 | 33 | Set algsSet = new HashSet<>(); 34 | Collections.addAll(algsSet, rawAlgs.split(",")); 35 | return new ExtensionInfo(algsSet); 36 | } 37 | 38 | public static ExtensionInfo noExtInfoSeen() 39 | { 40 | return new ExtensionInfo(Collections.emptySet()); 41 | } 42 | 43 | private ExtensionInfo(Set signatureAlgorithmsAccepted) 44 | { 45 | this.signatureAlgorithmsAccepted = Collections.unmodifiableSet(signatureAlgorithmsAccepted); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/HTTPProxyException.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * May be thrown upon connect() if a HTTP proxy is being used. 8 | * 9 | * @see Connection#connect() 10 | * @see Connection#setProxyData(ProxyData) 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: HTTPProxyException.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 14 | */ 15 | 16 | public class HTTPProxyException extends IOException 17 | { 18 | private static final long serialVersionUID = 2241537397104426186L; 19 | 20 | public final String httpResponse; 21 | public final int httpErrorCode; 22 | 23 | public HTTPProxyException(String httpResponse, int httpErrorCode) 24 | { 25 | super("HTTP Proxy Error (" + httpErrorCode + " " + httpResponse + ")"); 26 | this.httpResponse = httpResponse; 27 | this.httpErrorCode = httpErrorCode; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/InteractiveCallback.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * An InteractiveCallback is used to respond to challenges sent 6 | * by the server if authentication mode "keyboard-interactive" is selected. 7 | * 8 | * @see Connection#authenticateWithKeyboardInteractive(String, 9 | * String[], InteractiveCallback) 10 | * 11 | * @author Christian Plattner, plattner@trilead.com 12 | * @version $Id: InteractiveCallback.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 13 | */ 14 | 15 | public interface InteractiveCallback 16 | { 17 | /** 18 | * This callback interface is used during a "keyboard-interactive" 19 | * authentication. Every time the server sends a set of challenges (however, 20 | * most often just one challenge at a time), this callback function will be 21 | * called to give your application a chance to talk to the user and to 22 | * determine the response(s). 23 | *

24 | * Some copy-paste information from the standard: a command line interface 25 | * (CLI) client SHOULD print the name and instruction (if non-empty), adding 26 | * newlines. Then for each prompt in turn, the client SHOULD display the 27 | * prompt and read the user input. The name and instruction fields MAY be 28 | * empty strings, the client MUST be prepared to handle this correctly. The 29 | * prompt field(s) MUST NOT be empty strings. 30 | *

31 | * Please refer to draft-ietf-secsh-auth-kbdinteract-XX.txt for the details. 32 | *

33 | * Note: clients SHOULD use control character filtering as discussed in 34 | * RFC4251 to avoid attacks by including 35 | * terminal control characters in the fields to be displayed. 36 | * 37 | * @param name 38 | * the name String sent by the server. 39 | * @param instruction 40 | * the instruction String sent by the server. 41 | * @param numPrompts 42 | * number of prompts - may be zero (in this case, you should just 43 | * return a String array of length zero). 44 | * @param prompt 45 | * an array (length numPrompts) of Strings 46 | * @param echo 47 | * an array (length numPrompts) of booleans. For 48 | * each prompt, the corresponding echo field indicates whether or 49 | * not the user input should be echoed as characters are typed. 50 | * @return an array of reponses - the array size must match the parameter 51 | * numPrompts. 52 | */ 53 | String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) 54 | throws Exception; 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/LocalPortForwarder.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | import java.io.IOException; 5 | import java.net.InetSocketAddress; 6 | 7 | import com.trilead.ssh2.channel.ChannelManager; 8 | import com.trilead.ssh2.channel.LocalAcceptThread; 9 | 10 | 11 | /** 12 | * A LocalPortForwarder forwards TCP/IP connections to a local 13 | * port via the secure tunnel to another host (which may or may not be identical 14 | * to the remote SSH-2 server). Checkout {@link Connection#createLocalPortForwarder(int, String, int)} 15 | * on how to create one. 16 | * 17 | * @author Christian Plattner, plattner@trilead.com 18 | * @version $Id: LocalPortForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 19 | */ 20 | public class LocalPortForwarder 21 | { 22 | ChannelManager cm; 23 | 24 | String host_to_connect; 25 | 26 | int port_to_connect; 27 | 28 | LocalAcceptThread lat; 29 | 30 | LocalPortForwarder(ChannelManager cm, int local_port, String host_to_connect, int port_to_connect) 31 | throws IOException 32 | { 33 | this.cm = cm; 34 | this.host_to_connect = host_to_connect; 35 | this.port_to_connect = port_to_connect; 36 | 37 | lat = new LocalAcceptThread(cm, local_port, host_to_connect, port_to_connect); 38 | lat.setDaemon(true); 39 | lat.start(); 40 | } 41 | 42 | LocalPortForwarder(ChannelManager cm, InetSocketAddress addr, String host_to_connect, int port_to_connect) 43 | throws IOException 44 | { 45 | this.cm = cm; 46 | this.host_to_connect = host_to_connect; 47 | this.port_to_connect = port_to_connect; 48 | 49 | lat = new LocalAcceptThread(cm, addr, host_to_connect, port_to_connect); 50 | lat.setDaemon(true); 51 | lat.start(); 52 | } 53 | 54 | /** 55 | * Stop TCP/IP forwarding of newly arriving connections. 56 | * 57 | */ 58 | public void close() { 59 | lat.stopWorking(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/LocalStreamForwarder.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | import com.trilead.ssh2.channel.Channel; 9 | import com.trilead.ssh2.channel.ChannelManager; 10 | import com.trilead.ssh2.channel.LocalAcceptThread; 11 | 12 | 13 | /** 14 | * A LocalStreamForwarder forwards an Input- and Outputstream 15 | * pair via the secure tunnel to another host (which may or may not be identical 16 | * to the remote SSH-2 server). 17 | * 18 | * @author Christian Plattner, plattner@trilead.com 19 | * @version $Id: LocalStreamForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 20 | */ 21 | public class LocalStreamForwarder 22 | { 23 | ChannelManager cm; 24 | 25 | String host_to_connect; 26 | int port_to_connect; 27 | LocalAcceptThread lat; 28 | 29 | Channel cn; 30 | 31 | LocalStreamForwarder(ChannelManager cm, String host_to_connect, int port_to_connect) throws IOException 32 | { 33 | this.cm = cm; 34 | this.host_to_connect = host_to_connect; 35 | this.port_to_connect = port_to_connect; 36 | 37 | cn = cm.openDirectTCPIPChannel(host_to_connect, port_to_connect, "127.0.0.1", 0); 38 | } 39 | 40 | /** 41 | * @return An InputStream object. 42 | */ 43 | public InputStream getInputStream() { 44 | return cn.getStdoutStream(); 45 | } 46 | 47 | /** 48 | * Get the OutputStream. Please be aware that the implementation MAY use an 49 | * internal buffer. To make sure that the buffered data is sent over the 50 | * tunnel, you have to call the flush method of the 51 | * OutputStream. To signal EOF, please use the 52 | * close method of the OutputStream. 53 | * 54 | * @return An OutputStream object. 55 | */ 56 | public OutputStream getOutputStream() { 57 | return cn.getStdinStream(); 58 | } 59 | 60 | /** 61 | * Close the underlying SSH forwarding channel and free up resources. 62 | * You can also use this method to force the shutdown of the underlying 63 | * forwarding channel. Pending output (OutputStream not flushed) will NOT 64 | * be sent. Pending input (InputStream) can still be read. If the shutdown 65 | * operation is already in progress (initiated from either side), then this 66 | * call is a no-op. 67 | * 68 | * @throws IOException 69 | */ 70 | public void close() throws IOException 71 | { 72 | cm.closeChannel(cn, "Closed due to user request.", true); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/ProxyData.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | import java.io.IOException; 5 | import java.net.Socket; 6 | 7 | /** 8 | * An abstract interface implemented by all proxy data implementations. 9 | * 10 | * @see HTTPProxyData 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: ProxyData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 14 | */ 15 | 16 | public interface ProxyData 17 | { 18 | /** 19 | * Connects the socket to the given destination using the proxy method that this instance 20 | * represents. 21 | * @param hostname hostname of end host (not proxy) 22 | * @param port port of end host (not proxy) 23 | * @param connectTimeout number of seconds before giving up on connecting to end host 24 | * @throws IOException if the connection could not be completed 25 | * @return connected socket instance 26 | */ 27 | Socket openConnection(String hostname, int port, int connectTimeout) throws IOException; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/SFTPException.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | import java.io.IOException; 5 | 6 | import com.trilead.ssh2.sftp.ErrorCodes; 7 | 8 | 9 | /** 10 | * Used in combination with the SFTPv3Client. This exception wraps 11 | * error messages sent by the SFTP server. 12 | * 13 | * @author Christian Plattner, plattner@trilead.com 14 | * @version $Id: SFTPException.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 15 | */ 16 | 17 | public class SFTPException extends IOException 18 | { 19 | private static final long serialVersionUID = 578654644222421811L; 20 | 21 | private final String sftpErrorMessage; 22 | private final int sftpErrorCode; 23 | 24 | private static String constructMessage(String s, int errorCode) 25 | { 26 | String[] detail = ErrorCodes.getDescription(errorCode); 27 | 28 | if (detail == null) 29 | return s + " (UNKNOW SFTP ERROR CODE)"; 30 | 31 | return s + " (" + detail[0] + ": " + detail[1] + ")"; 32 | } 33 | 34 | SFTPException(String msg, int errorCode) 35 | { 36 | super(constructMessage(msg, errorCode)); 37 | sftpErrorMessage = msg; 38 | sftpErrorCode = errorCode; 39 | } 40 | 41 | /** 42 | * Get the error message sent by the server. Often, this 43 | * message does not help a lot (e.g., "failure"). 44 | * 45 | * @return the plain string as sent by the server. 46 | */ 47 | public String getServerErrorMessage() 48 | { 49 | return sftpErrorMessage; 50 | } 51 | 52 | /** 53 | * Get the error code sent by the server. 54 | * 55 | * @return an error code as defined in the SFTP specs. 56 | */ 57 | public int getServerErrorCode() 58 | { 59 | return sftpErrorCode; 60 | } 61 | 62 | /** 63 | * Get the symbolic name of the error code as given in the SFTP specs. 64 | * 65 | * @return e.g., "SSH_FX_INVALID_FILENAME". 66 | */ 67 | public String getServerErrorCodeSymbol() 68 | { 69 | String[] detail = ErrorCodes.getDescription(sftpErrorCode); 70 | 71 | if (detail == null) 72 | return "UNKNOW SFTP ERROR CODE " + sftpErrorCode; 73 | 74 | return detail[0]; 75 | } 76 | 77 | /** 78 | * Get the description of the error code as given in the SFTP specs. 79 | * 80 | * @return e.g., "The filename is not valid." 81 | */ 82 | public String getServerErrorCodeVerbose() 83 | { 84 | String[] detail = ErrorCodes.getDescription(sftpErrorCode); 85 | 86 | if (detail == null) 87 | return "The error code " + sftpErrorCode + " is unknown."; 88 | 89 | return detail[1]; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/SFTPv3DirectoryEntry.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * A SFTPv3DirectoryEntry as returned by {@link SFTPv3Client#ls(String)}. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: SFTPv3DirectoryEntry.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | 11 | public class SFTPv3DirectoryEntry 12 | { 13 | /** 14 | * A relative name within the directory, without any path components. 15 | */ 16 | public String filename; 17 | 18 | /** 19 | * An expanded format for the file name, similar to what is returned by 20 | * "ls -l" on Un*x systems. 21 | *

22 | * The format of this field is unspecified by the SFTP v3 protocol. 23 | * It MUST be suitable for use in the output of a directory listing 24 | * command (in fact, the recommended operation for a directory listing 25 | * command is to simply display this data). However, clients SHOULD NOT 26 | * attempt to parse the longname field for file attributes; they SHOULD 27 | * use the attrs field instead. 28 | *

29 | * The recommended format for the longname field is as follows:
30 | * -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer 31 | */ 32 | public String longEntry; 33 | 34 | /** 35 | * The attributes of this entry. 36 | */ 37 | public SFTPv3FileAttributes attributes; 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/SFTPv3FileHandle.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * A SFTPv3FileHandle. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: SFTPv3FileHandle.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | 11 | public class SFTPv3FileHandle 12 | { 13 | final SFTPv3Client client; 14 | final byte[] fileHandle; 15 | boolean isClosed = false; 16 | 17 | /* The constructor is NOT public */ 18 | 19 | SFTPv3FileHandle(SFTPv3Client client, byte[] h) 20 | { 21 | this.client = client; 22 | this.fileHandle = h; 23 | } 24 | 25 | /** 26 | * Get the SFTPv3Client instance which created this handle. 27 | * 28 | * @return A SFTPv3Client instance. 29 | */ 30 | public SFTPv3Client getClient() 31 | { 32 | return client; 33 | } 34 | 35 | /** 36 | * Check if this handle was closed with the {@link SFTPv3Client#closeFile(SFTPv3FileHandle)} method 37 | * of the SFTPv3Client instance which created the handle. 38 | * 39 | * @return if the handle is closed. 40 | */ 41 | public boolean isClosed() 42 | { 43 | return isClosed; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/ServerHostKeyVerifier.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * A callback interface used to implement a client specific method of checking 6 | * server host keys. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: ServerHostKeyVerifier.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 10 | */ 11 | 12 | public interface ServerHostKeyVerifier 13 | { 14 | /** 15 | * The actual verifier method, it will be called by the key exchange code 16 | * on EVERY key exchange - this can happen several times during the lifetime 17 | * of a connection. 18 | *

19 | * Note: SSH-2 servers are allowed to change their hostkey at ANY time. 20 | * 21 | * @param hostname the hostname used to create the {@link Connection} object 22 | * @param port the remote TCP port 23 | * @param serverHostKeyAlgorithm the public key algorithm (ssh-rsa or ssh-dss) 24 | * @param serverHostKey the server's public key blob 25 | * @return if the client wants to accept the server's host key - if not, the 26 | * connection will be closed. 27 | * @throws Exception Will be wrapped with an IOException, extended version of returning false =) 28 | */ 29 | boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey) 30 | throws Exception; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/auth/SignatureProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Jonas Dippel, Michael Perk, Marc Totzke 3 | */ 4 | 5 | package com.trilead.ssh2.auth; 6 | 7 | import java.io.IOException; 8 | import java.security.PublicKey; 9 | 10 | public abstract class SignatureProxy 11 | { 12 | public static final String SHA1 = "SHA-1"; 13 | public static final String SHA256 = "SHA-256"; 14 | public static final String SHA384 = "SHA-384"; 15 | public static final String SHA512 = "SHA-512"; 16 | 17 | /** 18 | * Holds the public key which belongs to the private key which is used in the signing process. 19 | */ 20 | private PublicKey mPublicKey; 21 | 22 | /** 23 | * Instantiates a new SignatureProxy which needs a public key for the 24 | * later authentication process. 25 | * 26 | * @param publicKey The public key. 27 | * @throws IllegalArgumentException Might be thrown id the public key is invalid. 28 | */ 29 | public SignatureProxy(PublicKey publicKey) 30 | { 31 | if (publicKey == null) 32 | { 33 | throw new IllegalArgumentException("Public key must not be null"); 34 | } 35 | mPublicKey = publicKey; 36 | } 37 | 38 | /** 39 | * This method should sign a given byte array message using the private key. 40 | * 41 | * @param message The message which should be signed. 42 | * @param hashAlgorithm The hashing algorithm which should be used. 43 | * @return The signed message. 44 | * @throws IOException This exception might be thrown during the signing process. 45 | */ 46 | public abstract byte[] sign(byte[] message, String hashAlgorithm) throws IOException; 47 | 48 | public PublicKey getPublicKey() 49 | { 50 | return mPublicKey; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/channel/ChannelInputStream.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | /** 8 | * ChannelInputStream. 9 | * 10 | * @author Christian Plattner, plattner@trilead.com 11 | * @version $Id: ChannelInputStream.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 12 | */ 13 | public final class ChannelInputStream extends InputStream 14 | { 15 | Channel c; 16 | 17 | boolean isClosed = false; 18 | boolean isEOF = false; 19 | boolean extendedFlag = false; 20 | 21 | ChannelInputStream(Channel c, boolean isExtended) 22 | { 23 | this.c = c; 24 | this.extendedFlag = isExtended; 25 | } 26 | 27 | public int available() throws IOException 28 | { 29 | if (isEOF) 30 | return 0; 31 | 32 | int avail = c.cm.getAvailable(c, extendedFlag); 33 | 34 | /* We must not return -1 on EOF */ 35 | 36 | return (avail > 0) ? avail : 0; 37 | } 38 | 39 | public void close() { 40 | isClosed = true; 41 | } 42 | 43 | public int read(byte[] b, int off, int len) throws IOException 44 | { 45 | if (b == null) 46 | throw new NullPointerException(); 47 | 48 | if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) 49 | throw new IndexOutOfBoundsException(); 50 | 51 | if (len == 0) 52 | return 0; 53 | 54 | if (isEOF) 55 | return -1; 56 | 57 | int ret = c.cm.getChannelData(c, extendedFlag, b, off, len); 58 | 59 | if (ret == -1) 60 | { 61 | isEOF = true; 62 | } 63 | 64 | return ret; 65 | } 66 | 67 | public int read(byte[] b) throws IOException 68 | { 69 | return read(b, 0, b.length); 70 | } 71 | 72 | public int read() throws IOException 73 | { 74 | /* Yes, this stream is pure and unbuffered, a single byte read() is slow */ 75 | 76 | final byte b[] = new byte[1]; 77 | 78 | int ret = read(b, 0, 1); 79 | 80 | if (ret != 1) 81 | return -1; 82 | 83 | return b[0] & 0xff; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/channel/ChannelOutputStream.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.channel; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | /** 7 | * ChannelOutputStream. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: ChannelOutputStream.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 11 | */ 12 | public final class ChannelOutputStream extends OutputStream 13 | { 14 | Channel c; 15 | 16 | private byte[] writeBuffer; 17 | 18 | boolean isClosed = false; 19 | 20 | ChannelOutputStream(Channel c) 21 | { 22 | this.c = c; 23 | writeBuffer = new byte[1]; 24 | } 25 | 26 | public void write(int b) throws IOException 27 | { 28 | writeBuffer[0] = (byte) b; 29 | 30 | write(writeBuffer, 0, 1); 31 | } 32 | 33 | public void close() throws IOException 34 | { 35 | if (!isClosed) 36 | { 37 | isClosed = true; 38 | c.cm.sendEOF(c); 39 | } 40 | } 41 | 42 | public void flush() throws IOException 43 | { 44 | if (isClosed) 45 | throw new IOException("This OutputStream is closed."); 46 | 47 | /* This is a no-op, since this stream is unbuffered */ 48 | } 49 | 50 | public void write(byte[] b, int off, int len) throws IOException 51 | { 52 | if (isClosed) 53 | throw new IOException("This OutputStream is closed."); 54 | 55 | if (b == null) 56 | throw new NullPointerException(); 57 | 58 | if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) 59 | throw new IndexOutOfBoundsException(); 60 | 61 | if (len == 0) 62 | return; 63 | 64 | c.cm.sendData(c, b, off, len); 65 | } 66 | 67 | public void write(byte[] b) throws IOException 68 | { 69 | write(b, 0, b.length); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/channel/IChannelWorkerThread.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | /** 5 | * IChannelWorkerThread. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: IChannelWorkerThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | interface IChannelWorkerThread 11 | { 12 | void stopWorking(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/channel/LocalAcceptThread.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | import java.io.IOException; 5 | import java.net.InetSocketAddress; 6 | import java.net.ServerSocket; 7 | import java.net.Socket; 8 | 9 | /** 10 | * LocalAcceptThread. 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: LocalAcceptThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 14 | */ 15 | public class LocalAcceptThread extends Thread implements IChannelWorkerThread 16 | { 17 | ChannelManager cm; 18 | String host_to_connect; 19 | int port_to_connect; 20 | 21 | final ServerSocket ss; 22 | 23 | public LocalAcceptThread(ChannelManager cm, int local_port, String host_to_connect, int port_to_connect) 24 | throws IOException 25 | { 26 | this.cm = cm; 27 | this.host_to_connect = host_to_connect; 28 | this.port_to_connect = port_to_connect; 29 | 30 | ss = new ServerSocket(local_port); 31 | } 32 | 33 | public LocalAcceptThread(ChannelManager cm, InetSocketAddress localAddress, String host_to_connect, 34 | int port_to_connect) throws IOException 35 | { 36 | this.cm = cm; 37 | this.host_to_connect = host_to_connect; 38 | this.port_to_connect = port_to_connect; 39 | 40 | ss = new ServerSocket(); 41 | ss.bind(localAddress); 42 | } 43 | 44 | public void run() 45 | { 46 | try 47 | { 48 | cm.registerThread(this); 49 | } 50 | catch (IOException e) 51 | { 52 | stopWorking(); 53 | return; 54 | } 55 | 56 | while (true) 57 | { 58 | Socket s = null; 59 | 60 | try 61 | { 62 | s = ss.accept(); 63 | } 64 | catch (IOException e) 65 | { 66 | stopWorking(); 67 | return; 68 | } 69 | 70 | Channel cn = null; 71 | StreamForwarder r2l = null; 72 | StreamForwarder l2r = null; 73 | 74 | try 75 | { 76 | /* This may fail, e.g., if the remote port is closed (in optimistic terms: not open yet) */ 77 | 78 | cn = cm.openDirectTCPIPChannel(host_to_connect, port_to_connect, s.getInetAddress().getHostAddress(), s 79 | .getPort()); 80 | 81 | } 82 | catch (IOException e) 83 | { 84 | /* Simply close the local socket and wait for the next incoming connection */ 85 | 86 | try 87 | { 88 | s.close(); 89 | } 90 | catch (IOException ignore) 91 | { 92 | } 93 | 94 | continue; 95 | } 96 | 97 | try 98 | { 99 | r2l = new StreamForwarder(cn, null, s, cn.stdoutStream, s.getOutputStream(), "RemoteToLocal"); 100 | l2r = new StreamForwarder(cn, r2l, s, s.getInputStream(), cn.stdinStream, "LocalToRemote"); 101 | } 102 | catch (IOException e) 103 | { 104 | try 105 | { 106 | /* This message is only visible during debugging, since we discard the channel immediatelly */ 107 | cn.cm.closeChannel(cn, "Weird error during creation of StreamForwarder (" + e.getMessage() + ")", 108 | true); 109 | } 110 | catch (IOException ignore) 111 | { 112 | } 113 | 114 | continue; 115 | } 116 | 117 | r2l.setDaemon(true); 118 | l2r.setDaemon(true); 119 | r2l.start(); 120 | l2r.start(); 121 | } 122 | } 123 | 124 | public void stopWorking() 125 | { 126 | try 127 | { 128 | /* This will lead to an IOException in the ss.accept() call */ 129 | ss.close(); 130 | } 131 | catch (IOException e) 132 | { 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/channel/RemoteAcceptThread.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | import java.io.IOException; 5 | import java.net.Socket; 6 | 7 | import com.trilead.ssh2.log.Logger; 8 | 9 | 10 | /** 11 | * RemoteAcceptThread. 12 | * 13 | * @author Christian Plattner, plattner@trilead.com 14 | * @version $Id: RemoteAcceptThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 15 | */ 16 | public class RemoteAcceptThread extends Thread 17 | { 18 | private static final Logger log = Logger.getLogger(RemoteAcceptThread.class); 19 | 20 | Channel c; 21 | 22 | String remoteConnectedAddress; 23 | int remoteConnectedPort; 24 | String remoteOriginatorAddress; 25 | int remoteOriginatorPort; 26 | String targetAddress; 27 | int targetPort; 28 | 29 | Socket s; 30 | 31 | public RemoteAcceptThread(Channel c, String remoteConnectedAddress, int remoteConnectedPort, 32 | String remoteOriginatorAddress, int remoteOriginatorPort, String targetAddress, int targetPort) 33 | { 34 | this.c = c; 35 | this.remoteConnectedAddress = remoteConnectedAddress; 36 | this.remoteConnectedPort = remoteConnectedPort; 37 | this.remoteOriginatorAddress = remoteOriginatorAddress; 38 | this.remoteOriginatorPort = remoteOriginatorPort; 39 | this.targetAddress = targetAddress; 40 | this.targetPort = targetPort; 41 | 42 | if (log.isEnabled()) 43 | log.log(20, "RemoteAcceptThread: " + remoteConnectedAddress + "/" + remoteConnectedPort + ", R: " 44 | + remoteOriginatorAddress + "/" + remoteOriginatorPort); 45 | } 46 | 47 | public void run() 48 | { 49 | try 50 | { 51 | c.cm.sendOpenConfirmation(c); 52 | 53 | s = new Socket(targetAddress, targetPort); 54 | 55 | StreamForwarder r2l = new StreamForwarder(c, null, s, c.getStdoutStream(), s.getOutputStream(), 56 | "RemoteToLocal"); 57 | StreamForwarder l2r = new StreamForwarder(c, null, null, s.getInputStream(), c.getStdinStream(), 58 | "LocalToRemote"); 59 | 60 | /* No need to start two threads, one can be executed in the current thread */ 61 | 62 | r2l.setDaemon(true); 63 | r2l.start(); 64 | l2r.run(); 65 | 66 | while (r2l.isAlive()) 67 | { 68 | try 69 | { 70 | r2l.join(); 71 | } 72 | catch (InterruptedException e) 73 | { 74 | } 75 | } 76 | 77 | /* If the channel is already closed, then this is a no-op */ 78 | 79 | c.cm.closeChannel(c, "EOF on both streams reached.", true); 80 | s.close(); 81 | } 82 | catch (IOException e) 83 | { 84 | log.log(50, "IOException in proxy code: " + e.getMessage()); 85 | 86 | try 87 | { 88 | c.cm.closeChannel(c, "IOException in proxy code (" + e.getMessage() + ")", true); 89 | } 90 | catch (IOException e1) 91 | { 92 | } 93 | try 94 | { 95 | if (s != null) 96 | s.close(); 97 | } 98 | catch (IOException e1) 99 | { 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/channel/RemoteForwardingData.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | /** 5 | * RemoteForwardingData. Data about a requested remote forwarding. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: RemoteForwardingData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | public class RemoteForwardingData 11 | { 12 | public String bindAddress; 13 | public int bindPort; 14 | 15 | String targetAddress; 16 | int targetPort; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/channel/StreamForwarder.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | import java.net.Socket; 8 | 9 | /** 10 | * A StreamForwarder forwards data between two given streams. 11 | * If two StreamForwarder threads are used (one for each direction) 12 | * then one can be configured to shutdown the underlying channel/socket 13 | * if both threads have finished forwarding (EOF). 14 | * 15 | * @author Christian Plattner, plattner@trilead.com 16 | * @version $Id: StreamForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 17 | */ 18 | public class StreamForwarder extends Thread 19 | { 20 | final OutputStream os; 21 | final InputStream is; 22 | final byte[] buffer = new byte[Channel.CHANNEL_BUFFER_SIZE]; 23 | final Channel c; 24 | final StreamForwarder sibling; 25 | final Socket s; 26 | final String mode; 27 | 28 | StreamForwarder(Channel c, StreamForwarder sibling, Socket s, InputStream is, OutputStream os, String mode) { 29 | this.is = is; 30 | this.os = os; 31 | this.mode = mode; 32 | this.c = c; 33 | this.sibling = sibling; 34 | this.s = s; 35 | } 36 | 37 | public void run() 38 | { 39 | try 40 | { 41 | while (true) 42 | { 43 | int len = is.read(buffer); 44 | if (len <= 0) 45 | break; 46 | os.write(buffer, 0, len); 47 | os.flush(); 48 | } 49 | } 50 | catch (IOException ignore) 51 | { 52 | try 53 | { 54 | c.cm.closeChannel(c, "Closed due to exception in StreamForwarder (" + mode + "): " 55 | + ignore.getMessage(), true); 56 | } 57 | catch (IOException e) 58 | { 59 | } 60 | } 61 | finally 62 | { 63 | try 64 | { 65 | os.close(); 66 | } 67 | catch (IOException e1) 68 | { 69 | } 70 | try 71 | { 72 | is.close(); 73 | } 74 | catch (IOException e2) 75 | { 76 | } 77 | 78 | if (sibling != null) 79 | { 80 | while (sibling.isAlive()) 81 | { 82 | try 83 | { 84 | sibling.join(); 85 | } 86 | catch (InterruptedException e) 87 | { 88 | } 89 | } 90 | 91 | try 92 | { 93 | c.cm.closeChannel(c, "StreamForwarder (" + mode + ") is cleaning up the connection", true); 94 | } 95 | catch (IOException e3) 96 | { 97 | } 98 | } 99 | 100 | if (s != null) { 101 | try 102 | { 103 | s.close(); 104 | } 105 | catch (IOException e1) 106 | { 107 | } 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/channel/X11ServerData.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | /** 5 | * X11ServerData. Data regarding an x11 forwarding target. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: X11ServerData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | * 10 | */ 11 | public class X11ServerData 12 | { 13 | public String hostname; 14 | public int port; 15 | public byte[] x11_magic_cookie; /* not the remote (fake) one, the local (real) one */ 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/compression/ICompressor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007 Kenny Root, Jeffrey Sharkey 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * a.) Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * b.) Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * c.) Neither the name of Trilead nor the names of its contributors may 14 | * be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | package com.trilead.ssh2.compression; 31 | 32 | /** 33 | * @author Kenny Root 34 | * 35 | */ 36 | public interface ICompressor { 37 | int getBufferSize(); 38 | 39 | int compress(byte[] buf, int start, int len, byte[] output); 40 | 41 | byte[] uncompress(byte[] buf, int start, int[] len); 42 | 43 | boolean canCompressPreauth(); 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/compression/ZlibOpenSSH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007 Kenny Root, Jeffrey Sharkey 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * a.) Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * b.) Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * c.) Neither the name of Trilead nor the names of its contributors may 14 | * be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | package com.trilead.ssh2.compression; 31 | 32 | /** 33 | * Defines how zlib@openssh.org compression works. 34 | * See 35 | * http://www.openssh.org/txt/draft-miller-secsh-compression-delayed-00.txt 36 | * compression is disabled until userauth has occurred. 37 | * 38 | * @author Matt Johnston 39 | * 40 | */ 41 | public class ZlibOpenSSH extends Zlib { 42 | 43 | public boolean canCompressPreauth() { 44 | return false; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/CryptoWishList.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto; 3 | 4 | import com.trilead.ssh2.compression.CompressionFactory; 5 | import com.trilead.ssh2.crypto.cipher.BlockCipherFactory; 6 | import com.trilead.ssh2.crypto.digest.MACs; 7 | import com.trilead.ssh2.transport.KexManager; 8 | 9 | 10 | /** 11 | * CryptoWishList. 12 | * 13 | * @author Christian Plattner, plattner@trilead.com 14 | * @version $Id: CryptoWishList.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 15 | */ 16 | public class CryptoWishList implements Cloneable 17 | { 18 | public CryptoWishList() { 19 | kexAlgorithms = KexManager.getDefaultKexAlgorithmList(); 20 | serverHostKeyAlgorithms = KexManager.getDefaultServerHostkeyAlgorithmList(); 21 | c2s_enc_algos = BlockCipherFactory.getDefaultCipherList(); 22 | s2c_enc_algos = BlockCipherFactory.getDefaultCipherList(); 23 | c2s_mac_algos = MACs.getMacList(); 24 | s2c_mac_algos = MACs.getMacList(); 25 | c2s_comp_algos = CompressionFactory.getDefaultCompressorList(); 26 | s2c_comp_algos = CompressionFactory.getDefaultCompressorList(); 27 | } 28 | 29 | public CryptoWishList(CryptoWishList other) { 30 | kexAlgorithms = other.kexAlgorithms.clone(); 31 | serverHostKeyAlgorithms = other.serverHostKeyAlgorithms.clone(); 32 | c2s_enc_algos = other.c2s_enc_algos.clone(); 33 | s2c_enc_algos = other.s2c_enc_algos.clone(); 34 | c2s_mac_algos = other.c2s_mac_algos.clone(); 35 | s2c_mac_algos = other.s2c_mac_algos.clone(); 36 | c2s_comp_algos = other.c2s_comp_algos.clone(); 37 | s2c_comp_algos = other.s2c_comp_algos.clone(); 38 | } 39 | 40 | public String[] kexAlgorithms; 41 | public String[] serverHostKeyAlgorithms; 42 | public String[] c2s_enc_algos; 43 | public String[] s2c_enc_algos; 44 | public String[] c2s_mac_algos; 45 | public String[] s2c_mac_algos; 46 | public String[] c2s_comp_algos; 47 | public String[] s2c_comp_algos; 48 | 49 | @Override 50 | public CryptoWishList clone() { 51 | return new CryptoWishList(this); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/KeyMaterial.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto; 3 | 4 | 5 | import java.math.BigInteger; 6 | 7 | import com.trilead.ssh2.crypto.digest.HashForSSH2Types; 8 | 9 | /** 10 | * Establishes key material for iv/key/mac (both directions). 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: KeyMaterial.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 14 | */ 15 | public class KeyMaterial 16 | { 17 | public byte[] initial_iv_client_to_server; 18 | public byte[] initial_iv_server_to_client; 19 | public byte[] enc_key_client_to_server; 20 | public byte[] enc_key_server_to_client; 21 | public byte[] integrity_key_client_to_server; 22 | public byte[] integrity_key_server_to_client; 23 | 24 | private static byte[] calculateKey(HashForSSH2Types sh, BigInteger K, byte[] H, byte type, byte[] SessionID, 25 | int keyLength) 26 | { 27 | byte[] res = new byte[keyLength]; 28 | 29 | int dglen = sh.getDigestLength(); 30 | int numRounds = (keyLength + dglen - 1) / dglen; 31 | 32 | byte[][] tmp = new byte[numRounds][]; 33 | 34 | sh.reset(); 35 | sh.updateBigInt(K); 36 | sh.updateBytes(H); 37 | sh.updateByte(type); 38 | sh.updateBytes(SessionID); 39 | 40 | tmp[0] = sh.getDigest(); 41 | 42 | int off = 0; 43 | int produced = Math.min(dglen, keyLength); 44 | 45 | System.arraycopy(tmp[0], 0, res, off, produced); 46 | 47 | keyLength -= produced; 48 | off += produced; 49 | 50 | for (int i = 1; i < numRounds; i++) 51 | { 52 | sh.updateBigInt(K); 53 | sh.updateBytes(H); 54 | 55 | for (int j = 0; j < i; j++) 56 | sh.updateBytes(tmp[j]); 57 | 58 | tmp[i] = sh.getDigest(); 59 | 60 | produced = Math.min(dglen, keyLength); 61 | System.arraycopy(tmp[i], 0, res, off, produced); 62 | keyLength -= produced; 63 | off += produced; 64 | } 65 | 66 | return res; 67 | } 68 | 69 | public static KeyMaterial create(String hashAlgo, byte[] H, BigInteger K, byte[] SessionID, int keyLengthCS, 70 | int blockSizeCS, int macLengthCS, int keyLengthSC, int blockSizeSC, int macLengthSC) 71 | throws IllegalArgumentException 72 | { 73 | KeyMaterial km = new KeyMaterial(); 74 | 75 | HashForSSH2Types sh = new HashForSSH2Types(hashAlgo); 76 | 77 | km.initial_iv_client_to_server = calculateKey(sh, K, H, (byte) 'A', SessionID, blockSizeCS); 78 | 79 | km.initial_iv_server_to_client = calculateKey(sh, K, H, (byte) 'B', SessionID, blockSizeSC); 80 | 81 | km.enc_key_client_to_server = calculateKey(sh, K, H, (byte) 'C', SessionID, keyLengthCS); 82 | 83 | km.enc_key_server_to_client = calculateKey(sh, K, H, (byte) 'D', SessionID, keyLengthSC); 84 | 85 | km.integrity_key_client_to_server = calculateKey(sh, K, H, (byte) 'E', SessionID, macLengthCS); 86 | 87 | km.integrity_key_server_to_client = calculateKey(sh, K, H, (byte) 'F', SessionID, macLengthSC); 88 | 89 | return km; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/PEMStructure.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto; 3 | 4 | /** 5 | * Parsed PEM structure. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PEMStructure.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | 11 | public class PEMStructure 12 | { 13 | public int pemType; 14 | String dekInfo[]; 15 | String procType[]; 16 | public byte[] data; 17 | } -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/cipher/AES.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.cipher; 3 | 4 | import javax.crypto.Cipher; 5 | import javax.crypto.NoSuchPaddingException; 6 | import javax.crypto.ShortBufferException; 7 | import javax.crypto.spec.IvParameterSpec; 8 | import javax.crypto.spec.SecretKeySpec; 9 | import java.security.InvalidAlgorithmParameterException; 10 | import java.security.InvalidKeyException; 11 | import java.security.NoSuchAlgorithmException; 12 | 13 | /** 14 | * AES modes for SSH using the JCE. 15 | */ 16 | public abstract class AES implements BlockCipher 17 | { 18 | private final int AES_BLOCK_SIZE = 16; 19 | 20 | protected Cipher cipher; 21 | 22 | @Override 23 | public void init(boolean forEncryption, byte[] key, byte[] iv) { 24 | try { 25 | cipher.init(forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, 26 | new SecretKeySpec(key, "AES"), 27 | new IvParameterSpec(iv)); 28 | } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { 29 | throw new IllegalArgumentException("Cannot initialize " + cipher.getAlgorithm(), e); 30 | } 31 | } 32 | 33 | @Override 34 | public int getBlockSize() { 35 | return AES_BLOCK_SIZE; 36 | } 37 | 38 | @Override 39 | public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) { 40 | try { 41 | cipher.update(src, srcoff, AES_BLOCK_SIZE, dst, dstoff); 42 | } catch (ShortBufferException e) { 43 | throw new AssertionError(e); 44 | } 45 | } 46 | 47 | public static class CBC extends AES { 48 | public CBC() throws IllegalArgumentException { 49 | try { 50 | cipher = Cipher.getInstance("AES/CBC/NoPadding"); 51 | } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 52 | throw new IllegalArgumentException("Cannot initialize AES/CBC/NoPadding", e); 53 | } 54 | } 55 | } 56 | 57 | public static class CTR extends AES { 58 | public CTR() throws IllegalArgumentException { 59 | try { 60 | cipher = Cipher.getInstance("AES/CTR/NoPadding"); 61 | } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { 62 | throw new IllegalArgumentException("Cannot initialize AES/CBC/NoPadding", e); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/cipher/BlockCipher.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | /** 4 | * BlockCipher. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: BlockCipher.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 8 | */ 9 | public interface BlockCipher 10 | { 11 | void init(boolean forEncryption, byte[] key, byte[] iv) throws IllegalArgumentException; 12 | 13 | int getBlockSize(); 14 | 15 | void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/cipher/BlockCipherFactory.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.cipher; 3 | 4 | import java.lang.reflect.Constructor; 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * BlockCipherFactory. 9 | * 10 | * @author Christian Plattner, plattner@trilead.com 11 | * @version $Id: BlockCipherFactory.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ 12 | */ 13 | public class BlockCipherFactory 14 | { 15 | private static class CipherEntry 16 | { 17 | final String type; 18 | final int blocksize; 19 | final int keysize; 20 | final String cipherClass; 21 | 22 | CipherEntry(String type, int blockSize, int keySize, String cipherClass) 23 | { 24 | this.type = type; 25 | this.blocksize = blockSize; 26 | this.keysize = keySize; 27 | this.cipherClass = cipherClass; 28 | } 29 | } 30 | 31 | private static final ArrayList ciphers = new ArrayList<>(); 32 | 33 | static 34 | { 35 | /* Higher Priority First */ 36 | 37 | ciphers.add(new CipherEntry("aes256-ctr", 16, 32, "com.trilead.ssh2.crypto.cipher.AES$CTR")); 38 | ciphers.add(new CipherEntry("aes128-ctr", 16, 16, "com.trilead.ssh2.crypto.cipher.AES$CTR")); 39 | ciphers.add(new CipherEntry("blowfish-ctr", 8, 16, "com.trilead.ssh2.crypto.cipher.BlowFish$CTR")); 40 | 41 | ciphers.add(new CipherEntry("aes256-cbc", 16, 32, "com.trilead.ssh2.crypto.cipher.AES$CBC")); 42 | ciphers.add(new CipherEntry("aes128-cbc", 16, 16, "com.trilead.ssh2.crypto.cipher.AES$CBC")); 43 | ciphers.add(new CipherEntry("blowfish-cbc", 8, 16, "com.trilead.ssh2.crypto.cipher.BlowFish$CBC")); 44 | 45 | ciphers.add(new CipherEntry("3des-ctr", 8, 24, "com.trilead.ssh2.crypto.cipher.DESede$CTR")); 46 | ciphers.add(new CipherEntry("3des-cbc", 8, 24, "com.trilead.ssh2.crypto.cipher.DESede$CBC")); 47 | } 48 | 49 | public static String[] getDefaultCipherList() 50 | { 51 | String list[] = new String[ciphers.size()]; 52 | for (int i = 0; i < ciphers.size(); i++) 53 | { 54 | CipherEntry ce = ciphers.get(i); 55 | list[i] = ce.type; 56 | } 57 | return list; 58 | } 59 | 60 | public static void checkCipherList(String[] cipherCandidates) 61 | { 62 | for (String cipherCandidate : cipherCandidates) 63 | getEntry(cipherCandidate); 64 | } 65 | 66 | public static BlockCipher createCipher(String type, boolean encrypt, byte[] key, byte[] iv) 67 | { 68 | try 69 | { 70 | CipherEntry ce = getEntry(type); 71 | Class cc = Class.forName(ce.cipherClass); 72 | Constructor constructor = cc.getConstructor(); 73 | BlockCipher bc = constructor.newInstance(); 74 | bc.init(encrypt, key, iv); 75 | return bc; 76 | } 77 | catch (Exception e) 78 | { 79 | throw new IllegalArgumentException("Cannot instantiate " + type, e); 80 | } 81 | } 82 | 83 | private static CipherEntry getEntry(String type) 84 | { 85 | for (CipherEntry ce : ciphers) { 86 | if (ce.type.equals(type)) 87 | return ce; 88 | } 89 | throw new IllegalArgumentException("Unknown algorithm " + type); 90 | } 91 | 92 | public static int getBlockSize(String type) 93 | { 94 | CipherEntry ce = getEntry(type); 95 | return ce.blocksize; 96 | } 97 | 98 | public static int getKeySize(String type) 99 | { 100 | CipherEntry ce = getEntry(type); 101 | return ce.keysize; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/cipher/CBCMode.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | /** 4 | * CBCMode. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: CBCMode.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 8 | */ 9 | public class CBCMode implements BlockCipher 10 | { 11 | BlockCipher tc; 12 | int blockSize; 13 | boolean doEncrypt; 14 | 15 | byte[] cbc_vector; 16 | byte[] tmp_vector; 17 | 18 | public void init(boolean forEncryption, byte[] key, byte[] iv) 19 | { 20 | } 21 | 22 | public CBCMode(BlockCipher tc, byte[] iv, boolean doEncrypt) 23 | throws IllegalArgumentException 24 | { 25 | this.tc = tc; 26 | this.blockSize = tc.getBlockSize(); 27 | this.doEncrypt = doEncrypt; 28 | 29 | if (this.blockSize != iv.length) 30 | throw new IllegalArgumentException("IV must be " + blockSize 31 | + " bytes long! (currently " + iv.length + ")"); 32 | 33 | this.cbc_vector = new byte[blockSize]; 34 | this.tmp_vector = new byte[blockSize]; 35 | System.arraycopy(iv, 0, cbc_vector, 0, blockSize); 36 | } 37 | 38 | public int getBlockSize() 39 | { 40 | return blockSize; 41 | } 42 | 43 | private void encryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 44 | { 45 | for (int i = 0; i < blockSize; i++) 46 | cbc_vector[i] ^= src[srcoff + i]; 47 | 48 | tc.transformBlock(cbc_vector, 0, dst, dstoff); 49 | 50 | System.arraycopy(dst, dstoff, cbc_vector, 0, blockSize); 51 | } 52 | 53 | private void decryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 54 | { 55 | /* Assume the worst, src and dst are overlapping... */ 56 | 57 | System.arraycopy(src, srcoff, tmp_vector, 0, blockSize); 58 | 59 | tc.transformBlock(src, srcoff, dst, dstoff); 60 | 61 | for (int i = 0; i < blockSize; i++) 62 | dst[dstoff + i] ^= cbc_vector[i]; 63 | 64 | /* ...that is why we need a tmp buffer. */ 65 | 66 | byte[] swap = cbc_vector; 67 | cbc_vector = tmp_vector; 68 | tmp_vector = swap; 69 | } 70 | 71 | public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 72 | { 73 | if (doEncrypt) 74 | encryptBlock(src, srcoff, dst, dstoff); 75 | else 76 | decryptBlock(src, srcoff, dst, dstoff); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/cipher/CTRMode.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.cipher; 3 | 4 | /** 5 | * This is CTR mode as described in draft-ietf-secsh-newmodes-XY.txt 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: CTRMode.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class CTRMode implements BlockCipher 11 | { 12 | byte[] X; 13 | byte[] Xenc; 14 | 15 | BlockCipher bc; 16 | int blockSize; 17 | boolean doEncrypt; 18 | 19 | int count = 0; 20 | 21 | public void init(boolean forEncryption, byte[] key, byte[] iv) 22 | { 23 | } 24 | 25 | public CTRMode(BlockCipher tc, byte[] iv, boolean doEnc) throws IllegalArgumentException 26 | { 27 | bc = tc; 28 | blockSize = bc.getBlockSize(); 29 | doEncrypt = doEnc; 30 | 31 | if (blockSize != iv.length) 32 | throw new IllegalArgumentException("IV must be " + blockSize + " bytes long! (currently " + iv.length + ")"); 33 | 34 | X = new byte[blockSize]; 35 | Xenc = new byte[blockSize]; 36 | 37 | System.arraycopy(iv, 0, X, 0, blockSize); 38 | } 39 | 40 | public final int getBlockSize() 41 | { 42 | return blockSize; 43 | } 44 | 45 | public final void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 46 | { 47 | bc.transformBlock(X, 0, Xenc, 0); 48 | 49 | for (int i = 0; i < blockSize; i++) 50 | { 51 | dst[dstoff + i] = (byte) (src[srcoff + i] ^ Xenc[i]); 52 | } 53 | 54 | for (int i = (blockSize - 1); i >= 0; i--) 55 | { 56 | X[i]++; 57 | if (X[i] != 0) 58 | break; 59 | 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/cipher/CipherOutputStream.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.cipher; 3 | 4 | import java.io.BufferedOutputStream; 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.IOException; 7 | import java.io.OutputStream; 8 | 9 | /** 10 | * CipherOutputStream. 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: CipherOutputStream.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 14 | */ 15 | public class CipherOutputStream 16 | { 17 | private BlockCipher currentCipher; 18 | private final BufferedOutputStream bo; 19 | private byte[] buffer; 20 | private byte[] enc; 21 | private int blockSize; 22 | private int pos; 23 | private boolean recordingOutput; 24 | private final ByteArrayOutputStream recordingOutputStream = new ByteArrayOutputStream(); 25 | 26 | public CipherOutputStream(BlockCipher tc, OutputStream bo) 27 | { 28 | if (bo instanceof BufferedOutputStream) { 29 | this.bo = (BufferedOutputStream) bo; 30 | } else { 31 | this.bo = new BufferedOutputStream(bo); 32 | } 33 | changeCipher(tc); 34 | } 35 | 36 | public void flush() throws IOException 37 | { 38 | if (pos != 0) 39 | throw new IOException("FATAL: cannot flush since crypto buffer is not aligned."); 40 | 41 | bo.flush(); 42 | } 43 | 44 | public void changeCipher(BlockCipher bc) 45 | { 46 | this.currentCipher = bc; 47 | blockSize = bc.getBlockSize(); 48 | buffer = new byte[blockSize]; 49 | enc = new byte[blockSize]; 50 | pos = 0; 51 | } 52 | 53 | public void startRecording() { 54 | recordingOutput = true; 55 | } 56 | 57 | public byte[] getRecordedOutput() { 58 | recordingOutput = false; 59 | byte[] recordedOutput = recordingOutputStream.toByteArray(); 60 | recordingOutputStream.reset(); 61 | return recordedOutput; 62 | } 63 | 64 | private void writeBlock() throws IOException 65 | { 66 | try 67 | { 68 | currentCipher.transformBlock(buffer, 0, enc, 0); 69 | } 70 | catch (Exception e) 71 | { 72 | throw new IOException("Error while decrypting block.", e); 73 | } 74 | 75 | bo.write(enc, 0, blockSize); 76 | pos = 0; 77 | 78 | if (recordingOutput) { 79 | recordingOutputStream.write(enc, 0, blockSize); 80 | } 81 | } 82 | 83 | public void write(byte[] src, int off, int len) throws IOException 84 | { 85 | while (len > 0) 86 | { 87 | int avail = blockSize - pos; 88 | int copy = Math.min(avail, len); 89 | 90 | System.arraycopy(src, off, buffer, pos, copy); 91 | pos += copy; 92 | off += copy; 93 | len -= copy; 94 | 95 | if (pos >= blockSize) 96 | writeBlock(); 97 | } 98 | } 99 | 100 | public void write(int b) throws IOException 101 | { 102 | buffer[pos++] = (byte) b; 103 | if (pos >= blockSize) 104 | writeBlock(); 105 | } 106 | 107 | public void writePlain(int b) throws IOException 108 | { 109 | if (pos != 0) 110 | throw new IOException("Cannot write plain since crypto buffer is not aligned."); 111 | bo.write(b); 112 | } 113 | 114 | public void writePlain(byte[] b, int off, int len) throws IOException 115 | { 116 | if (pos != 0) 117 | throw new IOException("Cannot write plain since crypto buffer is not aligned."); 118 | bo.write(b, off, len); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/cipher/EtmCipher.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | public interface EtmCipher { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/cipher/NullCipher.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | /** 4 | * NullCipher. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: NullCipher.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 8 | */ 9 | public class NullCipher implements BlockCipher 10 | { 11 | private int blockSize = 8; 12 | 13 | public NullCipher() 14 | { 15 | } 16 | 17 | public NullCipher(int blockSize) 18 | { 19 | this.blockSize = blockSize; 20 | } 21 | 22 | public void init(boolean forEncryption, byte[] key, byte[] iv) 23 | { 24 | } 25 | 26 | public int getBlockSize() 27 | { 28 | return blockSize; 29 | } 30 | 31 | public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 32 | { 33 | System.arraycopy(src, srcoff, dst, dstoff, blockSize); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/dh/Curve25519Exchange.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.dh; 2 | 3 | import com.google.crypto.tink.subtle.X25519; 4 | 5 | import java.io.IOException; 6 | import java.math.BigInteger; 7 | import java.security.InvalidKeyException; 8 | 9 | /** 10 | * Created by Kenny Root on 1/23/16. 11 | */ 12 | public class Curve25519Exchange extends GenericDhExchange { 13 | public static final String NAME = "curve25519-sha256"; 14 | public static final String ALT_NAME = "curve25519-sha256@libssh.org"; 15 | public static final int KEY_SIZE = 32; 16 | 17 | private byte[] clientPublic; 18 | private byte[] clientPrivate; 19 | private byte[] serverPublic; 20 | 21 | public Curve25519Exchange() { 22 | super(); 23 | } 24 | 25 | /* 26 | * Used to test known vectors. 27 | */ 28 | public Curve25519Exchange(byte[] secret) throws InvalidKeyException { 29 | if (secret.length != KEY_SIZE) { 30 | throw new AssertionError("secret must be key size"); 31 | } 32 | clientPrivate = secret.clone(); 33 | } 34 | 35 | @Override 36 | public void init(String name) throws IOException { 37 | if (!NAME.equals(name) && !ALT_NAME.equals(name)) { 38 | throw new IOException("Invalid name " + name); 39 | } 40 | 41 | clientPrivate = X25519.generatePrivateKey(); 42 | try { 43 | clientPublic = X25519.publicFromPrivate(clientPrivate); 44 | } catch (InvalidKeyException e) { 45 | throw new IOException(e); 46 | } 47 | } 48 | 49 | @Override 50 | public byte[] getE() { 51 | return clientPublic.clone(); 52 | } 53 | 54 | @Override 55 | protected byte[] getServerE() { 56 | return serverPublic.clone(); 57 | } 58 | 59 | @Override 60 | public void setF(byte[] f) throws IOException { 61 | if (f.length != KEY_SIZE) { 62 | throw new IOException("Server sent invalid key length " + f.length + " (expected " + 63 | KEY_SIZE + ")"); 64 | } 65 | serverPublic = f.clone(); 66 | try { 67 | byte[] sharedSecretBytes = X25519.computeSharedSecret(clientPrivate, serverPublic); 68 | int allBytes = 0; 69 | for (int i = 0; i < sharedSecretBytes.length; i++) { 70 | allBytes |= sharedSecretBytes[i]; 71 | } 72 | if (allBytes == 0) { 73 | throw new IOException("Invalid key computed; all zeroes"); 74 | } 75 | sharedSecret = new BigInteger(1, sharedSecretBytes); 76 | } catch (InvalidKeyException e) { 77 | throw new IOException(e); 78 | } 79 | } 80 | 81 | @Override 82 | public String getHashAlgo() { 83 | return "SHA-256"; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/dh/DhGroupExchange.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.dh; 3 | 4 | import java.math.BigInteger; 5 | import java.security.SecureRandom; 6 | 7 | import com.trilead.ssh2.DHGexParameters; 8 | import com.trilead.ssh2.crypto.digest.HashForSSH2Types; 9 | 10 | 11 | /** 12 | * DhGroupExchange. 13 | * 14 | * @author Christian Plattner, plattner@trilead.com 15 | * @version $Id: DhGroupExchange.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 16 | */ 17 | public class DhGroupExchange 18 | { 19 | /* Given by the standard */ 20 | 21 | private BigInteger p; 22 | private BigInteger g; 23 | 24 | /* Client public and private */ 25 | 26 | private BigInteger e; 27 | private BigInteger x; 28 | 29 | /* Server public */ 30 | 31 | private BigInteger f; 32 | 33 | /* Shared secret */ 34 | 35 | private BigInteger k; 36 | 37 | public DhGroupExchange(BigInteger p, BigInteger g) 38 | { 39 | this.p = p; 40 | this.g = g; 41 | } 42 | 43 | public void init(SecureRandom rnd) 44 | { 45 | k = null; 46 | 47 | x = new BigInteger(p.bitLength() - 1, rnd); 48 | e = g.modPow(x, p); 49 | } 50 | 51 | /** 52 | * @return Returns the e. 53 | */ 54 | public BigInteger getE() 55 | { 56 | if (e == null) 57 | throw new IllegalStateException("Not initialized!"); 58 | 59 | return e; 60 | } 61 | 62 | /** 63 | * @return Returns the shared secret k. 64 | */ 65 | public BigInteger getK() 66 | { 67 | if (k == null) 68 | throw new IllegalStateException("Shared secret not yet known, need f first!"); 69 | 70 | return k; 71 | } 72 | 73 | /** 74 | * Sets f and calculates the shared secret. 75 | */ 76 | public void setF(BigInteger f) 77 | { 78 | if (e == null) 79 | throw new IllegalStateException("Not initialized!"); 80 | 81 | BigInteger zero = BigInteger.valueOf(0); 82 | 83 | if (zero.compareTo(f) >= 0 || p.compareTo(f) <= 0) 84 | throw new IllegalArgumentException("Invalid f specified!"); 85 | 86 | this.f = f; 87 | this.k = f.modPow(x, p); 88 | } 89 | 90 | public byte[] calculateH(String hashAlgo, byte[] clientversion, byte[] serverversion, 91 | byte[] clientKexPayload, byte[] serverKexPayload, byte[] hostKey, DHGexParameters para) 92 | { 93 | HashForSSH2Types hash = new HashForSSH2Types(hashAlgo); 94 | 95 | hash.updateByteString(clientversion); 96 | hash.updateByteString(serverversion); 97 | hash.updateByteString(clientKexPayload); 98 | hash.updateByteString(serverKexPayload); 99 | hash.updateByteString(hostKey); 100 | if (para.getMin_group_len() > 0) 101 | hash.updateUINT32(para.getMin_group_len()); 102 | hash.updateUINT32(para.getPref_group_len()); 103 | if (para.getMax_group_len() > 0) 104 | hash.updateUINT32(para.getMax_group_len()); 105 | hash.updateBigInt(p); 106 | hash.updateBigInt(g); 107 | hash.updateBigInt(e); 108 | hash.updateBigInt(f); 109 | hash.updateBigInt(k); 110 | 111 | return hash.getDigest(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/dh/GenericDhExchange.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.dh; 3 | 4 | import java.io.IOException; 5 | import java.io.UnsupportedEncodingException; 6 | import java.math.BigInteger; 7 | 8 | import com.trilead.ssh2.crypto.digest.HashForSSH2Types; 9 | import com.trilead.ssh2.log.Logger; 10 | 11 | 12 | /** 13 | * DhExchange. 14 | * 15 | * @author Christian Plattner, plattner@trilead.com 16 | * @version $Id: DhExchange.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ 17 | */ 18 | public abstract class GenericDhExchange 19 | { 20 | private static final Logger log = Logger.getLogger(GenericDhExchange.class); 21 | 22 | /* Shared secret */ 23 | 24 | BigInteger sharedSecret; 25 | 26 | protected GenericDhExchange() 27 | { 28 | } 29 | 30 | public static GenericDhExchange getInstance(String algo) { 31 | if (Curve25519Exchange.NAME.equals(algo) || Curve25519Exchange.ALT_NAME.equals(algo)) { 32 | return new Curve25519Exchange(); 33 | } 34 | if (algo.startsWith("ecdh-sha2-")) { 35 | return new EcDhExchange(); 36 | } else { 37 | return new DhExchange(); 38 | } 39 | } 40 | 41 | public abstract void init(String name) throws IOException; 42 | 43 | /** 44 | * @return Returns the e (public value) 45 | * @throws IllegalStateException 46 | */ 47 | public abstract byte[] getE(); 48 | 49 | /** 50 | * @return Returns the server's e (public value) 51 | * @throws IllegalStateException 52 | */ 53 | protected abstract byte[] getServerE(); 54 | 55 | /** 56 | * @return Returns the shared secret k. 57 | * @throws IllegalStateException 58 | */ 59 | public BigInteger getK() 60 | { 61 | if (sharedSecret == null) 62 | throw new IllegalStateException("Shared secret not yet known, need f first!"); 63 | 64 | return sharedSecret; 65 | } 66 | 67 | /** 68 | * @param f 69 | */ 70 | public abstract void setF(byte[] f) throws IOException; 71 | 72 | public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload, 73 | byte[] serverKexPayload, byte[] hostKey) throws UnsupportedEncodingException 74 | { 75 | HashForSSH2Types hash = new HashForSSH2Types(getHashAlgo()); 76 | 77 | if (log.isEnabled()) 78 | { 79 | log.log(90, "Client: '" + new String(clientversion) + "'"); 80 | log.log(90, "Server: '" + new String(serverversion) + "'"); 81 | } 82 | 83 | hash.updateByteString(clientversion); 84 | hash.updateByteString(serverversion); 85 | hash.updateByteString(clientKexPayload); 86 | hash.updateByteString(serverKexPayload); 87 | hash.updateByteString(hostKey); 88 | hash.updateByteString(getE()); 89 | hash.updateByteString(getServerE()); 90 | hash.updateBigInt(sharedSecret); 91 | 92 | return hash.getDigest(); 93 | } 94 | 95 | public abstract String getHashAlgo(); 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.digest; 3 | 4 | import java.math.BigInteger; 5 | import java.security.DigestException; 6 | import java.security.MessageDigest; 7 | import java.security.NoSuchAlgorithmException; 8 | 9 | /** 10 | * HashForSSH2Types. 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: HashForSSH2Types.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 14 | */ 15 | public class HashForSSH2Types 16 | { 17 | MessageDigest md; 18 | 19 | public HashForSSH2Types(String type) 20 | { 21 | try { 22 | md = MessageDigest.getInstance(type); 23 | } catch (NoSuchAlgorithmException e) { 24 | throw new RuntimeException("Unsupported algorithm " + type); 25 | } 26 | } 27 | 28 | public void updateByte(byte b) 29 | { 30 | /* HACK - to test it with J2ME */ 31 | byte[] tmp = new byte[1]; 32 | tmp[0] = b; 33 | md.update(tmp); 34 | } 35 | 36 | public void updateBytes(byte[] b) 37 | { 38 | md.update(b); 39 | } 40 | 41 | public void updateUINT32(int v) 42 | { 43 | md.update((byte) (v >> 24)); 44 | md.update((byte) (v >> 16)); 45 | md.update((byte) (v >> 8)); 46 | md.update((byte) (v)); 47 | } 48 | 49 | public void updateByteString(byte[] b) 50 | { 51 | updateUINT32(b.length); 52 | updateBytes(b); 53 | } 54 | 55 | public void updateBigInt(BigInteger b) 56 | { 57 | updateByteString(b.toByteArray()); 58 | } 59 | 60 | public void reset() 61 | { 62 | md.reset(); 63 | } 64 | 65 | public int getDigestLength() 66 | { 67 | return md.getDigestLength(); 68 | } 69 | 70 | public byte[] getDigest() 71 | { 72 | byte[] tmp = new byte[md.getDigestLength()]; 73 | getDigest(tmp); 74 | return tmp; 75 | } 76 | 77 | public void getDigest(byte[] out) 78 | { 79 | getDigest(out, 0); 80 | } 81 | 82 | public void getDigest(byte[] out, int off) 83 | { 84 | try { 85 | md.digest(out, off, out.length - off); 86 | } catch (DigestException e) { 87 | // TODO is this right?! 88 | throw new RuntimeException("Unable to digest", e); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/digest/MAC.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.digest; 2 | 3 | /** 4 | * Created by kenny on 2/12/17. 5 | */ 6 | public interface MAC { 7 | void initMac(int seq); 8 | void update(byte[] packetdata, int off, int len); 9 | void getMac(byte[] out, int off); 10 | int size(); 11 | boolean isEncryptThenMac(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/digest/MACs.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.digest; 3 | 4 | /** 5 | * MAC. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: MAC.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 9 | */ 10 | public final class MACs 11 | { 12 | /* Higher Priority First */ 13 | private static final String[] MAC_LIST = { 14 | HMAC.HMAC_SHA2_256_ETM, 15 | HMAC.HMAC_SHA2_512_ETM, 16 | HMAC.HMAC_SHA1_ETM, 17 | HMAC.HMAC_SHA2_256, 18 | HMAC.HMAC_SHA2_512, 19 | HMAC.HMAC_SHA1, 20 | }; 21 | 22 | public final static String[] getMacList() 23 | { 24 | return MAC_LIST; 25 | } 26 | 27 | public final static void checkMacList(String[] macs) 28 | { 29 | for (int i = 0; i < macs.length; i++) { 30 | getKeyLen(macs[i]); 31 | } 32 | } 33 | 34 | public final static int getKeyLen(String type) 35 | { 36 | if (type == null) 37 | throw new IllegalArgumentException("type == null"); 38 | 39 | if (type.startsWith(HMAC.HMAC_SHA1)) 40 | return 20; 41 | if (type.startsWith(HMAC.HMAC_MD5)) 42 | return 16; 43 | if (type.startsWith(HMAC.HMAC_SHA2_256)) 44 | return 32; 45 | if (type.startsWith(HMAC.HMAC_SHA2_512)) 46 | return 64; 47 | 48 | throw new IllegalArgumentException("Unknown algorithm " + type); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/keys/Ed25519KeyFactory.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.keys; 2 | 3 | import java.security.InvalidKeyException; 4 | import java.security.Key; 5 | import java.security.KeyFactorySpi; 6 | import java.security.PrivateKey; 7 | import java.security.PublicKey; 8 | import java.security.spec.InvalidKeySpecException; 9 | import java.security.spec.KeySpec; 10 | import java.security.spec.PKCS8EncodedKeySpec; 11 | import java.security.spec.X509EncodedKeySpec; 12 | 13 | public class Ed25519KeyFactory extends KeyFactorySpi { 14 | @Override 15 | protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { 16 | if (keySpec instanceof X509EncodedKeySpec) { 17 | return new Ed25519PublicKey((X509EncodedKeySpec) keySpec); 18 | } 19 | throw new InvalidKeySpecException("Unrecognized key spec: " + keySpec.getClass()); 20 | } 21 | 22 | @Override 23 | protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { 24 | if (keySpec instanceof PKCS8EncodedKeySpec) { 25 | return new Ed25519PrivateKey((PKCS8EncodedKeySpec) keySpec); 26 | } 27 | throw new InvalidKeySpecException("Unrecognized key spec: " + keySpec.getClass()); 28 | } 29 | 30 | @Override 31 | protected T engineGetKeySpec(Key key, Class keySpec) throws InvalidKeySpecException { 32 | throw new InvalidKeySpecException("not implemented yet " + key + " " + keySpec); 33 | } 34 | 35 | @Override 36 | public Key engineTranslateKey(Key key) throws InvalidKeyException { 37 | if (key instanceof Ed25519PublicKey || key instanceof Ed25519PrivateKey) { 38 | return key; 39 | } 40 | 41 | if (key instanceof PublicKey && key.getFormat().equals("X.509")) { 42 | byte[] encoded = key.getEncoded(); 43 | try { 44 | return new Ed25519PublicKey(new X509EncodedKeySpec(encoded)); 45 | } catch (InvalidKeySpecException e) { 46 | throw new InvalidKeyException(e); 47 | } 48 | } 49 | 50 | if (key instanceof PrivateKey && key.getFormat().equals("PKCS#8")) { 51 | byte[] encoded = key.getEncoded(); 52 | try { 53 | return new Ed25519PrivateKey(new PKCS8EncodedKeySpec(encoded)); 54 | } catch (InvalidKeySpecException e) { 55 | throw new InvalidKeyException(e); 56 | } 57 | } 58 | 59 | throw new InvalidKeyException("Could not convert EdDSA key from key class " + key.getClass()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/keys/Ed25519KeyPairGenerator.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.keys; 2 | 3 | import com.google.crypto.tink.subtle.Ed25519Sign; 4 | 5 | import java.security.GeneralSecurityException; 6 | import java.security.KeyPair; 7 | import java.security.KeyPairGeneratorSpi; 8 | import java.security.SecureRandom; 9 | 10 | public class Ed25519KeyPairGenerator extends KeyPairGeneratorSpi { 11 | @Override 12 | public void initialize(int keySize, SecureRandom secureRandom) { 13 | // ignored. 14 | } 15 | 16 | @Override 17 | public KeyPair generateKeyPair() { 18 | try { 19 | Ed25519Sign.KeyPair kp = Ed25519Sign.KeyPair.newKeyPair(); 20 | return new KeyPair(new Ed25519PublicKey(kp.getPublicKey()), new Ed25519PrivateKey(kp.getPrivateKey())); 21 | } catch (GeneralSecurityException e) { 22 | throw new IllegalStateException(e); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/crypto/keys/Ed25519Provider.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.keys; 2 | 3 | import java.security.AccessController; 4 | import java.security.PrivilegedAction; 5 | import java.security.Provider; 6 | import java.security.Security; 7 | 8 | public class Ed25519Provider extends Provider { 9 | public static final String NAME = "ConnectBot Ed25519 Provider"; 10 | public static final String KEY_ALGORITHM = "Ed25519"; 11 | private static final Object sInitLock = new Object(); 12 | private static boolean sInitialized = false; 13 | 14 | public Ed25519Provider() { 15 | super(NAME, 1.0, "Not for use elsewhere"); 16 | AccessController.doPrivileged((PrivilegedAction) () -> { 17 | setup(); 18 | return null; 19 | }); 20 | } 21 | 22 | protected void setup() { 23 | put("KeyFactory." + KEY_ALGORITHM, getClass().getPackage().getName() + ".Ed25519KeyFactory"); 24 | put("KeyPairGenerator." + KEY_ALGORITHM, getClass().getPackage().getName() + ".Ed25519KeyPairGenerator"); 25 | 26 | // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } 27 | put("Alg.Alias.KeyFactory.1.3.101.112", KEY_ALGORITHM); 28 | put("Alg.Alias.KeyFactory.EdDSA", KEY_ALGORITHM); 29 | put("Alg.Alias.KeyFactory.OID.1.3.101.112", KEY_ALGORITHM); 30 | put("Alg.Alias.KeyPairGenerator.1.3.101.112", KEY_ALGORITHM); 31 | put("Alg.Alias.KeyPairGenerator.EdDSA", KEY_ALGORITHM); 32 | put("Alg.Alias.KeyPairGenerator.OID.1.3.101.112", KEY_ALGORITHM); 33 | } 34 | 35 | public static void insertIfNeeded() { 36 | synchronized (sInitLock) { 37 | if (!sInitialized) { 38 | Security.addProvider(new Ed25519Provider()); 39 | sInitialized = true; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/log/Logger.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.log; 3 | 4 | import com.trilead.ssh2.DebugLogger; 5 | 6 | /** 7 | * Logger - a very simple logger, mainly used during development. 8 | * Is not based on log4j (to reduce external dependencies). 9 | * However, if needed, something like log4j could easily be 10 | * hooked in. 11 | *

12 | * For speed reasons, the static variables are not protected 13 | * with semaphores. In other words, if you dynamicaly change the 14 | * logging settings, then some threads may still use the old setting. 15 | * 16 | * @author Christian Plattner, plattner@trilead.com 17 | * @version $Id: Logger.java,v 1.2 2008/03/03 07:01:36 cplattne Exp $ 18 | */ 19 | 20 | public class Logger 21 | { 22 | public static boolean enabled = false; 23 | public static DebugLogger logger = null; 24 | 25 | private String className; 26 | 27 | public final static Logger getLogger(Class x) 28 | { 29 | return new Logger(x); 30 | } 31 | 32 | public Logger(Class x) 33 | { 34 | this.className = x.getName(); 35 | } 36 | 37 | public final boolean isEnabled() 38 | { 39 | return enabled; 40 | } 41 | 42 | public final void log(int level, String message) 43 | { 44 | if (!enabled) 45 | return; 46 | 47 | DebugLogger target = logger; 48 | 49 | if (target == null) 50 | return; 51 | 52 | target.log(level, className, message); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketChannelAuthAgentReq.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | /** 4 | * PacketGlobalAuthAgent. 5 | * 6 | * @author Kenny Root, kenny@the-b.org 7 | * @version $Id$ 8 | */ 9 | public class PacketChannelAuthAgentReq 10 | { 11 | byte[] payload; 12 | 13 | public int recipientChannelID; 14 | 15 | public PacketChannelAuthAgentReq(int recipientChannelID) 16 | { 17 | this.recipientChannelID = recipientChannelID; 18 | } 19 | 20 | public byte[] getPayload() 21 | { 22 | if (payload == null) 23 | { 24 | TypesWriter tw = new TypesWriter(); 25 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 26 | tw.writeUINT32(recipientChannelID); 27 | tw.writeString("auth-agent-req@openssh.com"); 28 | tw.writeBoolean(true); // want reply 29 | payload = tw.getBytes(); 30 | } 31 | return payload; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketChannelOpenConfirmation.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketChannelOpenConfirmation. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketChannelOpenConfirmation.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketChannelOpenConfirmation 12 | { 13 | byte[] payload; 14 | 15 | public int recipientChannelID; 16 | public int senderChannelID; 17 | public int initialWindowSize; 18 | public int maxPacketSize; 19 | 20 | public PacketChannelOpenConfirmation(int recipientChannelID, int senderChannelID, int initialWindowSize, 21 | int maxPacketSize) 22 | { 23 | this.recipientChannelID = recipientChannelID; 24 | this.senderChannelID = senderChannelID; 25 | this.initialWindowSize = initialWindowSize; 26 | this.maxPacketSize = maxPacketSize; 27 | } 28 | 29 | public PacketChannelOpenConfirmation(byte payload[], int off, int len) throws IOException 30 | { 31 | this.payload = new byte[len]; 32 | System.arraycopy(payload, off, this.payload, 0, len); 33 | 34 | TypesReader tr = new TypesReader(payload, off, len); 35 | 36 | int packet_type = tr.readByte(); 37 | 38 | if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) 39 | throw new IOException( 40 | "This is not a SSH_MSG_CHANNEL_OPEN_CONFIRMATION! (" 41 | + packet_type + ")"); 42 | 43 | recipientChannelID = tr.readUINT32(); 44 | senderChannelID = tr.readUINT32(); 45 | initialWindowSize = tr.readUINT32(); 46 | maxPacketSize = tr.readUINT32(); 47 | 48 | if (tr.remain() != 0) 49 | throw new IOException("Padding in SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet!"); 50 | } 51 | 52 | public byte[] getPayload() 53 | { 54 | if (payload == null) 55 | { 56 | TypesWriter tw = new TypesWriter(); 57 | tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 58 | tw.writeUINT32(recipientChannelID); 59 | tw.writeUINT32(senderChannelID); 60 | tw.writeUINT32(initialWindowSize); 61 | tw.writeUINT32(maxPacketSize); 62 | payload = tw.getBytes(); 63 | } 64 | return payload; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketChannelOpenFailure.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketChannelOpenFailure. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketChannelOpenFailure.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketChannelOpenFailure 12 | { 13 | byte[] payload; 14 | 15 | public int recipientChannelID; 16 | public int reasonCode; 17 | public String description; 18 | public String languageTag; 19 | 20 | public PacketChannelOpenFailure(int recipientChannelID, int reasonCode, String description, 21 | String languageTag) 22 | { 23 | this.recipientChannelID = recipientChannelID; 24 | this.reasonCode = reasonCode; 25 | this.description = description; 26 | this.languageTag = languageTag; 27 | } 28 | 29 | public PacketChannelOpenFailure(byte payload[], int off, int len) throws IOException 30 | { 31 | this.payload = new byte[len]; 32 | System.arraycopy(payload, off, this.payload, 0, len); 33 | 34 | TypesReader tr = new TypesReader(payload, off, len); 35 | 36 | int packet_type = tr.readByte(); 37 | 38 | if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN_FAILURE) 39 | throw new IOException( 40 | "This is not a SSH_MSG_CHANNEL_OPEN_FAILURE! (" 41 | + packet_type + ")"); 42 | 43 | recipientChannelID = tr.readUINT32(); 44 | reasonCode = tr.readUINT32(); 45 | description = tr.readString(); 46 | languageTag = tr.readString(); 47 | 48 | if (tr.remain() != 0) 49 | throw new IOException("Padding in SSH_MSG_CHANNEL_OPEN_FAILURE packet!"); 50 | } 51 | 52 | public byte[] getPayload() 53 | { 54 | if (payload == null) 55 | { 56 | TypesWriter tw = new TypesWriter(); 57 | tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN_FAILURE); 58 | tw.writeUINT32(recipientChannelID); 59 | tw.writeUINT32(reasonCode); 60 | tw.writeString(description); 61 | tw.writeString(languageTag); 62 | payload = tw.getBytes(); 63 | } 64 | return payload; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketChannelTrileadPing.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketChannelTrileadPing. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketChannelTrileadPing.java,v 1.1 2008/03/03 07:01:36 9 | * cplattne Exp $ 10 | */ 11 | public class PacketChannelTrileadPing 12 | { 13 | byte[] payload; 14 | 15 | public int recipientChannelID; 16 | 17 | public PacketChannelTrileadPing(int recipientChannelID) 18 | { 19 | this.recipientChannelID = recipientChannelID; 20 | } 21 | 22 | public byte[] getPayload() 23 | { 24 | if (payload == null) 25 | { 26 | TypesWriter tw = new TypesWriter(); 27 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 28 | tw.writeUINT32(recipientChannelID); 29 | tw.writeString("trilead-ping"); 30 | tw.writeBoolean(true); 31 | payload = tw.getBytes(); 32 | } 33 | return payload; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketChannelWindowAdjust.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketChannelWindowAdjust. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketChannelWindowAdjust.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketChannelWindowAdjust 12 | { 13 | byte[] payload; 14 | 15 | public int recipientChannelID; 16 | public int windowChange; 17 | 18 | public PacketChannelWindowAdjust(int recipientChannelID, int windowChange) 19 | { 20 | this.recipientChannelID = recipientChannelID; 21 | this.windowChange = windowChange; 22 | } 23 | 24 | public PacketChannelWindowAdjust(byte payload[], int off, int len) throws IOException 25 | { 26 | this.payload = new byte[len]; 27 | System.arraycopy(payload, off, this.payload, 0, len); 28 | 29 | TypesReader tr = new TypesReader(payload, off, len); 30 | 31 | int packet_type = tr.readByte(); 32 | 33 | if (packet_type != Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST) 34 | throw new IOException( 35 | "This is not a SSH_MSG_CHANNEL_WINDOW_ADJUST! (" 36 | + packet_type + ")"); 37 | 38 | recipientChannelID = tr.readUINT32(); 39 | windowChange = tr.readUINT32(); 40 | 41 | if (tr.remain() != 0) 42 | throw new IOException("Padding in SSH_MSG_CHANNEL_WINDOW_ADJUST packet!"); 43 | } 44 | 45 | public byte[] getPayload() 46 | { 47 | if (payload == null) 48 | { 49 | TypesWriter tw = new TypesWriter(); 50 | tw.writeByte(Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST); 51 | tw.writeUINT32(recipientChannelID); 52 | tw.writeUINT32(windowChange); 53 | payload = tw.getBytes(); 54 | } 55 | return payload; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketDisconnect.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketDisconnect. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketDisconnect.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ 11 | */ 12 | public class PacketDisconnect 13 | { 14 | byte[] payload; 15 | 16 | int reason; 17 | String desc; 18 | String lang; 19 | 20 | public PacketDisconnect(byte payload[], int off, int len) throws IOException 21 | { 22 | this.payload = new byte[len]; 23 | System.arraycopy(payload, off, this.payload, 0, len); 24 | 25 | TypesReader tr = new TypesReader(payload, off, len); 26 | 27 | int packet_type = tr.readByte(); 28 | 29 | if (packet_type != Packets.SSH_MSG_DISCONNECT) 30 | throw new IOException("This is not a Disconnect Packet! (" + packet_type + ")"); 31 | 32 | reason = tr.readUINT32(); 33 | desc = tr.readString(); 34 | lang = tr.readString(); 35 | } 36 | 37 | public PacketDisconnect(int reason, String desc, String lang) 38 | { 39 | this.reason = reason; 40 | this.desc = desc; 41 | this.lang = lang; 42 | } 43 | 44 | public byte[] getPayload() 45 | { 46 | if (payload == null) 47 | { 48 | TypesWriter tw = new TypesWriter(); 49 | tw.writeByte(Packets.SSH_MSG_DISCONNECT); 50 | tw.writeUINT32(reason); 51 | tw.writeString(desc); 52 | tw.writeString(lang); 53 | payload = tw.getBytes(); 54 | } 55 | return payload; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketExtInfo.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | 9 | /** 10 | * Packet format described here: 11 | * https://tools.ietf.org/html/draft-ietf-curdle-ssh-ext-info-15#section-2.3 12 | */ 13 | public class PacketExtInfo 14 | { 15 | private byte[] payload; 16 | 17 | private final Map extNameToValue; 18 | 19 | public byte[] getPayload() 20 | { 21 | if (payload == null) 22 | { 23 | TypesWriter tw = new TypesWriter(); 24 | tw.writeByte(Packets.SSH_MSG_EXT_INFO); 25 | tw.writeUINT32(extNameToValue.size()); 26 | for (Entry nameAndValue : extNameToValue.entrySet()) 27 | { 28 | tw.writeString(nameAndValue.getKey()); 29 | tw.writeString(nameAndValue.getValue()); 30 | } 31 | payload = tw.getBytes(); 32 | } 33 | return payload; 34 | } 35 | 36 | public Map getExtNameToValue() 37 | { 38 | return extNameToValue; 39 | } 40 | 41 | public PacketExtInfo(byte[] payload, int off, int len) throws IOException 42 | { 43 | this.payload = new byte[len]; 44 | System.arraycopy(payload, off, this.payload, 0, len); 45 | 46 | TypesReader tr = new TypesReader(payload, off, len); 47 | int packet_type = tr.readByte(); 48 | if (packet_type != Packets.SSH_MSG_EXT_INFO) 49 | { 50 | throw new IOException("This is not a SSH_MSG_EXT_INFO! (" 51 | + packet_type + ")"); 52 | } 53 | 54 | // Type has dynamic number of fields 55 | // First int tells us how many pairs to expect 56 | int numExtensions = tr.readUINT32(); 57 | if (numExtensions >= 1024) { 58 | throw new IOException("Too many entries in ext info packet"); 59 | } 60 | 61 | Map extNameToValue_ = new HashMap<>(numExtensions); 62 | for (int i = 0; i < numExtensions; i++) 63 | { 64 | String name = tr.readString(); 65 | String value = tr.readString(); 66 | extNameToValue_.put(name, value); 67 | } 68 | extNameToValue = Collections.unmodifiableMap(extNameToValue_); 69 | 70 | if (tr.remain() != 0) 71 | { 72 | throw new IOException("Padding in SSH_MSG_EXT_INFO packet!"); 73 | } 74 | } 75 | 76 | public PacketExtInfo(Map extNameToValue) 77 | { 78 | this.extNameToValue = Collections.unmodifiableMap(new HashMap<>(extNameToValue)); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketGlobalCancelForwardRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketGlobalCancelForwardRequest. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketGlobalCancelForwardRequest.java,v 1.1 2007/10/15 12:49:55 9 | * cplattne Exp $ 10 | */ 11 | public class PacketGlobalCancelForwardRequest 12 | { 13 | byte[] payload; 14 | 15 | public boolean wantReply; 16 | public String bindAddress; 17 | public int bindPort; 18 | 19 | public PacketGlobalCancelForwardRequest(boolean wantReply, String bindAddress, int bindPort) 20 | { 21 | this.wantReply = wantReply; 22 | this.bindAddress = bindAddress; 23 | this.bindPort = bindPort; 24 | } 25 | 26 | public byte[] getPayload() 27 | { 28 | if (payload == null) 29 | { 30 | TypesWriter tw = new TypesWriter(); 31 | tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST); 32 | 33 | tw.writeString("cancel-tcpip-forward"); 34 | tw.writeBoolean(wantReply); 35 | tw.writeString(bindAddress); 36 | tw.writeUINT32(bindPort); 37 | 38 | payload = tw.getBytes(); 39 | } 40 | return payload; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketGlobalForwardRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketGlobalForwardRequest. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketGlobalForwardRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketGlobalForwardRequest 11 | { 12 | byte[] payload; 13 | 14 | public boolean wantReply; 15 | public String bindAddress; 16 | public int bindPort; 17 | 18 | public PacketGlobalForwardRequest(boolean wantReply, String bindAddress, int bindPort) 19 | { 20 | this.wantReply = wantReply; 21 | this.bindAddress = bindAddress; 22 | this.bindPort = bindPort; 23 | } 24 | 25 | public byte[] getPayload() 26 | { 27 | if (payload == null) 28 | { 29 | TypesWriter tw = new TypesWriter(); 30 | tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST); 31 | 32 | tw.writeString("tcpip-forward"); 33 | tw.writeBoolean(wantReply); 34 | tw.writeString(bindAddress); 35 | tw.writeUINT32(bindPort); 36 | 37 | payload = tw.getBytes(); 38 | } 39 | return payload; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketGlobalTrileadPing.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketGlobalTrileadPing. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketGlobalTrileadPing.java,v 1.1 2008/03/03 07:01:36 cplattne Exp $ 9 | */ 10 | public class PacketGlobalTrileadPing 11 | { 12 | byte[] payload; 13 | 14 | public PacketGlobalTrileadPing() 15 | { 16 | } 17 | 18 | public byte[] getPayload() 19 | { 20 | if (payload == null) 21 | { 22 | TypesWriter tw = new TypesWriter(); 23 | tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST); 24 | 25 | tw.writeString("trilead-ping"); 26 | tw.writeBoolean(true); 27 | 28 | payload = tw.getBytes(); 29 | } 30 | return payload; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketIgnore.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketIgnore. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketIgnore.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketIgnore 13 | { 14 | byte[] payload; 15 | 16 | byte[] data; 17 | 18 | public void setData(byte[] data) 19 | { 20 | this.data = data; 21 | payload = null; 22 | } 23 | 24 | public PacketIgnore() 25 | { 26 | } 27 | 28 | public PacketIgnore(byte payload[], int off, int len) throws IOException 29 | { 30 | this.payload = new byte[len]; 31 | System.arraycopy(payload, off, this.payload, 0, len); 32 | 33 | TypesReader tr = new TypesReader(payload, off, len); 34 | 35 | int packet_type = tr.readByte(); 36 | 37 | if (packet_type != Packets.SSH_MSG_IGNORE) 38 | throw new IOException("This is not a SSH_MSG_IGNORE packet! (" + packet_type + ")"); 39 | 40 | /* Could parse String body */ 41 | } 42 | 43 | public byte[] getPayload() 44 | { 45 | if (payload == null) 46 | { 47 | TypesWriter tw = new TypesWriter(); 48 | tw.writeByte(Packets.SSH_MSG_IGNORE); 49 | 50 | if (data != null) 51 | tw.writeString(data, 0, data.length); 52 | else 53 | tw.writeString(""); 54 | 55 | payload = tw.getBytes(); 56 | } 57 | return payload; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketKexDHInit.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | /** 4 | * PacketKexDHInit. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: PacketKexDHInit.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 8 | */ 9 | public class PacketKexDHInit 10 | { 11 | byte[] payload; 12 | 13 | byte[] publicKey; 14 | 15 | public PacketKexDHInit(byte[] publicKey) 16 | { 17 | this.publicKey = publicKey; 18 | } 19 | 20 | public byte[] getPayload() 21 | { 22 | if (payload == null) 23 | { 24 | TypesWriter tw = new TypesWriter(); 25 | tw.writeByte(Packets.SSH_MSG_KEXDH_INIT); 26 | tw.writeString(publicKey, 0, publicKey.length); 27 | payload = tw.getBytes(); 28 | } 29 | return payload; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketKexDHReply.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketKexDHReply. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketKexDHReply.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketKexDHReply 12 | { 13 | byte[] payload; 14 | 15 | byte[] hostKey; 16 | byte[] publicKey; 17 | byte[] signature; 18 | 19 | public PacketKexDHReply(byte payload[], int off, int len) throws IOException 20 | { 21 | this.payload = new byte[len]; 22 | System.arraycopy(payload, off, this.payload, 0, len); 23 | 24 | TypesReader tr = new TypesReader(payload, off, len); 25 | 26 | int packet_type = tr.readByte(); 27 | 28 | if (packet_type != Packets.SSH_MSG_KEXDH_REPLY) 29 | throw new IOException("This is not a SSH_MSG_KEXDH_REPLY! (" 30 | + packet_type + ")"); 31 | 32 | hostKey = tr.readByteString(); 33 | publicKey = tr.readByteString(); 34 | signature = tr.readByteString(); 35 | 36 | if (tr.remain() != 0) throw new IOException("PADDING IN SSH_MSG_KEXDH_REPLY!"); 37 | } 38 | 39 | public byte[] getF() 40 | { 41 | return publicKey; 42 | } 43 | 44 | public byte[] getHostKey() 45 | { 46 | return hostKey; 47 | } 48 | 49 | public byte[] getSignature() 50 | { 51 | return signature; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketKexDhGexGroup.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | import java.math.BigInteger; 6 | 7 | /** 8 | * PacketKexDhGexGroup. 9 | * 10 | * @author Christian Plattner, plattner@trilead.com 11 | * @version $Id: PacketKexDhGexGroup.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 12 | */ 13 | public class PacketKexDhGexGroup 14 | { 15 | byte[] payload; 16 | 17 | BigInteger p; 18 | BigInteger g; 19 | 20 | public PacketKexDhGexGroup(byte payload[], int off, int len) throws IOException 21 | { 22 | this.payload = new byte[len]; 23 | System.arraycopy(payload, off, this.payload, 0, len); 24 | 25 | TypesReader tr = new TypesReader(payload, off, len); 26 | 27 | int packet_type = tr.readByte(); 28 | 29 | if (packet_type != Packets.SSH_MSG_KEX_DH_GEX_GROUP) 30 | throw new IllegalArgumentException( 31 | "This is not a SSH_MSG_KEX_DH_GEX_GROUP! (" + packet_type 32 | + ")"); 33 | 34 | p = tr.readMPINT(); 35 | g = tr.readMPINT(); 36 | 37 | if (tr.remain() != 0) 38 | throw new IOException("PADDING IN SSH_MSG_KEX_DH_GEX_GROUP!"); 39 | } 40 | 41 | public BigInteger getG() 42 | { 43 | return g; 44 | } 45 | 46 | public BigInteger getP() 47 | { 48 | return p; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketKexDhGexInit.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.math.BigInteger; 4 | 5 | /** 6 | * PacketKexDhGexInit. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketKexDhGexInit.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketKexDhGexInit 12 | { 13 | byte[] payload; 14 | 15 | BigInteger e; 16 | 17 | public PacketKexDhGexInit(BigInteger e) 18 | { 19 | this.e = e; 20 | } 21 | 22 | public byte[] getPayload() 23 | { 24 | if (payload == null) 25 | { 26 | TypesWriter tw = new TypesWriter(); 27 | tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_INIT); 28 | tw.writeMPInt(e); 29 | payload = tw.getBytes(); 30 | } 31 | return payload; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketKexDhGexReply.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | import java.math.BigInteger; 7 | 8 | /** 9 | * PacketKexDhGexReply. 10 | * 11 | * @author Christian Plattner, plattner@trilead.com 12 | * @version $Id: PacketKexDhGexReply.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 13 | */ 14 | public class PacketKexDhGexReply 15 | { 16 | byte[] payload; 17 | 18 | byte[] hostKey; 19 | BigInteger f; 20 | byte[] signature; 21 | 22 | public PacketKexDhGexReply(byte payload[], int off, int len) throws IOException 23 | { 24 | this.payload = new byte[len]; 25 | System.arraycopy(payload, off, this.payload, 0, len); 26 | 27 | TypesReader tr = new TypesReader(payload, off, len); 28 | 29 | int packet_type = tr.readByte(); 30 | 31 | if (packet_type != Packets.SSH_MSG_KEX_DH_GEX_REPLY) 32 | throw new IOException("This is not a SSH_MSG_KEX_DH_GEX_REPLY! (" + packet_type + ")"); 33 | 34 | hostKey = tr.readByteString(); 35 | f = tr.readMPINT(); 36 | signature = tr.readByteString(); 37 | 38 | if (tr.remain() != 0) 39 | throw new IOException("PADDING IN SSH_MSG_KEX_DH_GEX_REPLY!"); 40 | } 41 | 42 | public BigInteger getF() 43 | { 44 | return f; 45 | } 46 | 47 | public byte[] getHostKey() 48 | { 49 | return hostKey; 50 | } 51 | 52 | public byte[] getSignature() 53 | { 54 | return signature; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketKexDhGexRequest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import com.trilead.ssh2.DHGexParameters; 4 | 5 | /** 6 | * PacketKexDhGexRequest. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketKexDhGexRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketKexDhGexRequest 12 | { 13 | byte[] payload; 14 | 15 | int min; 16 | int n; 17 | int max; 18 | 19 | public PacketKexDhGexRequest(DHGexParameters para) 20 | { 21 | this.min = para.getMin_group_len(); 22 | this.n = para.getPref_group_len(); 23 | this.max = para.getMax_group_len(); 24 | } 25 | 26 | public byte[] getPayload() 27 | { 28 | if (payload == null) 29 | { 30 | TypesWriter tw = new TypesWriter(); 31 | tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_REQUEST); 32 | tw.writeUINT32(min); 33 | tw.writeUINT32(n); 34 | tw.writeUINT32(max); 35 | payload = tw.getBytes(); 36 | } 37 | return payload; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketKexDhGexRequestOld.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import com.trilead.ssh2.DHGexParameters; 5 | 6 | /** 7 | * PacketKexDhGexRequestOld. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketKexDhGexRequestOld.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketKexDhGexRequestOld 13 | { 14 | byte[] payload; 15 | 16 | int n; 17 | 18 | public PacketKexDhGexRequestOld(DHGexParameters para) 19 | { 20 | this.n = para.getPref_group_len(); 21 | } 22 | 23 | public byte[] getPayload() 24 | { 25 | if (payload == null) 26 | { 27 | TypesWriter tw = new TypesWriter(); 28 | tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_REQUEST_OLD); 29 | tw.writeUINT32(n); 30 | payload = tw.getBytes(); 31 | } 32 | return payload; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketNewKeys.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketNewKeys. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketNewKeys.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketNewKeys 12 | { 13 | byte[] payload; 14 | 15 | public PacketNewKeys() 16 | { 17 | } 18 | 19 | public PacketNewKeys(byte payload[], int off, int len) throws IOException 20 | { 21 | this.payload = new byte[len]; 22 | System.arraycopy(payload, off, this.payload, 0, len); 23 | 24 | TypesReader tr = new TypesReader(payload, off, len); 25 | 26 | int packet_type = tr.readByte(); 27 | 28 | if (packet_type != Packets.SSH_MSG_NEWKEYS) 29 | throw new IOException("This is not a SSH_MSG_NEWKEYS! (" 30 | + packet_type + ")"); 31 | 32 | if (tr.remain() != 0) 33 | throw new IOException("Padding in SSH_MSG_NEWKEYS packet!"); 34 | } 35 | 36 | public byte[] getPayload() 37 | { 38 | if (payload == null) 39 | { 40 | TypesWriter tw = new TypesWriter(); 41 | tw.writeByte(Packets.SSH_MSG_NEWKEYS); 42 | payload = tw.getBytes(); 43 | } 44 | return payload; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketOpenDirectTCPIPChannel.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | 4 | /** 5 | * PacketOpenDirectTCPIPChannel. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketOpenDirectTCPIPChannel.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketOpenDirectTCPIPChannel 11 | { 12 | byte[] payload; 13 | 14 | int channelID; 15 | int initialWindowSize; 16 | int maxPacketSize; 17 | 18 | String host_to_connect; 19 | int port_to_connect; 20 | String originator_IP_address; 21 | int originator_port; 22 | 23 | public PacketOpenDirectTCPIPChannel(int channelID, int initialWindowSize, int maxPacketSize, 24 | String host_to_connect, int port_to_connect, String originator_IP_address, 25 | int originator_port) 26 | { 27 | this.channelID = channelID; 28 | this.initialWindowSize = initialWindowSize; 29 | this.maxPacketSize = maxPacketSize; 30 | this.host_to_connect = host_to_connect; 31 | this.port_to_connect = port_to_connect; 32 | this.originator_IP_address = originator_IP_address; 33 | this.originator_port = originator_port; 34 | } 35 | 36 | public byte[] getPayload() 37 | { 38 | if (payload == null) 39 | { 40 | TypesWriter tw = new TypesWriter(); 41 | 42 | tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN); 43 | tw.writeString("direct-tcpip"); 44 | tw.writeUINT32(channelID); 45 | tw.writeUINT32(initialWindowSize); 46 | tw.writeUINT32(maxPacketSize); 47 | tw.writeString(host_to_connect); 48 | tw.writeUINT32(port_to_connect); 49 | tw.writeString(originator_IP_address); 50 | tw.writeUINT32(originator_port); 51 | 52 | payload = tw.getBytes(); 53 | } 54 | return payload; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketOpenSessionChannel.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketOpenSessionChannel. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketOpenSessionChannel.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketOpenSessionChannel 12 | { 13 | byte[] payload; 14 | 15 | int channelID; 16 | int initialWindowSize; 17 | int maxPacketSize; 18 | 19 | public PacketOpenSessionChannel(int channelID, int initialWindowSize, 20 | int maxPacketSize) 21 | { 22 | this.channelID = channelID; 23 | this.initialWindowSize = initialWindowSize; 24 | this.maxPacketSize = maxPacketSize; 25 | } 26 | 27 | public PacketOpenSessionChannel(byte payload[], int off, int len) throws IOException 28 | { 29 | this.payload = new byte[len]; 30 | System.arraycopy(payload, off, this.payload, 0, len); 31 | 32 | TypesReader tr = new TypesReader(payload); 33 | 34 | int packet_type = tr.readByte(); 35 | 36 | if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN) 37 | throw new IOException("This is not a SSH_MSG_CHANNEL_OPEN! (" 38 | + packet_type + ")"); 39 | 40 | channelID = tr.readUINT32(); 41 | initialWindowSize = tr.readUINT32(); 42 | maxPacketSize = tr.readUINT32(); 43 | 44 | if (tr.remain() != 0) 45 | throw new IOException("Padding in SSH_MSG_CHANNEL_OPEN packet!"); 46 | } 47 | 48 | public byte[] getPayload() 49 | { 50 | if (payload == null) 51 | { 52 | TypesWriter tw = new TypesWriter(); 53 | tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN); 54 | tw.writeString("session"); 55 | tw.writeUINT32(channelID); 56 | tw.writeUINT32(initialWindowSize); 57 | tw.writeUINT32(maxPacketSize); 58 | payload = tw.getBytes(); 59 | } 60 | return payload; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketServiceAccept.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketServiceAccept. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketServiceAccept.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ 11 | */ 12 | public class PacketServiceAccept 13 | { 14 | byte[] payload; 15 | 16 | String serviceName; 17 | 18 | public PacketServiceAccept(String serviceName) 19 | { 20 | this.serviceName = serviceName; 21 | } 22 | 23 | public PacketServiceAccept(byte payload[], int off, int len) throws IOException 24 | { 25 | this.payload = new byte[len]; 26 | System.arraycopy(payload, off, this.payload, 0, len); 27 | 28 | TypesReader tr = new TypesReader(payload, off, len); 29 | 30 | int packet_type = tr.readByte(); 31 | 32 | if (packet_type != Packets.SSH_MSG_SERVICE_ACCEPT) 33 | throw new IOException("This is not a SSH_MSG_SERVICE_ACCEPT! (" + packet_type + ")"); 34 | 35 | /* Be clever in case the server is not. Some servers seem to violate RFC4253 */ 36 | 37 | if (tr.remain() > 0) 38 | { 39 | serviceName = tr.readString(); 40 | } 41 | else 42 | { 43 | serviceName = ""; 44 | } 45 | 46 | if (tr.remain() != 0) 47 | throw new IOException("Padding in SSH_MSG_SERVICE_ACCEPT packet!"); 48 | } 49 | 50 | public byte[] getPayload() 51 | { 52 | if (payload == null) 53 | { 54 | TypesWriter tw = new TypesWriter(); 55 | tw.writeByte(Packets.SSH_MSG_SERVICE_ACCEPT); 56 | tw.writeString(serviceName); 57 | payload = tw.getBytes(); 58 | } 59 | return payload; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketServiceRequest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketServiceRequest. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketServiceRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketServiceRequest 12 | { 13 | byte[] payload; 14 | 15 | String serviceName; 16 | 17 | public PacketServiceRequest(String serviceName) 18 | { 19 | this.serviceName = serviceName; 20 | } 21 | 22 | public PacketServiceRequest(byte payload[], int off, int len) throws IOException 23 | { 24 | this.payload = new byte[len]; 25 | System.arraycopy(payload, off, this.payload, 0, len); 26 | 27 | TypesReader tr = new TypesReader(payload, off, len); 28 | 29 | int packet_type = tr.readByte(); 30 | 31 | if (packet_type != Packets.SSH_MSG_SERVICE_REQUEST) 32 | throw new IOException("This is not a SSH_MSG_SERVICE_REQUEST! (" 33 | + packet_type + ")"); 34 | 35 | serviceName = tr.readString(); 36 | 37 | if (tr.remain() != 0) 38 | throw new IOException("Padding in SSH_MSG_SERVICE_REQUEST packet!"); 39 | } 40 | 41 | public byte[] getPayload() 42 | { 43 | if (payload == null) 44 | { 45 | TypesWriter tw = new TypesWriter(); 46 | tw.writeByte(Packets.SSH_MSG_SERVICE_REQUEST); 47 | tw.writeString(serviceName); 48 | payload = tw.getBytes(); 49 | } 50 | return payload; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketSessionExecCommand.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | 4 | /** 5 | * PacketSessionExecCommand. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionExecCommand.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionExecCommand 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | public String command; 17 | 18 | public PacketSessionExecCommand(int recipientChannelID, boolean wantReply, String command) 19 | { 20 | this.recipientChannelID = recipientChannelID; 21 | this.wantReply = wantReply; 22 | this.command = command; 23 | } 24 | 25 | public byte[] getPayload() 26 | { 27 | if (payload == null) 28 | { 29 | TypesWriter tw = new TypesWriter(); 30 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 31 | tw.writeUINT32(recipientChannelID); 32 | tw.writeString("exec"); 33 | tw.writeBoolean(wantReply); 34 | tw.writeString(command); 35 | payload = tw.getBytes(); 36 | } 37 | return payload; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketSessionPtyRequest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | 4 | /** 5 | * PacketSessionPtyRequest. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionPtyRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionPtyRequest 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | public String term; 17 | public int character_width; 18 | public int character_height; 19 | public int pixel_width; 20 | public int pixel_height; 21 | public byte[] terminal_modes; 22 | 23 | public PacketSessionPtyRequest(int recipientChannelID, boolean wantReply, String term, 24 | int character_width, int character_height, int pixel_width, int pixel_height, 25 | byte[] terminal_modes) 26 | { 27 | this.recipientChannelID = recipientChannelID; 28 | this.wantReply = wantReply; 29 | this.term = term; 30 | this.character_width = character_width; 31 | this.character_height = character_height; 32 | this.pixel_width = pixel_width; 33 | this.pixel_height = pixel_height; 34 | this.terminal_modes = terminal_modes; 35 | } 36 | 37 | public byte[] getPayload() 38 | { 39 | if (payload == null) 40 | { 41 | TypesWriter tw = new TypesWriter(); 42 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 43 | tw.writeUINT32(recipientChannelID); 44 | tw.writeString("pty-req"); 45 | tw.writeBoolean(wantReply); 46 | tw.writeString(term); 47 | tw.writeUINT32(character_width); 48 | tw.writeUINT32(character_height); 49 | tw.writeUINT32(pixel_width); 50 | tw.writeUINT32(pixel_height); 51 | tw.writeString(terminal_modes, 0, terminal_modes.length); 52 | 53 | payload = tw.getBytes(); 54 | } 55 | return payload; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketSessionPtyResize.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | public class PacketSessionPtyResize { 4 | byte[] payload; 5 | 6 | public int recipientChannelID; 7 | public int width; 8 | public int height; 9 | public int pixelWidth; 10 | public int pixelHeight; 11 | 12 | public PacketSessionPtyResize(int recipientChannelID, int width, int height, int pixelWidth, int pixelHeight) { 13 | this.recipientChannelID = recipientChannelID; 14 | this.width = width; 15 | this.height = height; 16 | this.pixelWidth = pixelWidth; 17 | this.pixelHeight = pixelHeight; 18 | } 19 | 20 | public byte[] getPayload() 21 | { 22 | if (payload == null) 23 | { 24 | TypesWriter tw = new TypesWriter(); 25 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 26 | tw.writeUINT32(recipientChannelID); 27 | tw.writeString("window-change"); 28 | tw.writeBoolean(false); 29 | tw.writeUINT32(width); 30 | tw.writeUINT32(height); 31 | tw.writeUINT32(pixelWidth); 32 | tw.writeUINT32(pixelHeight); 33 | 34 | payload = tw.getBytes(); 35 | } 36 | return payload; 37 | } 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketSessionStartShell.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketSessionStartShell. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionStartShell.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionStartShell 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | 17 | public PacketSessionStartShell(int recipientChannelID, boolean wantReply) 18 | { 19 | this.recipientChannelID = recipientChannelID; 20 | this.wantReply = wantReply; 21 | } 22 | 23 | public byte[] getPayload() 24 | { 25 | if (payload == null) 26 | { 27 | TypesWriter tw = new TypesWriter(); 28 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 29 | tw.writeUINT32(recipientChannelID); 30 | tw.writeString("shell"); 31 | tw.writeBoolean(wantReply); 32 | payload = tw.getBytes(); 33 | } 34 | return payload; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketSessionSubsystemRequest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | 4 | /** 5 | * PacketSessionSubsystemRequest. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionSubsystemRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionSubsystemRequest 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | public String subsystem; 17 | 18 | public PacketSessionSubsystemRequest(int recipientChannelID, boolean wantReply, String subsystem) 19 | { 20 | this.recipientChannelID = recipientChannelID; 21 | this.wantReply = wantReply; 22 | this.subsystem = subsystem; 23 | } 24 | 25 | public byte[] getPayload() 26 | { 27 | if (payload == null) 28 | { 29 | TypesWriter tw = new TypesWriter(); 30 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 31 | tw.writeUINT32(recipientChannelID); 32 | tw.writeString("subsystem"); 33 | tw.writeBoolean(wantReply); 34 | tw.writeString(subsystem); 35 | payload = tw.getBytes(); 36 | tw.getBytes(payload); 37 | } 38 | return payload; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketSessionX11Request.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketSessionX11Request. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionX11Request.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionX11Request 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | 17 | public boolean singleConnection; 18 | String x11AuthenticationProtocol; 19 | String x11AuthenticationCookie; 20 | int x11ScreenNumber; 21 | 22 | public PacketSessionX11Request(int recipientChannelID, boolean wantReply, boolean singleConnection, 23 | String x11AuthenticationProtocol, String x11AuthenticationCookie, int x11ScreenNumber) 24 | { 25 | this.recipientChannelID = recipientChannelID; 26 | this.wantReply = wantReply; 27 | 28 | this.singleConnection = singleConnection; 29 | this.x11AuthenticationProtocol = x11AuthenticationProtocol; 30 | this.x11AuthenticationCookie = x11AuthenticationCookie; 31 | this.x11ScreenNumber = x11ScreenNumber; 32 | } 33 | 34 | public byte[] getPayload() 35 | { 36 | if (payload == null) 37 | { 38 | TypesWriter tw = new TypesWriter(); 39 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 40 | tw.writeUINT32(recipientChannelID); 41 | tw.writeString("x11-req"); 42 | tw.writeBoolean(wantReply); 43 | 44 | tw.writeBoolean(singleConnection); 45 | tw.writeString(x11AuthenticationProtocol); 46 | tw.writeString(x11AuthenticationCookie); 47 | tw.writeUINT32(x11ScreenNumber); 48 | 49 | payload = tw.getBytes(); 50 | } 51 | return payload; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketUserauthBanner.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketUserauthBanner. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketUserauthBanner.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketUserauthBanner 12 | { 13 | byte[] payload; 14 | 15 | String message; 16 | String language; 17 | 18 | public PacketUserauthBanner(String message, String language) 19 | { 20 | this.message = message; 21 | this.language = language; 22 | } 23 | 24 | public String getBanner() 25 | { 26 | return message; 27 | } 28 | 29 | public PacketUserauthBanner(byte payload[], int off, int len) throws IOException 30 | { 31 | this.payload = new byte[len]; 32 | System.arraycopy(payload, off, this.payload, 0, len); 33 | 34 | TypesReader tr = new TypesReader(payload, off, len); 35 | 36 | int packet_type = tr.readByte(); 37 | 38 | if (packet_type != Packets.SSH_MSG_USERAUTH_BANNER) 39 | throw new IOException("This is not a SSH_MSG_USERAUTH_BANNER! (" + packet_type + ")"); 40 | 41 | message = tr.readString("UTF-8"); 42 | language = tr.readString(); 43 | 44 | if (tr.remain() != 0) 45 | throw new IOException("Padding in SSH_MSG_USERAUTH_REQUEST packet!"); 46 | } 47 | 48 | public byte[] getPayload() 49 | { 50 | if (payload == null) 51 | { 52 | TypesWriter tw = new TypesWriter(); 53 | tw.writeByte(Packets.SSH_MSG_USERAUTH_BANNER); 54 | tw.writeString(message); 55 | tw.writeString(language); 56 | payload = tw.getBytes(); 57 | } 58 | return payload; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketUserauthFailure.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketUserauthBanner. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketUserauthFailure.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketUserauthFailure 13 | { 14 | byte[] payload; 15 | 16 | String[] authThatCanContinue; 17 | boolean partialSuccess; 18 | 19 | public PacketUserauthFailure(String[] authThatCanContinue, boolean partialSuccess) 20 | { 21 | this.authThatCanContinue = authThatCanContinue; 22 | this.partialSuccess = partialSuccess; 23 | } 24 | 25 | public PacketUserauthFailure(byte payload[], int off, int len) throws IOException 26 | { 27 | this.payload = new byte[len]; 28 | System.arraycopy(payload, off, this.payload, 0, len); 29 | 30 | TypesReader tr = new TypesReader(payload, off, len); 31 | 32 | int packet_type = tr.readByte(); 33 | 34 | if (packet_type != Packets.SSH_MSG_USERAUTH_FAILURE) 35 | throw new IOException("This is not a SSH_MSG_USERAUTH_FAILURE! (" + packet_type + ")"); 36 | 37 | authThatCanContinue = tr.readNameList(); 38 | partialSuccess = tr.readBoolean(); 39 | 40 | if (tr.remain() != 0) 41 | throw new IOException("Padding in SSH_MSG_USERAUTH_FAILURE packet!"); 42 | } 43 | 44 | public String[] getAuthThatCanContinue() 45 | { 46 | return authThatCanContinue; 47 | } 48 | 49 | public boolean isPartialSuccess() 50 | { 51 | return partialSuccess; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketUserauthInfoRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketUserauthInfoRequest. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketUserauthInfoRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketUserauthInfoRequest 13 | { 14 | byte[] payload; 15 | 16 | String name; 17 | String instruction; 18 | String languageTag; 19 | int numPrompts; 20 | 21 | String prompt[]; 22 | boolean echo[]; 23 | 24 | public PacketUserauthInfoRequest(byte payload[], int off, int len) throws IOException 25 | { 26 | this.payload = new byte[len]; 27 | System.arraycopy(payload, off, this.payload, 0, len); 28 | 29 | TypesReader tr = new TypesReader(payload, off, len); 30 | 31 | int packet_type = tr.readByte(); 32 | 33 | if (packet_type != Packets.SSH_MSG_USERAUTH_INFO_REQUEST) 34 | throw new IOException("This is not a SSH_MSG_USERAUTH_INFO_REQUEST! (" + packet_type + ")"); 35 | 36 | name = tr.readString(); 37 | instruction = tr.readString(); 38 | languageTag = tr.readString(); 39 | 40 | numPrompts = tr.readUINT32(); 41 | 42 | prompt = new String[numPrompts]; 43 | echo = new boolean[numPrompts]; 44 | 45 | for (int i = 0; i < numPrompts; i++) 46 | { 47 | prompt[i] = tr.readString(); 48 | echo[i] = tr.readBoolean(); 49 | } 50 | 51 | if (tr.remain() != 0) 52 | throw new IOException("Padding in SSH_MSG_USERAUTH_INFO_REQUEST packet!"); 53 | } 54 | 55 | public boolean[] getEcho() 56 | { 57 | return echo; 58 | } 59 | 60 | public String getInstruction() 61 | { 62 | return instruction; 63 | } 64 | 65 | public String getLanguageTag() 66 | { 67 | return languageTag; 68 | } 69 | 70 | public String getName() 71 | { 72 | return name; 73 | } 74 | 75 | public int getNumPrompts() 76 | { 77 | return numPrompts; 78 | } 79 | 80 | public String[] getPrompt() 81 | { 82 | return prompt; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketUserauthInfoResponse.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketUserauthInfoResponse. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketUserauthInfoResponse.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketUserauthInfoResponse 11 | { 12 | byte[] payload; 13 | 14 | String[] responses; 15 | 16 | public PacketUserauthInfoResponse(String[] responses) 17 | { 18 | this.responses = responses; 19 | } 20 | 21 | public byte[] getPayload() 22 | { 23 | if (payload == null) 24 | { 25 | TypesWriter tw = new TypesWriter(); 26 | tw.writeByte(Packets.SSH_MSG_USERAUTH_INFO_RESPONSE); 27 | tw.writeUINT32(responses.length); 28 | for (int i = 0; i < responses.length; i++) 29 | tw.writeString(responses[i]); 30 | 31 | payload = tw.getBytes(); 32 | } 33 | return payload; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketUserauthRequestInteractive.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.UnsupportedEncodingException; 5 | 6 | /** 7 | * PacketUserauthRequestInteractive. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketUserauthRequestInteractive.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketUserauthRequestInteractive 13 | { 14 | byte[] payload; 15 | 16 | String userName; 17 | String serviceName; 18 | String[] submethods; 19 | 20 | public PacketUserauthRequestInteractive(String serviceName, String user, String[] submethods) 21 | { 22 | this.serviceName = serviceName; 23 | this.userName = user; 24 | this.submethods = submethods; 25 | } 26 | 27 | public byte[] getPayload() throws UnsupportedEncodingException { 28 | if (payload == null) 29 | { 30 | TypesWriter tw = new TypesWriter(); 31 | tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); 32 | tw.writeString(userName, "UTF-8"); 33 | tw.writeString(serviceName); 34 | tw.writeString("keyboard-interactive"); 35 | tw.writeString(""); // draft-ietf-secsh-newmodes-04.txt says that 36 | // the language tag should be empty. 37 | tw.writeNameList(submethods); 38 | 39 | payload = tw.getBytes(); 40 | } 41 | return payload; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketUserauthRequestNone.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | import java.io.UnsupportedEncodingException; 5 | 6 | /** 7 | * PacketUserauthRequestPassword. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketUserauthRequestNone.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketUserauthRequestNone 13 | { 14 | byte[] payload; 15 | 16 | String userName; 17 | String serviceName; 18 | 19 | public PacketUserauthRequestNone(String serviceName, String user) 20 | { 21 | this.serviceName = serviceName; 22 | this.userName = user; 23 | } 24 | 25 | public PacketUserauthRequestNone(byte payload[], int off, int len) throws IOException 26 | { 27 | this.payload = new byte[len]; 28 | System.arraycopy(payload, off, this.payload, 0, len); 29 | 30 | TypesReader tr = new TypesReader(payload, off, len); 31 | 32 | int packet_type = tr.readByte(); 33 | 34 | if (packet_type != Packets.SSH_MSG_USERAUTH_REQUEST) 35 | throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST! (" + packet_type + ")"); 36 | 37 | userName = tr.readString(); 38 | serviceName = tr.readString(); 39 | 40 | String method = tr.readString(); 41 | 42 | if (!method.equals("none")) 43 | throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST with type none!"); 44 | 45 | if (tr.remain() != 0) 46 | throw new IOException("Padding in SSH_MSG_USERAUTH_REQUEST packet!"); 47 | } 48 | 49 | public byte[] getPayload() throws UnsupportedEncodingException { 50 | if (payload == null) 51 | { 52 | TypesWriter tw = new TypesWriter(); 53 | tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); 54 | tw.writeString(userName, "UTF-8"); 55 | tw.writeString(serviceName); 56 | tw.writeString("none"); 57 | payload = tw.getBytes(); 58 | } 59 | return payload; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketUserauthRequestPassword.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | import java.io.UnsupportedEncodingException; 5 | 6 | /** 7 | * PacketUserauthRequestPassword. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketUserauthRequestPassword.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketUserauthRequestPassword 13 | { 14 | byte[] payload; 15 | 16 | String userName; 17 | String serviceName; 18 | String password; 19 | 20 | public PacketUserauthRequestPassword(String serviceName, String user, String pass) 21 | { 22 | this.serviceName = serviceName; 23 | this.userName = user; 24 | this.password = pass; 25 | } 26 | 27 | public PacketUserauthRequestPassword(byte payload[], int off, int len) throws IOException 28 | { 29 | this.payload = new byte[len]; 30 | System.arraycopy(payload, off, this.payload, 0, len); 31 | 32 | TypesReader tr = new TypesReader(payload, off, len); 33 | 34 | int packet_type = tr.readByte(); 35 | 36 | if (packet_type != Packets.SSH_MSG_USERAUTH_REQUEST) 37 | throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST! (" + packet_type + ")"); 38 | 39 | userName = tr.readString(); 40 | serviceName = tr.readString(); 41 | 42 | String method = tr.readString(); 43 | 44 | if (!method.equals("password")) 45 | throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST with type password!"); 46 | 47 | /* ... */ 48 | 49 | if (tr.remain() != 0) 50 | throw new IOException("Padding in SSH_MSG_USERAUTH_REQUEST packet!"); 51 | } 52 | 53 | public byte[] getPayload() throws UnsupportedEncodingException { 54 | if (payload == null) 55 | { 56 | TypesWriter tw = new TypesWriter(); 57 | tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); 58 | tw.writeString(userName, "UTF-8"); 59 | tw.writeString(serviceName); 60 | tw.writeString("password"); 61 | tw.writeBoolean(false); 62 | tw.writeString(password, "UTF-8"); 63 | payload = tw.getBytes(); 64 | } 65 | return payload; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/packets/PacketUserauthRequestPublicKey.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | import java.io.UnsupportedEncodingException; 5 | 6 | /** 7 | * PacketUserauthRequestPublicKey. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketUserauthRequestPublicKey.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketUserauthRequestPublicKey 13 | { 14 | byte[] payload; 15 | 16 | String userName; 17 | String serviceName; 18 | String password; 19 | String pkAlgoName; 20 | byte[] pk; 21 | byte[] sig; 22 | 23 | public PacketUserauthRequestPublicKey(String serviceName, String user, 24 | String pkAlgorithmName, byte[] pk, byte[] sig) 25 | { 26 | this.serviceName = serviceName; 27 | this.userName = user; 28 | this.pkAlgoName = pkAlgorithmName; 29 | this.pk = pk; 30 | this.sig = sig; 31 | } 32 | 33 | public PacketUserauthRequestPublicKey(byte payload[], int off, int len) throws IOException 34 | { 35 | this.payload = new byte[len]; 36 | System.arraycopy(payload, off, this.payload, 0, len); 37 | 38 | TypesReader tr = new TypesReader(payload, off, len); 39 | 40 | int packet_type = tr.readByte(); 41 | 42 | if (packet_type != Packets.SSH_MSG_USERAUTH_REQUEST) 43 | throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST! (" 44 | + packet_type + ")"); 45 | 46 | throw new IOException("Not implemented!"); 47 | } 48 | 49 | public byte[] getPayload() throws UnsupportedEncodingException { 50 | if (payload == null) 51 | { 52 | TypesWriter tw = new TypesWriter(); 53 | tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); 54 | tw.writeString(userName, "UTF-8"); 55 | tw.writeString(serviceName); 56 | tw.writeString("publickey"); 57 | tw.writeBoolean(true); 58 | tw.writeString(pkAlgoName); 59 | tw.writeString(pk, 0, pk.length); 60 | tw.writeString(sig, 0, sig.length); 61 | payload = tw.getBytes(); 62 | } 63 | return payload; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/sftp/AttrTextHints.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.sftp; 3 | 4 | /** 5 | * 6 | * Values for the 'text-hint' field in the SFTP ATTRS data type. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: AttrTextHints.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | * 11 | */ 12 | public class AttrTextHints 13 | { 14 | /** 15 | * The server knows the file is a text file, and should be opened 16 | * using the SSH_FXF_ACCESS_TEXT_MODE flag. 17 | */ 18 | public static final int SSH_FILEXFER_ATTR_KNOWN_TEXT = 0x00; 19 | 20 | /** 21 | * The server has applied a heuristic or other mechanism and 22 | * believes that the file should be opened with the 23 | * SSH_FXF_ACCESS_TEXT_MODE flag. 24 | */ 25 | public static final int SSH_FILEXFER_ATTR_GUESSED_TEXT = 0x01; 26 | 27 | /** 28 | * The server knows the file has binary content. 29 | */ 30 | public static final int SSH_FILEXFER_ATTR_KNOWN_BINARY = 0x02; 31 | 32 | /** 33 | * The server has applied a heuristic or other mechanism and 34 | * believes has binary content, and should not be opened with the 35 | * SSH_FXF_ACCESS_TEXT_MODE flag. 36 | */ 37 | public static final int SSH_FILEXFER_ATTR_GUESSED_BINARY = 0x03; 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/sftp/AttribPermissions.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.sftp; 3 | 4 | /** 5 | * 6 | * Permissions for the 'permissions' field in the SFTP ATTRS data type. 7 | *

8 | * "The 'permissions' field contains a bit mask specifying file permissions. 9 | * These permissions correspond to the st_mode field of the stat structure 10 | * defined by POSIX [IEEE.1003-1.1996]." 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: AttribPermissions.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 14 | * 15 | */ 16 | public class AttribPermissions 17 | { 18 | /* Octal values! */ 19 | 20 | public static final int S_IRUSR = 0400; 21 | public static final int S_IWUSR = 0200; 22 | public static final int S_IXUSR = 0100; 23 | public static final int S_IRGRP = 0040; 24 | public static final int S_IWGRP = 0020; 25 | public static final int S_IXGRP = 0010; 26 | public static final int S_IROTH = 0004; 27 | public static final int S_IWOTH = 0002; 28 | public static final int S_IXOTH = 0001; 29 | public static final int S_ISUID = 04000; 30 | public static final int S_ISGID = 02000; 31 | public static final int S_ISVTX = 01000; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/sftp/AttribTypes.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.sftp; 3 | 4 | /** 5 | * 6 | * Types for the 'type' field in the SFTP ATTRS data type. 7 | *

8 | * "On a POSIX system, these values would be derived from the mode field 9 | * of the stat structure. SPECIAL should be used for files that are of 10 | * a known type which cannot be expressed in the protocol. UNKNOWN 11 | * should be used if the type is not known." 12 | * 13 | * @author Christian Plattner, plattner@trilead.com 14 | * @version $Id: AttribTypes.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 15 | * 16 | */ 17 | public class AttribTypes 18 | { 19 | public static final int SSH_FILEXFER_TYPE_REGULAR = 1; 20 | public static final int SSH_FILEXFER_TYPE_DIRECTORY = 2; 21 | public static final int SSH_FILEXFER_TYPE_SYMLINK = 3; 22 | public static final int SSH_FILEXFER_TYPE_SPECIAL = 4; 23 | public static final int SSH_FILEXFER_TYPE_UNKNOWN = 5; 24 | public static final int SSH_FILEXFER_TYPE_SOCKET = 6; 25 | public static final int SSH_FILEXFER_TYPE_CHAR_DEVICE = 7; 26 | public static final int SSH_FILEXFER_TYPE_BLOCK_DEVICE = 8; 27 | public static final int SSH_FILEXFER_TYPE_FIFO = 9; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/sftp/Packet.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.sftp; 3 | 4 | /** 5 | * 6 | * SFTP Paket Types 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: Packet.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | * 11 | */ 12 | public class Packet 13 | { 14 | public static final int SSH_FXP_INIT = 1; 15 | public static final int SSH_FXP_VERSION = 2; 16 | public static final int SSH_FXP_OPEN = 3; 17 | public static final int SSH_FXP_CLOSE = 4; 18 | public static final int SSH_FXP_READ = 5; 19 | public static final int SSH_FXP_WRITE = 6; 20 | public static final int SSH_FXP_LSTAT = 7; 21 | public static final int SSH_FXP_FSTAT = 8; 22 | public static final int SSH_FXP_SETSTAT = 9; 23 | public static final int SSH_FXP_FSETSTAT = 10; 24 | public static final int SSH_FXP_OPENDIR = 11; 25 | public static final int SSH_FXP_READDIR = 12; 26 | public static final int SSH_FXP_REMOVE = 13; 27 | public static final int SSH_FXP_MKDIR = 14; 28 | public static final int SSH_FXP_RMDIR = 15; 29 | public static final int SSH_FXP_REALPATH = 16; 30 | public static final int SSH_FXP_STAT = 17; 31 | public static final int SSH_FXP_RENAME = 18; 32 | public static final int SSH_FXP_READLINK = 19; 33 | public static final int SSH_FXP_SYMLINK = 20; 34 | 35 | public static final int SSH_FXP_STATUS = 101; 36 | public static final int SSH_FXP_HANDLE = 102; 37 | public static final int SSH_FXP_DATA = 103; 38 | public static final int SSH_FXP_NAME = 104; 39 | public static final int SSH_FXP_ATTRS = 105; 40 | 41 | public static final int SSH_FXP_EXTENDED = 200; 42 | public static final int SSH_FXP_EXTENDED_REPLY = 201; 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/signature/SSHSignature.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.signature; 2 | 3 | import java.io.IOException; 4 | import java.security.PrivateKey; 5 | import java.security.PublicKey; 6 | import java.security.SecureRandom; 7 | 8 | public interface SSHSignature { 9 | /** Returns the supported signature formats. */ 10 | String getKeyFormat(); 11 | 12 | /** Decode from SSH specification key to Java public key. */ 13 | PublicKey decodePublicKey(byte[] encoded) throws IOException; 14 | 15 | /** Encode from Java public key to SSH specification. */ 16 | byte[] encodePublicKey(PublicKey publicKey) throws IOException; 17 | 18 | /** Verifies a SSH-format signature for a given key. */ 19 | boolean verifySignature(byte[] message, byte[] signature, PublicKey publicKey) throws IOException; 20 | 21 | /** Generate an SSH-format signature for the message and private key. */ 22 | byte[] generateSignature(byte[] message, PrivateKey privateKey, SecureRandom secureRandom) throws IOException; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/transport/KexParameters.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | /** 4 | * KexParameters. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: KexParameters.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 8 | */ 9 | public class KexParameters 10 | { 11 | public byte[] cookie; 12 | public String[] kex_algorithms; 13 | public String[] server_host_key_algorithms; 14 | public String[] encryption_algorithms_client_to_server; 15 | public String[] encryption_algorithms_server_to_client; 16 | public String[] mac_algorithms_client_to_server; 17 | public String[] mac_algorithms_server_to_client; 18 | public String[] compression_algorithms_client_to_server; 19 | public String[] compression_algorithms_server_to_client; 20 | public String[] languages_client_to_server; 21 | public String[] languages_server_to_client; 22 | public boolean first_kex_packet_follows; 23 | public int reserved_field1; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/transport/KexState.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | 4 | import java.math.BigInteger; 5 | 6 | import com.trilead.ssh2.DHGexParameters; 7 | import com.trilead.ssh2.crypto.dh.DhGroupExchange; 8 | import com.trilead.ssh2.crypto.dh.GenericDhExchange; 9 | import com.trilead.ssh2.packets.PacketKexInit; 10 | 11 | /** 12 | * KexState. 13 | * 14 | * @author Christian Plattner, plattner@trilead.com 15 | * @version $Id: KexState.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 16 | */ 17 | public class KexState 18 | { 19 | public PacketKexInit localKEX; 20 | public PacketKexInit remoteKEX; 21 | public NegotiatedParameters np; 22 | public int state = 0; 23 | 24 | public BigInteger K; 25 | public byte[] H; 26 | 27 | public byte[] hostkey; 28 | 29 | public String hashAlgo; 30 | public GenericDhExchange dhx; 31 | public DhGroupExchange dhgx; 32 | public DHGexParameters dhgexParameters; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/transport/MessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * MessageHandler. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: MessageHandler.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 10 | */ 11 | public interface MessageHandler 12 | { 13 | void handleMessage(byte[] msg, int msglen) throws IOException; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/transport/NegotiateException.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | /** 4 | * NegotiateException. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: NegotiateException.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 8 | */ 9 | public class NegotiateException extends Exception 10 | { 11 | private static final long serialVersionUID = 3689910669428143157L; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/transport/NegotiatedParameters.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | /** 4 | * NegotiatedParameters. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: NegotiatedParameters.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 8 | */ 9 | public class NegotiatedParameters 10 | { 11 | public boolean guessOK; 12 | public boolean isStrictKex; 13 | public String kex_algo; 14 | public String server_host_key_algo; 15 | public String enc_algo_client_to_server; 16 | public String enc_algo_server_to_client; 17 | public String mac_algo_client_to_server; 18 | public String mac_algo_server_to_client; 19 | public String comp_algo_client_to_server; 20 | public String comp_algo_server_to_client; 21 | public String lang_client_to_server; 22 | public String lang_server_to_client; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/trilead/ssh2/util/Tokenizer.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.util; 3 | 4 | /** 5 | * Tokenizer. Why? Because StringTokenizer is not available in J2ME. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: Tokenizer.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 9 | */ 10 | public class Tokenizer 11 | { 12 | /** 13 | * Exists because StringTokenizer is not available in J2ME. 14 | * Returns an array with at least 1 entry. 15 | * 16 | * @param source must be non-null 17 | * @param delimiter 18 | * @return an array of Strings 19 | */ 20 | public static String[] parseTokens(String source, char delimiter) 21 | { 22 | if (source.length() == 0) 23 | return new String[0]; 24 | 25 | int numtoken = 1; 26 | 27 | for (int i = 0; i < source.length(); i++) { 28 | if (source.charAt(i) == delimiter) 29 | numtoken++; 30 | } 31 | 32 | String[] list = new String[numtoken]; 33 | int nextfield = 0; 34 | 35 | for (int i = 0; i < numtoken; i++) { 36 | if (nextfield >= source.length()) { 37 | list[i] = ""; 38 | } else { 39 | int idx = source.indexOf(delimiter, nextfield); 40 | if (idx == -1) 41 | idx = source.length(); 42 | list[i] = source.substring(nextfield, idx); 43 | nextfield = idx + 1; 44 | } 45 | } 46 | 47 | return list; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/ExtensionInfoTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import com.trilead.ssh2.packets.PacketExtInfo; 4 | import org.junit.Test; 5 | 6 | import java.util.Collections; 7 | import java.util.Set; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertTrue; 11 | 12 | public class ExtensionInfoTest { 13 | @Test 14 | public void fromPacketExtInfo_NoArgs_NoAlgs() { 15 | PacketExtInfo packet = new PacketExtInfo(Collections.emptyMap()); 16 | ExtensionInfo extInfo = ExtensionInfo.fromPacketExtInfo(packet); 17 | assertTrue(extInfo.getSignatureAlgorithmsAccepted().isEmpty()); 18 | } 19 | 20 | @Test 21 | public void noExtInfoSeen_HasNoSigAlgs() { 22 | ExtensionInfo noExtInfo = ExtensionInfo.noExtInfoSeen(); 23 | assertTrue(noExtInfo.getSignatureAlgorithmsAccepted().isEmpty()); 24 | } 25 | 26 | @Test 27 | public void parsesSigAlgs() { 28 | PacketExtInfo packet = new PacketExtInfo(Collections.singletonMap("server-sig-algs", "rsa-sha2-256,rsa-sha2-512")); 29 | ExtensionInfo extInfo = ExtensionInfo.fromPacketExtInfo(packet); 30 | 31 | Set sigAlgs = extInfo.getSignatureAlgorithmsAccepted(); 32 | assertEquals(2, sigAlgs.size()); 33 | assertTrue(sigAlgs.contains("rsa-sha2-256")); 34 | assertTrue(sigAlgs.contains("rsa-sha2-512")); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/PubkeyConstants.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | public class PubkeyConstants { 4 | private PubkeyConstants() { 5 | } 6 | 7 | static final String[] KEY_NAMES = { 8 | "ecdsa-nistp256-openssh2-private-key.txt.pub", 9 | "ecdsa-nistp384-openssh2-private-key.txt.pub", 10 | "ecdsa-nistp521-openssh2-private-key.txt.pub", 11 | "ed25519-openssh2-private-key.txt.pub", 12 | "rsa-openssh2-private-key.txt.pub", 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/SshLogger.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import org.junit.rules.ExternalResource; 4 | import org.slf4j.Logger; 5 | 6 | public class SshLogger extends ExternalResource { 7 | private final Logger logger; 8 | 9 | private DebugLogger oldLogger; 10 | private boolean oldEnabled; 11 | 12 | SshLogger(Logger logger) { 13 | this.logger = logger; 14 | } 15 | 16 | @Override 17 | protected void before() throws Throwable { 18 | oldEnabled = com.trilead.ssh2.log.Logger.enabled; 19 | oldLogger = com.trilead.ssh2.log.Logger.logger; 20 | 21 | com.trilead.ssh2.log.Logger.enabled = true; 22 | com.trilead.ssh2.log.Logger.logger = (level, className, message) -> logger.info("[SSHLIB] " + message); 23 | } 24 | 25 | @Override 26 | protected void after() { 27 | com.trilead.ssh2.log.Logger.enabled = oldEnabled; 28 | com.trilead.ssh2.log.Logger.logger = oldLogger; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/TestExtendedHostKeyVerifier.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import java.io.IOException; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.logging.Level; 7 | import java.util.logging.Logger; 8 | 9 | import static org.junit.Assert.fail; 10 | 11 | public class TestExtendedHostKeyVerifier extends ExtendedServerHostKeyVerifier { 12 | private final Logger logger = Logger.getLogger("TestHostKeyVerifier"); 13 | private final KnownHosts knownHosts = new KnownHosts(); 14 | 15 | @Override 16 | public List getKnownKeyAlgorithmsForHost(String hostname, int port) { 17 | String[] algorithms = knownHosts.getPreferredServerHostkeyAlgorithmOrder(hostname); 18 | if (algorithms == null) 19 | return null; 20 | return Arrays.asList(algorithms); 21 | } 22 | 23 | @Override 24 | public void removeServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey) { 25 | throw new UnsupportedOperationException(); 26 | } 27 | 28 | @Override 29 | public void addServerHostKey(String hostname, int port, String keyAlgorithm, byte[] serverHostKey) { 30 | try { 31 | knownHosts.addHostkey(new String[]{hostname}, keyAlgorithm, serverHostKey); 32 | } catch (IOException e) { 33 | fail("Could not add host key"); 34 | } 35 | } 36 | 37 | @Override 38 | public boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey) throws Exception { 39 | try { 40 | int resultCode = knownHosts.verifyHostkey(hostname, serverHostKeyAlgorithm, serverHostKey); 41 | if (resultCode == KnownHosts.HOSTKEY_IS_OK) { 42 | logger.log(Level.INFO, "Verified host key of type " + serverHostKeyAlgorithm); 43 | return true; 44 | } else if (resultCode == KnownHosts.HOSTKEY_IS_NEW) { 45 | logger.log(Level.INFO, "New host key of type " + serverHostKeyAlgorithm); 46 | return true; 47 | } 48 | } catch (IOException e) { 49 | fail("Could not verify host key"); 50 | } 51 | return false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/compression/CompressionFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.compression; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Collections; 6 | 7 | import static org.junit.Assert.assertNotNull; 8 | import static org.junit.Assert.assertNull; 9 | import static org.junit.Assert.assertTrue; 10 | 11 | public class CompressionFactoryTest { 12 | @Test 13 | public void getDefaultCompressors_Success() { 14 | assertTrue(CompressionFactory.getDefaultCompressorList().length > 0); 15 | } 16 | 17 | @Test(expected = IllegalArgumentException.class) 18 | public void brokenCompressor_Failure() { 19 | CompressionFactory.addCompressor("fake", "class.fake"); 20 | CompressionFactory.createCompressor("fake"); 21 | } 22 | 23 | @Test 24 | public void noneCompressorCreatesNull_Success() { 25 | assertNull(CompressionFactory.createCompressor("none")); 26 | } 27 | 28 | @Test 29 | public void realCompressor_Success() { 30 | assertNotNull(CompressionFactory.createCompressor("zlib")); 31 | } 32 | 33 | @Test(expected = IllegalArgumentException.class) 34 | public void invalidCompressor_Failure() { 35 | CompressionFactory.checkCompressorList(Collections.singletonList("broken").toArray(new String[1])); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/crypto/PEMDecoderTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto; 2 | 3 | import org.apache.commons.io.IOUtils; 4 | import org.junit.Test; 5 | 6 | import java.io.IOException; 7 | import java.security.KeyPair; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | /** 12 | * @author Michael Clarke 13 | */ 14 | public class PEMDecoderTest { 15 | private char[] getPem(String s) throws IOException { 16 | return IOUtils.toCharArray(getClass().getResourceAsStream(s), "UTF-8"); 17 | } 18 | 19 | @Test 20 | public void testRsaKeyDecodingTest() throws IOException { 21 | KeyPair expected = PEMDecoder.decode(getPem("rsa-private-key.txt"), null); 22 | KeyPair actual = PEMDecoder.decode(getPem("rsa-openssh2-private-key.txt"), "password"); 23 | 24 | assertEquals(expected.getPrivate(), actual.getPrivate()); 25 | assertEquals(expected.getPublic(), actual.getPublic()); 26 | } 27 | 28 | @Test 29 | public void testDsaKeyDecodingTest() throws IOException { 30 | KeyPair oldFormat = PEMDecoder.decode(getPem("dsa-private-key.txt"), null); 31 | KeyPair newFormat = PEMDecoder.decode(getPem("dsa-openssh2-private-key.txt"), null); 32 | 33 | assertEquals(oldFormat.getPublic(), newFormat.getPublic()); 34 | assertEquals(oldFormat.getPrivate(), newFormat.getPrivate()); 35 | } 36 | 37 | @Test 38 | public void testEcdsaNistp256KeyDecodingTest() throws IOException { 39 | KeyPair oldFormat = PEMDecoder.decode(getPem("ecdsa-nistp256-private-key.txt"), null); 40 | KeyPair newFormat = PEMDecoder.decode(getPem("ecdsa-nistp256-openssh2-private-key.txt"), null); 41 | 42 | assertEquals(oldFormat.getPublic(), newFormat.getPublic()); 43 | assertEquals(oldFormat.getPrivate(), newFormat.getPrivate()); 44 | } 45 | 46 | @Test 47 | public void testEcdsaNistp384KeyDecodingTest() throws IOException { 48 | KeyPair oldFormat = PEMDecoder.decode(getPem("ecdsa-nistp384-private-key.txt"), null); 49 | KeyPair newFormat = PEMDecoder.decode(getPem("ecdsa-nistp384-openssh2-private-key.txt"), null); 50 | 51 | assertEquals(oldFormat.getPublic(), newFormat.getPublic()); 52 | assertEquals(oldFormat.getPrivate(), newFormat.getPrivate()); 53 | } 54 | 55 | @Test 56 | public void testEcdsaNistp521KeyDecodingTest() throws IOException { 57 | KeyPair oldFormat = PEMDecoder.decode(getPem("ecdsa-nistp521-private-key.txt"), null); 58 | KeyPair newFormat = PEMDecoder.decode(getPem("ecdsa-nistp521-openssh2-private-key.txt"), null); 59 | 60 | assertEquals(oldFormat.getPublic(), newFormat.getPublic()); 61 | assertEquals(oldFormat.getPrivate(), newFormat.getPrivate()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/crypto/cipher/AESCBCTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Testing composed AES-CBC mode. 7 | *

8 | * Test vectors from 9 | * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CBC.pdf 10 | */ 11 | public class AESCBCTest extends AESTest { 12 | private final byte[] iv = toBytes("000102030405060708090A0B0C0D0E0F"); 13 | 14 | @Override 15 | BlockCipher getCipher(boolean forEncrypt, byte[] iv, byte[] key) { 16 | return BlockCipherFactory.createCipher( 17 | key.length == 16 ? "aes128-cbc" : "aes256-cbc", 18 | forEncrypt, key, iv); 19 | } 20 | 21 | @Test 22 | public void aes128Vector1() { 23 | checkVector(toBytes("2B7E151628AED2A6ABF7158809CF4F3C"), 24 | iv, 25 | csrcPlaintext, 26 | toBytes("7649ABAC8119B246CEE98E9B12E9197D" + 27 | "5086CB9B507219EE95DB113A917678B2" + 28 | "73BED6B8E3C1743B7116E69E22229516" + 29 | "3FF1CAA1681FAC09120ECA307586E1A7")); 30 | } 31 | 32 | @Test 33 | public void aes256Vector1() { 34 | checkVector(toBytes("603DEB1015CA71BE2B73AEF0857D7781" + 35 | "1F352C073B6108D72D9810A30914DFF4"), 36 | iv, 37 | csrcPlaintext, 38 | toBytes("F58C4C04D6E5F1BA779EABFB5F7BFBD6" + 39 | "9CFC4E967EDB808D679F777BC6702C7D" + 40 | "39F23369A9D9BACFA530E26304231461" + 41 | "B2EB05E2C39BE9FCDA6C19078C6A9D1B")); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/crypto/cipher/AESCTRTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Testing composed AES-CTR mode. 7 | *

8 | * Test vectors from 9 | * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CTR.pdf 10 | */ 11 | public class AESCTRTest extends AESTest { 12 | private final byte[] iv = toBytes("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); 13 | 14 | @Override 15 | BlockCipher getCipher(boolean forEncrypt, byte[] iv, byte[] key) { 16 | return BlockCipherFactory.createCipher( 17 | key.length == 16 ? "aes128-ctr" : "aes256-ctr", 18 | forEncrypt, key, iv); 19 | } 20 | 21 | @Test 22 | public void aes128Vector1() { 23 | checkVector(toBytes("2B7E151628AED2A6ABF7158809CF4F3C"), 24 | iv, 25 | csrcPlaintext, 26 | toBytes("874D6191B620E3261BEF6864990DB6CE" + 27 | "9806F66B7970FDFF8617187BB9FFFDFF" + 28 | "5AE4DF3EDBD5D35E5B4F09020DB03EAB" + 29 | "1E031DDA2FBE03D1792170A0F3009CEE")); 30 | } 31 | 32 | @Test 33 | public void aes256Vector1() { 34 | checkVector(toBytes("603DEB1015CA71BE2B73AEF0857D7781" + 35 | "1F352C073B6108D72D9810A30914DFF4"), 36 | iv, 37 | csrcPlaintext, 38 | toBytes("601EC313775789A5B7A7F504BBF3D228" + 39 | "F443E3CA4D62B59ACA84E990CACAF5C5" + 40 | "2B0930DAA23DE94CE87017BA2D84988D" + 41 | "DFC9C58DB67AADA613C2DD08457941A6")); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/crypto/cipher/AESTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | import org.apache.commons.codec.DecoderException; 4 | import org.apache.commons.codec.binary.Hex; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertArrayEquals; 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public abstract class AESTest { 11 | 12 | // Vectors from: 13 | // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_Core_All.pdf 14 | static final byte[] csrcPlaintext = toBytes( 15 | "6BC1BEE22E409F96E93D7E117393172A" + 16 | "AE2D8A571E03AC9C9EB76FAC45AF8E51" + 17 | "30C81C46A35CE411E5FBC1191A0A52EF" + 18 | "F69F2445DF4F9B17AD2B417BE66C3710"); 19 | 20 | abstract BlockCipher getCipher(boolean forEncrypt, byte[] iv, byte[] key); 21 | 22 | @Test(expected = IllegalArgumentException.class) 23 | public void init_zeroKeySize_Failure() { 24 | BlockCipher aes = getCipher(true, new byte[16], new byte[0]); 25 | } 26 | 27 | @Test(expected = IllegalArgumentException.class) 28 | public void init_8BitKeySize_Failure() { 29 | BlockCipher aes = getCipher(true, new byte[16], new byte[1]); 30 | } 31 | 32 | @Test 33 | public void init_128BitKeySize_Success() { 34 | getCipher(true, new byte[16], new byte[128 / 8]); 35 | getCipher(false, new byte[16], new byte[128 / 8]); 36 | } 37 | 38 | @Test 39 | public void init_192BitKeySize_Success() { 40 | getCipher(true, new byte[16], new byte[192 / 8]); 41 | getCipher(false, new byte[16], new byte[192 / 8]); 42 | } 43 | 44 | @Test 45 | public void init_256BitKeySize_Success() { 46 | getCipher(true, new byte[16], new byte[256 / 8]); 47 | getCipher(false, new byte[16], new byte[256 / 8]); 48 | } 49 | 50 | @Test 51 | public void getBlockSize() { 52 | BlockCipher aes = getCipher(true, new byte[16], new byte[16]); 53 | assertEquals(16, aes.getBlockSize()); 54 | } 55 | 56 | void checkVector(byte[] key, byte[] iv, byte[] plain, byte[] cipher) { 57 | BlockCipher encrypt = getCipher(true, iv, key); 58 | byte[] actualCipher = new byte[plain.length]; 59 | transformBlocks(encrypt, plain, actualCipher); 60 | assertArrayEquals(cipher, actualCipher); 61 | 62 | BlockCipher decrypt = getCipher(false, iv, key); 63 | byte[] actualPlain = new byte[cipher.length]; 64 | transformBlocks(decrypt, cipher, actualPlain); 65 | assertArrayEquals(plain, actualPlain); 66 | } 67 | 68 | private static final void transformBlocks(BlockCipher aes, byte[] in, byte[] out) { 69 | for (int i = 0; i < in.length; i += aes.getBlockSize()) { 70 | aes.transformBlock(in, i, out, i); 71 | } 72 | } 73 | 74 | static final byte[] toBytes(String input) { 75 | try { 76 | return Hex.decodeHex(input); 77 | } catch (DecoderException e) { 78 | throw new AssertionError("Cannot decode test vector: " + input); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/crypto/dh/Curve25519ExchangeTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.dh; 2 | 3 | import com.google.crypto.tink.subtle.X25519; 4 | 5 | import org.junit.Test; 6 | 7 | import java.math.BigInteger; 8 | 9 | import static org.junit.Assert.assertArrayEquals; 10 | import static org.junit.Assert.assertEquals; 11 | import static org.junit.Assert.assertNotNull; 12 | 13 | /** 14 | * Created by Kenny Root on 1/23/16. 15 | */ 16 | public class Curve25519ExchangeTest { 17 | private static final byte[] ALICE_PRIVATE = toByteArray("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"); 18 | private static final byte[] ALICE_PUBLIC = toByteArray("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"); 19 | 20 | private static final byte[] BOB_PRIVATE = toByteArray("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"); 21 | private static final byte[] BOB_PUBLIC = toByteArray("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"); 22 | 23 | private static final byte[] KNOWN_SHARED_SECRET = toByteArray("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"); 24 | private static final BigInteger KNOWN_SHARED_SECRET_BI = new BigInteger(1, KNOWN_SHARED_SECRET); 25 | 26 | private static byte[] toByteArray(String s) { 27 | byte[] b = new byte[s.length() / 2]; 28 | for (int i = 0; i < b.length; i++) { 29 | int hexIndex = i * 2; 30 | int hexDigit = Integer.parseInt(s.substring(hexIndex, hexIndex + 2), 16); 31 | b[i] = (byte) hexDigit; 32 | } 33 | return b; 34 | } 35 | 36 | @Test 37 | public void selfAgreement() throws Exception { 38 | byte[] alicePrivKey = X25519.generatePrivateKey(); 39 | byte[] alicePubKey = X25519.publicFromPrivate(alicePrivKey); 40 | 41 | byte[] bobPrivKey = X25519.generatePrivateKey(); 42 | byte[] bobPubKey = X25519.publicFromPrivate(bobPrivKey); 43 | 44 | Curve25519Exchange alice = new Curve25519Exchange(alicePrivKey); 45 | alice.setF(bobPubKey); 46 | 47 | Curve25519Exchange bob = new Curve25519Exchange(bobPrivKey); 48 | bob.setF(alicePubKey); 49 | 50 | assertNotNull(alice.sharedSecret); 51 | assertEquals(alice.sharedSecret, bob.sharedSecret); 52 | } 53 | 54 | @Test 55 | public void deriveAlicePublicKey() throws Exception { 56 | byte[] pubKey = X25519.publicFromPrivate(ALICE_PRIVATE); 57 | assertArrayEquals(ALICE_PUBLIC, pubKey); 58 | } 59 | 60 | @Test 61 | public void deriveBobPublicKey() throws Exception { 62 | byte[] pubKey = X25519.publicFromPrivate(BOB_PRIVATE); 63 | assertArrayEquals(BOB_PUBLIC, pubKey); 64 | } 65 | 66 | @Test 67 | public void knownValues_Alice() throws Exception { 68 | Curve25519Exchange ex = new Curve25519Exchange(ALICE_PRIVATE); 69 | ex.setF(BOB_PUBLIC); 70 | assertEquals(KNOWN_SHARED_SECRET_BI, ex.sharedSecret); 71 | } 72 | 73 | @Test 74 | public void knownValues_Bob() throws Exception { 75 | Curve25519Exchange ex = new Curve25519Exchange(BOB_PRIVATE); 76 | ex.setF(ALICE_PUBLIC); 77 | assertEquals(KNOWN_SHARED_SECRET_BI, ex.sharedSecret); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/crypto/keys/Ed25519KeyPairGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.keys; 2 | 3 | import org.junit.Test; 4 | 5 | import java.security.KeyPairGenerator; 6 | 7 | import static com.trilead.ssh2.crypto.keys.IsValidEdDSAKeyPair.isValidEdDSAKeyPair; 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | 10 | public class Ed25519KeyPairGeneratorTest { 11 | @Test 12 | public void generatesValidKeys_noInitialize() throws Exception { 13 | Ed25519Provider p = new Ed25519Provider(); 14 | KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519", p); 15 | assertThat(kpg.generateKeyPair(), isValidEdDSAKeyPair()); 16 | } 17 | 18 | @Test 19 | public void generatesValidKeys_withInitialize() throws Exception { 20 | Ed25519Provider p = new Ed25519Provider(); 21 | KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519", p); 22 | kpg.initialize(256); 23 | assertThat(kpg.generateKeyPair(), isValidEdDSAKeyPair()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/crypto/keys/IsValidEdDSAKeyPair.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.keys; 2 | 3 | import com.google.crypto.tink.subtle.Ed25519Sign; 4 | import com.google.crypto.tink.subtle.Ed25519Verify; 5 | import org.hamcrest.Description; 6 | import org.hamcrest.Matcher; 7 | import org.hamcrest.TypeSafeMatcher; 8 | 9 | import java.security.KeyPair; 10 | import java.security.PrivateKey; 11 | import java.security.PublicKey; 12 | 13 | public class IsValidEdDSAKeyPair extends TypeSafeMatcher { 14 | @Override 15 | protected boolean matchesSafely(KeyPair item) { 16 | PrivateKey privKey = item.getPrivate(); 17 | PublicKey pubKey = item.getPublic(); 18 | if (!(privKey instanceof Ed25519PrivateKey) || !(pubKey instanceof Ed25519PublicKey)) { 19 | return false; 20 | } 21 | 22 | Ed25519PrivateKey edPriv = (Ed25519PrivateKey) privKey; 23 | Ed25519PublicKey edPub = (Ed25519PublicKey) pubKey; 24 | 25 | try { 26 | byte[] signature = new Ed25519Sign(edPriv.getSeed()).sign(new byte[128]); 27 | new Ed25519Verify(edPub.getAbyte()).verify(signature, new byte[128]); 28 | return true; 29 | } catch (Exception e) { 30 | return false; 31 | } 32 | } 33 | 34 | @Override 35 | public void describeTo(Description description) { 36 | description.appendText("is valid EdDSA key pair"); 37 | } 38 | 39 | public static Matcher isValidEdDSAKeyPair() { 40 | return new IsValidEdDSAKeyPair(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/packets/PacketExtInfoTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import org.junit.Test; 4 | 5 | import java.io.IOException; 6 | import java.util.Collections; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | import static org.junit.Assert.assertNotNull; 10 | 11 | public class PacketExtInfoTest { 12 | @Test 13 | public void getPayload_NullPayload_IsEmpty() { 14 | PacketExtInfo p = new PacketExtInfo(Collections.emptyMap()); 15 | assertNotNull(p.getPayload()); 16 | assertEquals(Collections.emptyMap(), p.getExtNameToValue()); 17 | } 18 | 19 | @Test(expected = IOException.class) 20 | public void packetWithPadding_Fails() throws IOException { 21 | byte[] unpaddedPacket = new PacketExtInfo(Collections.emptyMap()).getPayload(); 22 | byte[] paddedPacket = new byte[unpaddedPacket.length + 1]; 23 | System.arraycopy(unpaddedPacket, 0, paddedPacket, 0, unpaddedPacket.length); 24 | new PacketExtInfo(paddedPacket, 0, paddedPacket.length); 25 | } 26 | 27 | @Test(expected = IOException.class) 28 | public void wrongPacket_Fails() throws IOException { 29 | byte[] wrongPacket = new PacketGlobalTrileadPing().getPayload(); 30 | new PacketExtInfo(wrongPacket, 0, wrongPacket.length); 31 | } 32 | 33 | @Test 34 | public void createPacketAndParsePayload_Success() throws IOException { 35 | byte[] payload = new PacketExtInfo(Collections.singletonMap("test", "value")).getPayload(); 36 | PacketExtInfo copy = new PacketExtInfo(payload, 0, payload.length); 37 | assertEquals("value", copy.getExtNameToValue().get("test")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/packets/PacketsTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | public class PacketsTest { 8 | @Test 9 | public void getMessageName_BeyondEnd_Fails() { 10 | assertEquals("UNKNOWN MSG 8928392", Packets.getMessageName(8928392)); 11 | } 12 | 13 | @Test 14 | public void getMessageName_Negative_Fails() { 15 | assertEquals("UNKNOWN MSG -1", Packets.getMessageName(-1)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/trilead/ssh2/signature/ECDSASHA2VerifyTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.signature; 2 | 3 | import com.trilead.ssh2.crypto.PEMDecoder; 4 | import org.junit.Test; 5 | 6 | 7 | /** 8 | * Created by kenny on 12/25/15. 9 | */ 10 | public class ECDSASHA2VerifyTest { 11 | @Test 12 | public void decodeP521PEMKey() throws Exception { 13 | char[] pemKey = ("-----BEGIN EC PRIVATE KEY-----\n" + 14 | "MIHbAgEBBEGiLM/lkLGNRu6KdnQaWhWM/PBqR0ibIokEW4xa0Nv5O1TDBpiM+lus\n" + 15 | "wi8oM6qzWJbKf685J322VH3uYAs5oIYxJ6AHBgUrgQQAI6GBiQOBhgAEAK6P4X/5\n" + 16 | "n3hZssRG1x1jPNBTSFG79H36JkJHsCerPrsdjCNzfh/P5a87bCOor/My8un/JFly\n" + 17 | "H5mVXAO0t2YQq7qfAMCBawq2HfC+rfCikl5mrSYg6d0bshQ5ZIYAwU85VIK9kdjA\n" + 18 | "ImRIKkyB7MN7qqQUASFcYZLFwwdeRZw/0Yp7Ma/+\n" + 19 | "-----END EC PRIVATE KEY-----\n").toCharArray(); 20 | PEMDecoder.decode(pemKey, null); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/resources/asyncssh-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12-slim-bookworm AS builder 2 | RUN apt-get update && \ 3 | apt-get install -y gcc openssh-server && \ 4 | apt-get clean 5 | COPY requirements.txt /app/requirements.txt 6 | WORKDIR app 7 | RUN pip install --user -r requirements.txt 8 | RUN mkdir -p /etc/ssh && ssh-keygen -A 9 | COPY . /app 10 | 11 | FROM python:3.12-slim-bookworm AS app 12 | COPY --from=builder /etc/ssh /etc/ssh 13 | COPY --from=builder /root/.local /root/.local 14 | COPY --from=builder /app/server.py /app/server.py 15 | WORKDIR app 16 | EXPOSE 8022 17 | ENV PYTHONUNBUFFERED=0 18 | ENTRYPOINT ["python", "-u", "server.py"] 19 | COPY *.pub /app/ 20 | RUN cat /app/*.pub > /app/authorized_keys && rm -f /app/*.pub 21 | -------------------------------------------------------------------------------- /src/test/resources/asyncssh-server/requirements.txt: -------------------------------------------------------------------------------- 1 | asyncssh[libnacl] 2 | -------------------------------------------------------------------------------- /src/test/resources/asyncssh-server/server.py: -------------------------------------------------------------------------------- 1 | # To run this program, the file ``ssh_host_key`` must exist with an SSH 2 | # private key in it to use as a server host key. An SSH host certificate 3 | # can optionally be provided in the file ``ssh_host_key-cert.pub``. 4 | 5 | import asyncio, asyncssh, crypt, sys, time, logging 6 | 7 | passwords = { 8 | 'user123': 'qV2iEadIGV2rw' # password of 'secretpw' 9 | } 10 | 11 | def handle_client(process): 12 | process.stdout.write('success\n') 13 | time.sleep(10) 14 | process.exit(0) 15 | 16 | class MySSHServer(asyncssh.SSHServer): 17 | def __init__(self): 18 | self._conn = None 19 | 20 | def connection_made(self, conn): 21 | print('SSH connection received from %s.' % 22 | conn.get_extra_info('peername')[0]) 23 | self._conn = conn; 24 | 25 | def connection_lost(self, exc): 26 | if exc: 27 | print('SSH connection error: ' + str(exc), file=sys.stderr) 28 | else: 29 | print('SSH connection closed.') 30 | 31 | def begin_auth(self, username): 32 | # If the user's password is the empty string, no auth is required 33 | self._conn.set_authorized_keys('authorized_keys') 34 | return passwords.get(username) != '' 35 | 36 | def password_auth_supported(self): 37 | return True 38 | 39 | def validate_password(self, username, password): 40 | pw = passwords.get(username, '*') 41 | return crypt.crypt(password, pw) == pw 42 | 43 | def public_key_auth_supported(self): 44 | return True 45 | 46 | 47 | async def start_server(): 48 | asyncssh.set_log_level('DEBUG') 49 | asyncssh.set_debug_level(2) 50 | await asyncssh.create_server(MySSHServer, '', 8022, 51 | server_host_keys=[ 52 | '/etc/ssh/ssh_host_ecdsa_key', 53 | '/etc/ssh/ssh_host_rsa_key', 54 | ], 55 | process_factory=handle_client) 56 | 57 | print("SETTING LOGGER") 58 | root = logging.getLogger() 59 | root.setLevel(logging.DEBUG) 60 | 61 | ch = logging.StreamHandler(sys.stdout) 62 | ch.setLevel(logging.DEBUG) 63 | formatter = logging.Formatter('%(message)s') 64 | ch.setFormatter(formatter) 65 | root.addHandler(ch) 66 | 67 | print("STARTING UP") 68 | loop = asyncio.get_event_loop() 69 | 70 | try: 71 | loop.run_until_complete(start_server()) 72 | except (OSError, asyncssh.Error) as exc: 73 | sys.exit('Error starting server: ' + str(exc)) 74 | 75 | print("LISTENER READY") 76 | 77 | # Only run the loop once for testing 78 | #loop.call_soon(loop.stop) 79 | loop.run_forever() 80 | -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/dsa-openssh2-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN OPENSSH PRIVATE KEY----- 2 | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAADMQAAAAdz 3 | c2gtZHNzAAABAQCTwRCtqVzAb54+8dO5HnIpI6c/xxemJaTWSIkkkqT6cPQWnYMY 4 | T8q+ozxeuml39qWR7/EjJEGyzuCM5E3gtmEB2fJtqmDtrNS+3W28WBcsz/cRFr0O 5 | xohHOaTY6nOHnXTIwEUMclXaX3Fqc1erN20wGSuvqWiQuoSLo56KJ05/DmhNrFdf 6 | 2jnS20k3SfKqCfj9wTUh9XFBRbH3aP/1iaDXjSogg/86N9bgwj+XkDclBySNOKp4 7 | xH6youAsXzaicMtwg2JHwLJbpVMOrtXdcJoUpq80mTvMj1asJWhuw/sCOzat5G92 8 | yE3ejJPMNK7Zxmpf98KDQDi5NtdOJCqqMq0jAAAAFQC6+Z5aw4Z+R71Hv3PsK8yz 9 | d5zdlQAAAQAK54Po+geyRR3uypcIw6Z5e9dkbsjYfeRYE3bHwAVR92/etX8uKIJU 10 | xIaBmzSYWqxqmtamxNe+VIU5MlE3FOA+XcqG+6ALS7Su6Eb3GVNG2W7YY6Oo8vEb 11 | IfU7yY3FWz5r69zjw20wMH/191NVxDQBWiwDLvpGLpbJQFNL58x2JFAiBglb6Jfs 12 | m3SCXJpg8wsOgGrpv8/sB/cO9ugV+/Kdv3DLHDJ8H/+qdPazwFatSywm1+DEyuZ4 13 | 8ZQJGtcfrx7qQ8aEbiQGZCXDlIrrBY2/3OV3n774fvssc+GN98YpcVg3LOZW6rMp 14 | GaCHnLmZ9kupaSFjEMsyIq917H0/+HpTAAABADnMJBHQgFaxq/sG5ipM0Ct8cUk4 15 | Tsw4ijUFyuzWeaaeLs3q8N5bdZH/BHZoQS2L9zEoUTXWvhyc1X3tjVvDL+w6Hrek 16 | lzY6Wi2TQjZ+Q660/5yyROwQUDCAwVlMhLqDnfL5IZbNjak2YqPC6WKCdy8zaBYx 17 | xkJKftawZYqZ3noc4WqX30AKik/QYt04LpHWKw21EjqH1Bgq8T8yZlt264Ta21WR 18 | 3pdqs59w+9g3BLnxUj599zmd4IUHuVWbuf5zhvn0jxi/FHFXBpDIqrsk3+LDiSKH 19 | citnP+Lq2ovFnR6IymwLMSLs6S4GNzM8b/G8tRdsoPOTVoFhYytEmyEtp84AAANw 20 | gzYvnYM2L50AAAAHc3NoLWRzcwAAAQEAk8EQralcwG+ePvHTuR5yKSOnP8cXpiWk 21 | 1kiJJJKk+nD0Fp2DGE/KvqM8Xrppd/alke/xIyRBss7gjORN4LZhAdnybapg7azU 22 | vt1tvFgXLM/3ERa9DsaIRzmk2Opzh510yMBFDHJV2l9xanNXqzdtMBkrr6lokLqE 23 | i6OeiidOfw5oTaxXX9o50ttJN0nyqgn4/cE1IfVxQUWx92j/9Ymg140qIIP/OjfW 24 | 4MI/l5A3JQckjTiqeMR+sqLgLF82onDLcINiR8CyW6VTDq7V3XCaFKavNJk7zI9W 25 | rCVobsP7Ajs2reRvdshN3oyTzDSu2cZqX/fCg0A4uTbXTiQqqjKtIwAAABUAuvme 26 | WsOGfke9R79z7CvMs3ec3ZUAAAEACueD6PoHskUd7sqXCMOmeXvXZG7I2H3kWBN2 27 | x8AFUfdv3rV/LiiCVMSGgZs0mFqsaprWpsTXvlSFOTJRNxTgPl3KhvugC0u0ruhG 28 | 9xlTRtlu2GOjqPLxGyH1O8mNxVs+a+vc48NtMDB/9fdTVcQ0AVosAy76Ri6WyUBT 29 | S+fMdiRQIgYJW+iX7Jt0glyaYPMLDoBq6b/P7Af3DvboFfvynb9wyxwyfB//qnT2 30 | s8BWrUssJtfgxMrmePGUCRrXH68e6kPGhG4kBmQlw5SK6wWNv9zld5+++H77LHPh 31 | jffGKXFYNyzmVuqzKRmgh5y5mfZLqWkhYxDLMiKvdex9P/h6UwAAAQA5zCQR0IBW 32 | sav7BuYqTNArfHFJOE7MOIo1Bcrs1nmmni7N6vDeW3WR/wR2aEEti/cxKFE11r4c 33 | nNV97Y1bwy/sOh63pJc2Olotk0I2fkOutP+cskTsEFAwgMFZTIS6g53y+SGWzY2p 34 | NmKjwuligncvM2gWMcZCSn7WsGWKmd56HOFql99ACopP0GLdOC6R1isNtRI6h9QY 35 | KvE/MmZbduuE2ttVkd6XarOfcPvYNwS58VI+ffc5neCFB7lVm7n+c4b59I8YvxRx 36 | VwaQyKq7JN/iw4kih3IrZz/i6tqLxZ0eiMpsCzEi7OkuBjczPG/xvLUXbKDzk1aB 37 | YWMrRJshLafOAAAAFAXeCB+0dGeTXFy7JeSg5y5mfxGeAAAAEGRzYS1rZXktMjAx 38 | NzA0MDgBAgMEBQYHCAkKCw== 39 | -----END OPENSSH PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/dsa-openssh2-private-key.txt.pub: -------------------------------------------------------------------------------- 1 | ssh-dss AAAAB3NzaC1kc3MAAAEBAJPBEK2pXMBvnj7x07kecikjpz/HF6YlpNZIiSSSpPpw9BadgxhPyr6jPF66aXf2pZHv8SMkQbLO4IzkTeC2YQHZ8m2qYO2s1L7dbbxYFyzP9xEWvQ7GiEc5pNjqc4eddMjARQxyVdpfcWpzV6s3bTAZK6+paJC6hIujnoonTn8OaE2sV1/aOdLbSTdJ8qoJ+P3BNSH1cUFFsfdo//WJoNeNKiCD/zo31uDCP5eQNyUHJI04qnjEfrKi4CxfNqJwy3CDYkfAslulUw6u1d1wmhSmrzSZO8yPVqwlaG7D+wI7Nq3kb3bITd6Mk8w0rtnGal/3woNAOLk2104kKqoyrSMAAAAVALr5nlrDhn5HvUe/c+wrzLN3nN2VAAABAArng+j6B7JFHe7KlwjDpnl712RuyNh95FgTdsfABVH3b961fy4oglTEhoGbNJharGqa1qbE175UhTkyUTcU4D5dyob7oAtLtK7oRvcZU0bZbthjo6jy8Rsh9TvJjcVbPmvr3OPDbTAwf/X3U1XENAFaLAMu+kYulslAU0vnzHYkUCIGCVvol+ybdIJcmmDzCw6Aaum/z+wH9w726BX78p2/cMscMnwf/6p09rPAVq1LLCbX4MTK5njxlAka1x+vHupDxoRuJAZkJcOUiusFjb/c5Xefvvh++yxz4Y33xilxWDcs5lbqsykZoIecuZn2S6lpIWMQyzIir3XsfT/4elMAAAEAOcwkEdCAVrGr+wbmKkzQK3xxSThOzDiKNQXK7NZ5pp4uzerw3lt1kf8EdmhBLYv3MShRNda+HJzVfe2NW8Mv7Doet6SXNjpaLZNCNn5DrrT/nLJE7BBQMIDBWUyEuoOd8vkhls2NqTZio8LpYoJ3LzNoFjHGQkp+1rBlipneehzhapffQAqKT9Bi3TgukdYrDbUSOofUGCrxPzJmW3brhNrbVZHel2qzn3D72DcEufFSPn33OZ3ghQe5VZu5/nOG+fSPGL8UcVcGkMiquyTf4sOJIodyK2c/4urai8WdHojKbAsxIuzpLgY3Mzxv8by1F2yg85NWgWFjK0SbIS2nzg== 2 | -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/dsa-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PRIVATE KEY----- 2 | MIIDPQIBAAKCAQEAk8EQralcwG+ePvHTuR5yKSOnP8cXpiWk1kiJJJKk+nD0Fp2D 3 | GE/KvqM8Xrppd/alke/xIyRBss7gjORN4LZhAdnybapg7azUvt1tvFgXLM/3ERa9 4 | DsaIRzmk2Opzh510yMBFDHJV2l9xanNXqzdtMBkrr6lokLqEi6OeiidOfw5oTaxX 5 | X9o50ttJN0nyqgn4/cE1IfVxQUWx92j/9Ymg140qIIP/OjfW4MI/l5A3JQckjTiq 6 | eMR+sqLgLF82onDLcINiR8CyW6VTDq7V3XCaFKavNJk7zI9WrCVobsP7Ajs2reRv 7 | dshN3oyTzDSu2cZqX/fCg0A4uTbXTiQqqjKtIwIVALr5nlrDhn5HvUe/c+wrzLN3 8 | nN2VAoIBAArng+j6B7JFHe7KlwjDpnl712RuyNh95FgTdsfABVH3b961fy4oglTE 9 | hoGbNJharGqa1qbE175UhTkyUTcU4D5dyob7oAtLtK7oRvcZU0bZbthjo6jy8Rsh 10 | 9TvJjcVbPmvr3OPDbTAwf/X3U1XENAFaLAMu+kYulslAU0vnzHYkUCIGCVvol+yb 11 | dIJcmmDzCw6Aaum/z+wH9w726BX78p2/cMscMnwf/6p09rPAVq1LLCbX4MTK5njx 12 | lAka1x+vHupDxoRuJAZkJcOUiusFjb/c5Xefvvh++yxz4Y33xilxWDcs5lbqsykZ 13 | oIecuZn2S6lpIWMQyzIir3XsfT/4elMCggEAOcwkEdCAVrGr+wbmKkzQK3xxSThO 14 | zDiKNQXK7NZ5pp4uzerw3lt1kf8EdmhBLYv3MShRNda+HJzVfe2NW8Mv7Doet6SX 15 | NjpaLZNCNn5DrrT/nLJE7BBQMIDBWUyEuoOd8vkhls2NqTZio8LpYoJ3LzNoFjHG 16 | Qkp+1rBlipneehzhapffQAqKT9Bi3TgukdYrDbUSOofUGCrxPzJmW3brhNrbVZHe 17 | l2qzn3D72DcEufFSPn33OZ3ghQe5VZu5/nOG+fSPGL8UcVcGkMiquyTf4sOJIody 18 | K2c/4urai8WdHojKbAsxIuzpLgY3Mzxv8by1F2yg85NWgWFjK0SbIS2nzgIUBd4I 19 | H7R0Z5NcXLsl5KDnLmZ/EZ4= 20 | -----END DSA PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ecdsa-nistp256-openssh2-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN OPENSSH PRIVATE KEY----- 2 | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNl 3 | Y2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQQX3TPOKh4a/N4cJFB 4 | TUkUyS7yOgddIpdgsij/xyLNuXAZOIGsXlexQyTd3Krq1dbmj57XUBLZsnUPKkrC 5 | KOF+AAAAsJCs7bWQrO21AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy 6 | NTYAAABBBBBfdM84qHhr83hwkUFNSRTJLvI6B10il2CyKP/HIs25cBk4gaxeV7FD 7 | JN3cqurV1uaPntdQEtmydQ8qSsIo4X4AAAAgbIPKXLQtxkzECfQw7syiMp4r4uST 8 | J8a69bijYEOm/SUAAAASZWNkc2Eta2V5LTIwMTcwNDEwAQIDBAUG 9 | -----END OPENSSH PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ecdsa-nistp256-openssh2-private-key.txt.pub: -------------------------------------------------------------------------------- 1 | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBBfdM84qHhr83hwkUFNSRTJLvI6B10il2CyKP/HIs25cBk4gaxeV7FDJN3cqurV1uaPntdQEtmydQ8qSsIo4X4= 2 | -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ecdsa-nistp256-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIGyDyly0LcZMxAn0MO7MojKeK+LkkyfGuvW4o2BDpv0loAoGCCqGSM49 3 | AwEHoUQDQgAEEF90zzioeGvzeHCRQU1JFMku8joHXSKXYLIo/8cizblwGTiBrF5X 4 | sUMk3dyq6tXW5o+e11AS2bJ1DypKwijhfg== 5 | -----END EC PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ecdsa-nistp384-openssh2-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN OPENSSH PRIVATE KEY----- 2 | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNl 3 | Y2RzYS1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQSHxVgeI3jxXqmbFJi+ 4 | a/iHRtpWAvbFi5iTBAaWBuPQnX3l6LWVFXzD9NOnp4zOwkWhQKOWlzK2uxE8xoil 5 | MRHeCsDe6CnvapTNbLAS+QSmXbqnplq56pdycO8V7HIlZwkAAADgGvTURhr01EYA 6 | AAATZWNkc2Etc2hhMi1uaXN0cDM4NAAAAAhuaXN0cDM4NAAAAGEEh8VYHiN48V6p 7 | mxSYvmv4h0baVgL2xYuYkwQGlgbj0J195ei1lRV8w/TTp6eMzsJFoUCjlpcytrsR 8 | PMaIpTER3grA3ugp72qUzWywEvkEpl26p6ZaueqXcnDvFexyJWcJAAAAMEcPAUAa 9 | E4jEtr+7GgAwYQCuHfspoBS1cfTsuqjmDYiVcr2obG1NYKHRbLWjj5CqAgAAABJl 10 | Y2RzYS1rZXktMjAxNzA0MTABAgMEBQY= 11 | -----END OPENSSH PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ecdsa-nistp384-openssh2-private-key.txt.pub: -------------------------------------------------------------------------------- 1 | ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBIfFWB4jePFeqZsUmL5r+IdG2lYC9sWLmJMEBpYG49CdfeXotZUVfMP006enjM7CRaFAo5aXMra7ETzGiKUxEd4KwN7oKe9qlM1ssBL5BKZduqemWrnql3Jw7xXsciVnCQ== 2 | -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ecdsa-nistp384-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MIGkAgEBBDBHDwFAGhOIxLa/uxoAMGEArh37KaAUtXH07Lqo5g2IlXK9qGxtTWCh 3 | 0Wy1o4+QqgKgBwYFK4EEACKhZANiAASHxVgeI3jxXqmbFJi+a/iHRtpWAvbFi5iT 4 | BAaWBuPQnX3l6LWVFXzD9NOnp4zOwkWhQKOWlzK2uxE8xoilMRHeCsDe6CnvapTN 5 | bLAS+QSmXbqnplq56pdycO8V7HIlZwk= 6 | -----END EC PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ecdsa-nistp521-openssh2-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN OPENSSH PRIVATE KEY----- 2 | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNl 3 | Y2RzYS1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQBuvEdnrBmvZDBfsLp 4 | sGJqsVy5mbZ8Yi0R7P4gDO6lYK+hpRTtXTsVsPefozkQ6ZCO/7QkOzL6zg8Mlq5D 5 | UdRbDo0AR2IS/BirIPO6pMnl5UFXSFGbIAwBTGg2LVxPrj37rWpOjQtCkXAegTfZ 6 | ZKSaA9/1IAquGc0HADzn6VQKk0VmRMEAAAEgPB+FvTwfhb0AAAATZWNkc2Etc2hh 7 | Mi1uaXN0cDUyMQAAAAhuaXN0cDUyMQAAAIUEAbrxHZ6wZr2QwX7C6bBiarFcuZm2 8 | fGItEez+IAzupWCvoaUU7V07FbD3n6M5EOmQjv+0JDsy+s4PDJauQ1HUWw6NAEdi 9 | EvwYqyDzuqTJ5eVBV0hRmyAMAUxoNi1cT649+61qTo0LQpFwHoE32WSkmgPf9SAK 10 | rhnNBwA85+lUCpNFZkTBAAAAQgFDbxUKc3d5/rO94W8DRaPbNF9toGKNVH6wTcBt 11 | JUJTl8mOYziKL9wOWBak1eQjFC+ORXhs26JD+Z6XdI1wcU6zAQAAABJlY2RzYS1r 12 | ZXktMjAxNzA0MTABAgMEBQYHCAkKCwwNDg8Q 13 | -----END OPENSSH PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ecdsa-nistp521-openssh2-private-key.txt.pub: -------------------------------------------------------------------------------- 1 | ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAG68R2esGa9kMF+wumwYmqxXLmZtnxiLRHs/iAM7qVgr6GlFO1dOxWw95+jORDpkI7/tCQ7MvrODwyWrkNR1FsOjQBHYhL8GKsg87qkyeXlQVdIUZsgDAFMaDYtXE+uPfutak6NC0KRcB6BN9lkpJoD3/UgCq4ZzQcAPOfpVAqTRWZEwQ== 2 | -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ecdsa-nistp521-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MIHcAgEBBEIBQ28VCnN3ef6zveFvA0Wj2zRfbaBijVR+sE3AbSVCU5fJjmM4ii/c 3 | DlgWpNXkIxQvjkV4bNuiQ/mel3SNcHFOswGgBwYFK4EEACOhgYkDgYYABAG68R2e 4 | sGa9kMF+wumwYmqxXLmZtnxiLRHs/iAM7qVgr6GlFO1dOxWw95+jORDpkI7/tCQ7 5 | MvrODwyWrkNR1FsOjQBHYhL8GKsg87qkyeXlQVdIUZsgDAFMaDYtXE+uPfutak6N 6 | C0KRcB6BN9lkpJoD3/UgCq4ZzQcAPOfpVAqTRWZEwQ== 7 | -----END EC PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ed25519-openssh2-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN OPENSSH PRIVATE KEY----- 2 | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW 3 | QyNTUxOQAAACAESuFbBfi9GvagzrxZ+g54aYPZkL1GjpMeXJgFEjGfuAAAAJiZSdPTmUnT 4 | 0wAAAAtzc2gtZWQyNTUxOQAAACAESuFbBfi9GvagzrxZ+g54aYPZkL1GjpMeXJgFEjGfuA 5 | AAAEB/holg8Y5qxrG8PWN2w8pcHjQszGV+mqTRbysNUP6U7ARK4VsF+L0a9qDOvFn6Dnhp 6 | g9mQvUaOkx5cmAUSMZ+4AAAAFWtlbm55QGZsYXNoLW1icC5sb2NhbA== 7 | -----END OPENSSH PRIVATE KEY----- 8 | -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/ed25519-openssh2-private-key.txt.pub: -------------------------------------------------------------------------------- 1 | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIARK4VsF+L0a9qDOvFn6Dnhpg9mQvUaOkx5cmAUSMZ+4 2 | -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/rsa-openssh2-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN OPENSSH PRIVATE KEY----- 2 | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFQAAAAdz 3 | c2gtcnNhAAAAASUAAAEBAJCdQJNgQPpBmlratR9x70/h63ELD7itF1mjM60jyo+b 4 | RCCzvoi/fDA+L7RwBq9Clzje+lkWpP/A6Duw76ksWuulxrtvFf/TcvRaWndWZojS 5 | EqRG2O51yM+GMfxxjsnpkvli1/MewVri2gGDcLrd+ws3mH1wryn4eYrLW/93ZG/+ 6 | GckQegLoWlwYajNCgA1BqjHBlUbjMz2tI2DuOf+9Y/VB8QJ/CB9y/nyjHAzGFOoP 7 | y1c9Vnk0qqREghAUyAuJt6PKOMt2J3SUrnaMldFNuTAygdS4Ttt/EQTlP8xvursF 8 | GOoR1olEmOIHCIMYDJwHrM+/zmhWhkS45WmhV9XZh1MAAAPQmOYRGZjmERkAAAAH 9 | c3NoLXJzYQAAAQEAkJ1Ak2BA+kGaWtq1H3HvT+HrcQsPuK0XWaMzrSPKj5tEILO+ 10 | iL98MD4vtHAGr0KXON76WRak/8DoO7DvqSxa66XGu28V/9Ny9Fpad1ZmiNISpEbY 11 | 7nXIz4Yx/HGOyemS+WLX8x7BWuLaAYNwut37CzeYfXCvKfh5istb/3dkb/4ZyRB6 12 | AuhaXBhqM0KADUGqMcGVRuMzPa0jYO45/71j9UHxAn8IH3L+fKMcDMYU6g/LVz1W 13 | eTSqpESCEBTIC4m3o8o4y3YndJSudoyV0U25MDKB1LhO238RBOU/zG+6uwUY6hHW 14 | iUSY4gcIgxgMnAesz7/OaFaGRLjlaaFX1dmHUwAAAAElAAABABOK3zaCoP85TDXK 15 | hy3DSdpczMoWQGUQeMbsinFX3RpTQI7MLoEuohRbbjr6YcSoIkX0nl8Q5d1fQfo6 16 | gUBf8JxigqO1EM+LRuLAGhAgbriLF0ahykm848kES/GuexRd1ZdSi+KVdBMzaZGA 17 | dwR+3LxTnvwx0ntLF1fx96zmnt6zbN8YepMpUj3TyI5u7AZyxENR4rI/xHFve4Yy 18 | Ijp38U1L4a3vjd1RFkdAceoC46i38vyoe/PkyFmIYDkehosUJp6PKv8yHNI6HZ2c 19 | M0d9pokOSNzke5g524YeeecRJggDFGtkIi/RCiH00D3m6DH3AzymSpFoivSArHLP 20 | wPzl5p0AAACBAKLLjhPtAe6RH6n7ZGdLHKvi9gpD7Z9ZuNce69dSiJfqrOmqGtW5 21 | 2RR5ouPFjMOrZlf81jHNi5Z+cpQX/1n0ym94Jb9q1mqR2ksVURnopcxASVlES4Z0 22 | KHGhEm574640iut/HZfDCjjkzko92+FGL5f8ADZ3Hx0JfDqP4b4yq2AxAAAAgQD5 23 | JBMhcmipIcU6YHeAjyG59EPUgQQdOGin8C9Q3VWlZ2NmRAtn/yVB4rylz8ONYfMO 24 | RVWF2eUGTVl94ylXuWVSKDDvninn9hB1bdXd4uzax3NFnJX2XWaf3FJmaUwnLowZ 25 | yC0yzt1kc/EX/2wGd/Hpan6cdFiNUEf6Ynw7CG7xSwAAAIEAlJh7ZxxN6j2aY7TJ 26 | YBs1ELG5Zmugzr3YT8LlhXG8+B6tBLdTuYdcF73WXnlTjHRlHV3V1Pjl2cBgPB/W 27 | WYAo4UypCwAMnWrWKq2ZPHbyQT9Vh28hLErSskgXubU+RurImzpmDSVcT9k1hR// 28 | T+WLeD4MPVmR9K/r7ui9VX34hRkAAAAQcnNhLWtleS0yMDE3MDQwOQECAwQFBgcI 29 | CQoLDA== 30 | -----END OPENSSH PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/rsa-openssh2-private-key.txt.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAkJ1Ak2BA+kGaWtq1H3HvT+HrcQsPuK0XWaMzrSPKj5tEILO+iL98MD4vtHAGr0KXON76WRak/8DoO7DvqSxa66XGu28V/9Ny9Fpad1ZmiNISpEbY7nXIz4Yx/HGOyemS+WLX8x7BWuLaAYNwut37CzeYfXCvKfh5istb/3dkb/4ZyRB6AuhaXBhqM0KADUGqMcGVRuMzPa0jYO45/71j9UHxAn8IH3L+fKMcDMYU6g/LVz1WeTSqpESCEBTIC4m3o8o4y3YndJSudoyV0U25MDKB1LhO238RBOU/zG+6uwUY6hHWiUSY4gcIgxgMnAesz7/OaFaGRLjlaaFX1dmHUw== 2 | -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/crypto/rsa-private-key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEoQIBAAKCAQEAkJ1Ak2BA+kGaWtq1H3HvT+HrcQsPuK0XWaMzrSPKj5tEILO+ 3 | iL98MD4vtHAGr0KXON76WRak/8DoO7DvqSxa66XGu28V/9Ny9Fpad1ZmiNISpEbY 4 | 7nXIz4Yx/HGOyemS+WLX8x7BWuLaAYNwut37CzeYfXCvKfh5istb/3dkb/4ZyRB6 5 | AuhaXBhqM0KADUGqMcGVRuMzPa0jYO45/71j9UHxAn8IH3L+fKMcDMYU6g/LVz1W 6 | eTSqpESCEBTIC4m3o8o4y3YndJSudoyV0U25MDKB1LhO238RBOU/zG+6uwUY6hHW 7 | iUSY4gcIgxgMnAesz7/OaFaGRLjlaaFX1dmHUwIBJQKCAQATit82gqD/OUw1yoct 8 | w0naXMzKFkBlEHjG7IpxV90aU0COzC6BLqIUW246+mHEqCJF9J5fEOXdX0H6OoFA 9 | X/CcYoKjtRDPi0biwBoQIG64ixdGocpJvOPJBEvxrnsUXdWXUovilXQTM2mRgHcE 10 | fty8U578MdJ7SxdX8fes5p7es2zfGHqTKVI908iObuwGcsRDUeKyP8Rxb3uGMiI6 11 | d/FNS+Gt743dURZHQHHqAuOot/L8qHvz5MhZiGA5HoaLFCaejyr/MhzSOh2dnDNH 12 | faaJDkjc5HuYOduGHnnnESYIAxRrZCIv0Qoh9NA95ugx9wM8pkqRaIr0gKxyz8D8 13 | 5eadAoGBAPkkEyFyaKkhxTpgd4CPIbn0Q9SBBB04aKfwL1DdVaVnY2ZEC2f/JUHi 14 | vKXPw41h8w5FVYXZ5QZNWX3jKVe5ZVIoMO+eKef2EHVt1d3i7NrHc0WclfZdZp/c 15 | UmZpTCcujBnILTLO3WRz8Rf/bAZ38elqfpx0WI1QR/pifDsIbvFLAoGBAJSYe2cc 16 | Teo9mmO0yWAbNRCxuWZroM692E/C5YVxvPgerQS3U7mHXBe91l55U4x0ZR1d1dT4 17 | 5dnAYDwf1lmAKOFMqQsADJ1q1iqtmTx28kE/VYdvISxK0rJIF7m1PkbqyJs6Zg0l 18 | XE/ZNYUf/0/li3g+DD1ZkfSv6+7ovVV9+IUZAoGAUM1t/QKCzxHfGdoY62yw/goI 19 | KT6ZjO+zPWKnj9kU27LUISrTRFK/+bFR8JZo75Vjlez5JH4FFsz6bgR8HHN6zomT 20 | VKH/wNou2fob2UKtrr06JGoizHFRt05f6dz2GoujD0fXTr+hv7bmaKXd2JWakORE 21 | vR7QnIi9ZfZteu36d8UCgYA8PdEpzTRYCyLqJrKA6G91eHuYOXiLKl6c4E82GVpy 22 | bU0Pv/GCkNJO0GupwnvRKESrCl2bh3/G+vaU6k/6xUEBZESH60NiaZUYOIo7G3b3 23 | 22fc9bOAqLZIRr2Co2xGQ4HCY8iB3ra4llP3swaj2ZloGSeOfkIXFuMbqnZFQOg1 24 | 9QKBgQCiy44T7QHukR+p+2RnSxyr4vYKQ+2fWbjXHuvXUoiX6qzpqhrVudkUeaLj 25 | xYzDq2ZX/NYxzYuWfnKUF/9Z9MpveCW/atZqkdpLFVEZ6KXMQElZREuGdChxoRJu 26 | e+OuNIrrfx2Xwwo45M5KPdvhRi+X/AA2dx8dCXw6j+G+MqtgMQ== 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /src/test/resources/com/trilead/ssh2/known_hosts: -------------------------------------------------------------------------------- 1 | rsa ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmzHzJwYuD1YRGEmkTgZSkqqiq/tpAQgaS6yFA6MVc3b1q2dU0g6GT8FSXpiKhFB0tk27dPZ4AGbjkqtw2xuAwIRyyiCojzUfiogKXNdP9Iu9GWvV4JLPgNMilJYonhe0Ti2ZOdVF0ae8M7YlkIEo74m26TCvpHiVx9GvwIGb2JhYyeVjoH+ghjYDzEjNNdqlWOy49x7kUYvTnoO8gwm7oQK+2BSb5XJdB6KisEc7ElBn5Y2FVVintK9CA+L7c/oPRcs3YZpxNymAPtn014vHZaWJZNJ/cskDIB5XQoq4tggv+NR4eGqQxZ7+uj5wEf1mUjnK88TAKeiw8YFUOuxzN 2 | ecdsap256 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBATGuDwTqUgPZOrE/kAtV3+tQ/DUICJ4+z3VWRXYtB7vfJCGCnfMowioD5OJqVIwMelbGPX6uoIoZyVaY9EuU24= 3 | ed25519 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKadtsQvD91EJZI9+VCeIZRpq/VsLXoWi+L0s3eZZWEN 4 | dss ssh-dss AAAAB3NzaC1kc3MAAACBAOB1n9OLz95ALPkdIWn5fSAs3EPHQNiAOOT7iBaafY/PXZToedtYCpMcY+atUZcGlz6lPMf1kBVWhhYjWn8vXDO+wsItwVoa+eb4m7ecK2gUUXj7JdobkUrsPceRW73LBuZOcKiReAvqAQRsv8XUgp6KIWThktJhT46EC7jzgdSxAAAAFQDyru7A/0ZmZnz/tayxvfBhXcnuawAAAIEAjTPSwR9C+TEVWgiqsQT9+/IXgZoNpGyvJ6VIHK1kDlxf18sv9HuZuPGDIH+Jqq3RRCvTzNLVYwbB5CSA4ugzbW+ERLq9NKD5/q/O428bPtVSNnaHsLrMp8awxzqreCmV/Q62B+PlUzWNTITrPdJe5ZNQ5lWeXnVXangyQgYAkfsAAACAZxQ9rmGck3Cz5DnXO5Nh/xAZaFK1Uf2gysT6at7cPT4/ImiYAtwstw3RYUXeAD9lqcS3QRcfeJ7WImMiDlJZaXfeYYvbrSUAqd/tujDhdPZPwihNEXmoeh93TbnAzzflqkIUQYe/7DMchH9AQq8De+6CfkvYxHdQ3jO+EE93Vyw= 5 | multiple ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBATGuDwTqUgPZOrE/kAtV3+tQ/DUICJ4+z3VWRXYtB7vfJCGCnfMowioD5OJqVIwMelbGPX6uoIoZyVaY9EuU24= 6 | multiple ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmzHzJwYuD1YRGEmkTgZSkqqiq/tpAQgaS6yFA6MVc3b1q2dU0g6GT8FSXpiKhFB0tk27dPZ4AGbjkqtw2xuAwIRyyiCojzUfiogKXNdP9Iu9GWvV4JLPgNMilJYonhe0Ti2ZOdVF0ae8M7YlkIEo74m26TCvpHiVx9GvwIGb2JhYyeVjoH+ghjYDzEjNNdqlWOy49x7kUYvTnoO8gwm7oQK+2BSb5XJdB6KisEc7ElBn5Y2FVVintK9CA+L7c/oPRcs3YZpxNymAPtn014vHZaWJZNJ/cskDIB5XQoq4tggv+NR4eGqQxZ7+uj5wEf1mUjnK88TAKeiw8YFUOuxzN 7 | -------------------------------------------------------------------------------- /src/test/resources/dropbear-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:edge 2 | ENV USERNAME testuser 3 | ENV PASSWORD testtest123 4 | ENV OPTIONS "" 5 | 6 | # Add our test user with no login shell. 7 | RUN adduser -g 'Test User' -s /bin/ash -D $USERNAME && \ 8 | echo "$USERNAME:$PASSWORD" | chpasswd 9 | 10 | COPY run.sh /run.sh 11 | RUN chmod +x run.sh 12 | 13 | EXPOSE 22 14 | CMD ["/run.sh"] 15 | 16 | COPY *.pub / 17 | RUN mkdir /home/$USERNAME/.ssh && \ 18 | chmod 0700 /home/$USERNAME/.ssh && \ 19 | cat /*.pub > /home/$USERNAME/.ssh/authorized_keys && \ 20 | chmod 0600 /home/$USERNAME/.ssh/authorized_keys && \ 21 | chown -R $USERNAME /home/$USERNAME/.ssh && \ 22 | rm -f /*.pub 23 | 24 | # Install OpenSSH server to test against 25 | # TODO[kenny]: Add consistent host keys? 26 | RUN apk add --no-cache dropbear && \ 27 | mkdir -p /etc/dropbear && \ 28 | dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key && \ 29 | dropbearkey -t ecdsa -f /etc/dropbear/dropbear_ecdsa_host_key && \ 30 | dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key 31 | -------------------------------------------------------------------------------- /src/test/resources/dropbear-server/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/ash 2 | 3 | exec /usr/sbin/dropbear -EF $OPTIONS 4 | -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/openssh-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:edge 2 | ENV USERNAME testuser 3 | ENV PASSWORD testtest123 4 | ENV OPTIONS "" 5 | 6 | # Add our test user with no login shell. 7 | RUN adduser -g 'Test User' -s /sbin/nologin -D $USERNAME && \ 8 | echo "$USERNAME:$PASSWORD" | chpasswd 9 | 10 | COPY run.sh /run.sh 11 | RUN chmod +x run.sh 12 | 13 | EXPOSE 22 14 | CMD ["/run.sh"] 15 | 16 | COPY *.pub / 17 | RUN mkdir /home/$USERNAME/.ssh && \ 18 | chmod 0700 /home/$USERNAME/.ssh && \ 19 | cat /*.pub > /home/$USERNAME/.ssh/authorized_keys && \ 20 | chmod 0600 /home/$USERNAME/.ssh/authorized_keys && \ 21 | chown -R $USERNAME /home/$USERNAME/.ssh && \ 22 | rm -f /*.pub 23 | 24 | # Install OpenSSH server to test against 25 | # TODO[kenny]: Add consistent host keys? 26 | RUN apk add --no-cache openssh-server openssh-keygen && \ 27 | ssh-keygen -A 28 | -------------------------------------------------------------------------------- /src/test/resources/openssh-server/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/ash 2 | 3 | exec /usr/sbin/sshd -d $OPTIONS 4 | --------------------------------------------------------------------------------