From 968d4284a05e2d26951c8540408fad566a8f05eb Mon Sep 17 00:00:00 2001 From: Jeroen van Erp Date: Wed, 19 Oct 2016 12:08:51 +0100 Subject: [PATCH 1/6] Extracted common key file methods into an abstract base class --- .../keyprovider/BaseFileKeyProvider.java | 77 +++++++++++++++++ .../userauth/keyprovider/PKCS5KeyFile.java | 83 +++---------------- .../userauth/keyprovider/PKCS8KeyFile.java | 77 ++--------------- .../userauth/keyprovider/PuTTYKeyFile.java | 52 +----------- 4 files changed, 96 insertions(+), 193 deletions(-) create mode 100644 src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java new file mode 100644 index 000000000..d12445433 --- /dev/null +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java @@ -0,0 +1,77 @@ +package net.schmizz.sshj.userauth.keyprovider; + +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; + +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.userauth.password.*; + +abstract class BaseFileKeyProvider implements FileKeyProvider { + protected Resource resource; + protected PasswordFinder pwdf; + protected KeyPair kp; + + protected KeyType type; + + @Override + public void init(Reader location) { + assert location != null; + resource = new PrivateKeyReaderResource(location); + } + + @Override + public void init(Reader location, PasswordFinder pwdf) { + init(location); + this.pwdf = pwdf; + } + + @Override + public void init(File location) { + assert location != null; + resource = new PrivateKeyFileResource(location.getAbsoluteFile()); + } + + @Override + public void init(File location, PasswordFinder pwdf) { + init(location); + this.pwdf = pwdf; + } + + @Override + public void init(String privateKey, String publicKey) { + assert privateKey != null; + assert publicKey == null; + resource = new PrivateKeyStringResource(privateKey); + } + + @Override + public void init(String privateKey, String publicKey, PasswordFinder pwdf) { + init(privateKey, publicKey); + this.pwdf = pwdf; + } + + @Override + public PrivateKey getPrivate() + throws IOException { + return kp != null ? kp.getPrivate() : (kp = readKeyPair()).getPrivate(); + } + + @Override + public PublicKey getPublic() + throws IOException { + return kp != null ? kp.getPublic() : (kp = readKeyPair()).getPublic(); + } + + @Override + public KeyType getType() + throws IOException { + return type != null ? type : (type = KeyType.fromKey(getPublic())); + } + + + protected abstract KeyPair readKeyPair() throws IOException; +} diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/PKCS5KeyFile.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/PKCS5KeyFile.java index ff14c3f07..66a28cd85 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/PKCS5KeyFile.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/PKCS5KeyFile.java @@ -15,28 +15,28 @@ */ package net.schmizz.sshj.userauth.keyprovider; -import net.schmizz.sshj.common.Base64; -import net.schmizz.sshj.common.IOUtils; -import net.schmizz.sshj.common.KeyType; -import net.schmizz.sshj.transport.cipher.*; -import net.schmizz.sshj.transport.digest.Digest; -import net.schmizz.sshj.transport.digest.MD5; -import net.schmizz.sshj.userauth.password.*; - -import javax.xml.bind.DatatypeConverter; -import java.io.*; +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.security.*; import java.security.spec.*; import java.util.Arrays; +import javax.xml.bind.DatatypeConverter; + +import net.schmizz.sshj.common.Base64; +import net.schmizz.sshj.common.IOUtils; +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.transport.cipher.*; +import net.schmizz.sshj.transport.digest.Digest; +import net.schmizz.sshj.transport.digest.MD5; /** * Represents a PKCS5-encoded key file. This is the format typically used by OpenSSH, OpenSSL, Amazon, etc. */ -public class PKCS5KeyFile - implements FileKeyProvider { +public class PKCS5KeyFile extends BaseFileKeyProvider { public static class Factory implements net.schmizz.sshj.common.Factory.Named { @@ -74,67 +74,8 @@ public static class DecryptException } } - protected PasswordFinder pwdf; - protected Resource resource; - protected KeyPair kp; - protected KeyType type; protected byte[] data; - @Override - public PrivateKey getPrivate() - throws IOException { - return kp != null ? kp.getPrivate() : (kp = readKeyPair()).getPrivate(); - } - - @Override - public PublicKey getPublic() - throws IOException { - return kp != null ? kp.getPublic() : (kp = readKeyPair()).getPublic(); - } - - @Override - public KeyType getType() - throws IOException { - return type != null ? type : (type = KeyType.fromKey(getPublic())); - } - - @Override - public void init(Reader location) { - assert location != null; - resource = new PrivateKeyReaderResource(location); - } - - @Override - public void init(Reader location, PasswordFinder pwdf) { - init(location); - this.pwdf = pwdf; - } - - @Override - public void init(File location) { - assert location != null; - resource = new PrivateKeyFileResource(location.getAbsoluteFile()); - } - - @Override - public void init(File location, PasswordFinder pwdf) { - init(location); - this.pwdf = pwdf; - } - - @Override - public void init(String privateKey, String publicKey) { - assert privateKey != null; - assert publicKey == null; - resource = new PrivateKeyStringResource(privateKey); - } - - @Override - public void init(String privateKey, String publicKey, PasswordFinder pwdf) { - init(privateKey, publicKey); - this.pwdf = pwdf; - } - protected KeyPair readKeyPair() throws IOException { diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/PKCS8KeyFile.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/PKCS8KeyFile.java index b72e6ba71..26f500584 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/PKCS8KeyFile.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/PKCS8KeyFile.java @@ -15,9 +15,8 @@ */ package net.schmizz.sshj.userauth.keyprovider; -import net.schmizz.sshj.common.IOUtils; -import net.schmizz.sshj.common.KeyType; -import net.schmizz.sshj.userauth.password.*; +import java.io.IOException; +import java.security.KeyPair; import org.bouncycastle.openssl.EncryptionException; import org.bouncycastle.openssl.PEMEncryptedKeyPair; import org.bouncycastle.openssl.PEMKeyPair; @@ -27,16 +26,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.IOException; -import java.io.Reader; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; +import net.schmizz.sshj.common.IOUtils; +import net.schmizz.sshj.userauth.password.PasswordUtils; -/** Represents a PKCS8-encoded key file. This is the format used by OpenSSH and OpenSSL. */ -public class PKCS8KeyFile - implements FileKeyProvider { +/** Represents a PKCS8-encoded key file. This is the format used by (old-style) OpenSSH and OpenSSL. */ +public class PKCS8KeyFile extends BaseFileKeyProvider { public static class Factory implements net.schmizz.sshj.common.Factory.Named { @@ -53,68 +47,9 @@ public String getName() { } protected final Logger log = LoggerFactory.getLogger(getClass()); - protected PasswordFinder pwdf; - protected Resource resource; - protected KeyPair kp; - - protected KeyType type; protected char[] passphrase; // for blanking out - @Override - public PrivateKey getPrivate() - throws IOException { - return kp != null ? kp.getPrivate() : (kp = readKeyPair()).getPrivate(); - } - - @Override - public PublicKey getPublic() - throws IOException { - return kp != null ? kp.getPublic() : (kp = readKeyPair()).getPublic(); - } - - @Override - public KeyType getType() - throws IOException { - return type != null ? type : (type = KeyType.fromKey(getPublic())); - } - - @Override - public void init(Reader location) { - assert location != null; - resource = new PrivateKeyReaderResource(location); - } - - @Override - public void init(Reader location, PasswordFinder pwdf) { - init(location); - this.pwdf = pwdf; - } - - @Override - public void init(File location) { - assert location != null; - resource = new PrivateKeyFileResource(location.getAbsoluteFile()); - } - - @Override - public void init(File location, PasswordFinder pwdf) { - init(location); - this.pwdf = pwdf; - } - - @Override - public void init(String privateKey, String publicKey) { - assert privateKey != null; - assert publicKey == null; - resource = new PrivateKeyStringResource(privateKey); - } - - @Override - public void init(String privateKey, String publicKey, PasswordFinder pwdf) { - init(privateKey, publicKey); - this.pwdf = pwdf; - } protected KeyPair readKeyPair() throws IOException { diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/PuTTYKeyFile.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/PuTTYKeyFile.java index 80728e83e..a991d15f0 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/PuTTYKeyFile.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/PuTTYKeyFile.java @@ -56,7 +56,7 @@ * * @version $Id:$ */ -public class PuTTYKeyFile implements FileKeyProvider { +public class PuTTYKeyFile extends BaseFileKeyProvider { public static class Factory implements net.schmizz.sshj.common.Factory.Named { @@ -75,56 +75,6 @@ public String getName() { private byte[] privateKey; private byte[] publicKey; - private KeyPair kp; - - protected PasswordFinder pwdf; - - protected Resource resource; - - @Override - public void init(Reader location) { - this.resource = new PrivateKeyReaderResource(location); - } - - public void init(Reader location, PasswordFinder pwdf) { - this.init(location); - this.pwdf = pwdf; - } - - @Override - public void init(File location) { - resource = new PrivateKeyFileResource(location.getAbsoluteFile()); - } - - @Override - public void init(File location, PasswordFinder pwdf) { - this.init(location); - this.pwdf = pwdf; - } - - @Override - public void init(String privateKey, String publicKey) { - resource = new PrivateKeyStringResource(privateKey); - } - - @Override - public void init(String privateKey, String publicKey, PasswordFinder pwdf) { - init(privateKey, publicKey); - this.pwdf = pwdf; - } - - @Override - public PrivateKey getPrivate() - throws IOException { - return kp != null ? kp.getPrivate() : (kp = this.readKeyPair()).getPrivate(); - } - - @Override - public PublicKey getPublic() - throws IOException { - return kp != null ? kp.getPublic() : (kp = this.readKeyPair()).getPublic(); - } - /** * Key type. Either "ssh-rsa" for RSA key, or "ssh-dss" for DSA key. */ From 771751ca4c0c7b26f9b20ffffa73f60c2204159c Mon Sep 17 00:00:00 2001 From: Jeroen van Erp Date: Wed, 19 Oct 2016 14:48:06 +0100 Subject: [PATCH 2/6] Fixed license header --- .../userauth/keyprovider/BaseFileKeyProvider.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java index d12445433..c98427f3a 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package net.schmizz.sshj.userauth.keyprovider; import java.io.File; From bf34072c3aa94911288e09f7159a04f16fb0dca0 Mon Sep 17 00:00:00 2001 From: Jeroen van Erp Date: Mon, 24 Oct 2016 09:49:45 +0200 Subject: [PATCH 3/6] Reading first part of the new openssh key format --- .../java/net/schmizz/sshj/DefaultConfig.java | 3 +- .../keyprovider/OpenSSHKeyV1KeyFile.java | 117 ++++++++++++++++++ .../sshj/keyprovider/OpenSSHKeyFileTest.java | 16 ++- 3 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java diff --git a/src/main/java/net/schmizz/sshj/DefaultConfig.java b/src/main/java/net/schmizz/sshj/DefaultConfig.java index 98625521f..8ed0906f3 100644 --- a/src/main/java/net/schmizz/sshj/DefaultConfig.java +++ b/src/main/java/net/schmizz/sshj/DefaultConfig.java @@ -33,6 +33,7 @@ import net.schmizz.sshj.transport.random.JCERandom; import net.schmizz.sshj.transport.random.SingletonRandomFactory; import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile; +import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile; import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile; import org.slf4j.Logger; @@ -113,7 +114,7 @@ protected void initRandomFactory(boolean bouncyCastleRegistered) { protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) { if (bouncyCastleRegistered) { - setFileKeyProviderFactories(new PKCS8KeyFile.Factory(), new OpenSSHKeyFile.Factory(), new PuTTYKeyFile.Factory()); + setFileKeyProviderFactories(new OpenSSHKeyV1KeyFile.Factory(), new PKCS8KeyFile.Factory(), new OpenSSHKeyFile.Factory(), new PuTTYKeyFile.Factory()); } } diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java new file mode 100644 index 000000000..0597b82c9 --- /dev/null +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java @@ -0,0 +1,117 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.schmizz.sshj.userauth.keyprovider; + +import java.io.BufferedReader; +import java.io.IOException; +import java.security.KeyPair; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.schmizz.sshj.common.Base64; +import net.schmizz.sshj.common.Buffer; +import net.schmizz.sshj.common.ByteArrayUtils; +import net.schmizz.sshj.common.IOUtils; + +public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider { + private static final Logger logger = LoggerFactory.getLogger(OpenSSHKeyV1KeyFile.class); + private static final String BEGIN = "-----BEGIN "; + private static final String END = "-----END "; + private static final byte[] AUTH_MAGIC = "openssh-key-v1\0".getBytes(); + + public static class Factory + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public FileKeyProvider create() { + return new OpenSSHKeyV1KeyFile(); + } + + @Override + public String getName() { + return "openssh-key-v1"; + } + } + + @Override + protected KeyPair readKeyPair() throws IOException { + BufferedReader reader = new BufferedReader(resource.getReader()); + try { + String line = reader.readLine(); + while (line != null && !line.startsWith(BEGIN)) { + line = reader.readLine(); + } + line = line.substring(BEGIN.length()); + if (!line.startsWith("OPENSSH PRIVATE KEY-----")) { + throw new IOException("This key is not in 'openssh-key-v1' format"); + } + + StringBuffer stringBuffer = new StringBuffer(); + line = reader.readLine(); + while (!line.startsWith(END)) { + stringBuffer.append(line); + line = reader.readLine(); + } + byte[] decode = Base64.decode(stringBuffer.toString()); + System.out.println(ByteArrayUtils.printHex(decode, 0, decode.length)); + Buffer.PlainBuffer keyBuffer = new Buffer.PlainBuffer(decode); + byte[] bytes = new byte[AUTH_MAGIC.length]; + keyBuffer.readRawBytes(bytes); + if (!ByteArrayUtils.equals(bytes, 0, AUTH_MAGIC, 0, AUTH_MAGIC.length)) { + throw new IOException("This key does not contain the 'openssh-key-v1' format header"); + } + + String cipherName = keyBuffer.readString(); + String kdfName = keyBuffer.readString(); + String kdfOptions = keyBuffer.readString(); + + if ("none".equals(cipherName)) { + return readUnencrypted(keyBuffer); + } else { + logger.debug("Reading encrypted openssh-key-v1 file with cipher: " + cipherName); + + System.out.println(cipherName + " " + kdfName + " " + kdfOptions); + } + + } finally { + IOUtils.closeQuietly(reader); + } + + return null; + } + + private KeyPair readUnencrypted(final Buffer.PlainBuffer keyBuffer) throws IOException { + int i = keyBuffer.readUInt32AsInt(); + if (i != 1) { + throw new IOException("We don't support having more than 1 key in the file (yet)."); + } + logger.info("reading {} keys", i); + byte[] pubKey = keyBuffer.readBytes(); + logger.info("read key: {}", ByteArrayUtils.printHex(pubKey, 0, pubKey.length)); + int privKeyListSize = keyBuffer.readUInt32AsInt(); + if (privKeyListSize % 8 != 0) { + throw new IOException("The private key section must be a multiple of the block size (8)"); + } + int checkInt1 = keyBuffer.readUInt32AsInt(); + int checkInt2 = keyBuffer.readUInt32AsInt(); + logger.info("Read checkInts: {}, {}", checkInt1, checkInt2); + byte[] privKey = keyBuffer.readBytes(); + logger.info("read key: {}", ByteArrayUtils.printHex(privKey, 0, privKey.length)); + + return null; + } +} diff --git a/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java b/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java index 478a3399c..402fefc8a 100644 --- a/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java +++ b/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java @@ -18,6 +18,7 @@ import net.schmizz.sshj.common.KeyType; import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider; import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile; +import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; import net.schmizz.sshj.userauth.password.PasswordFinder; import net.schmizz.sshj.userauth.password.PasswordUtils; import net.schmizz.sshj.userauth.password.Resource; @@ -30,11 +31,13 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; +import java.security.PrivateKey; import java.security.PublicKey; import java.util.Arrays; import java.util.Scanner; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -142,7 +145,7 @@ public void shouldHaveCorrectFingerprintForECDSA() throws IOException, GeneralSe @Test public void shouldHaveCorrectFingerprintForED25519() throws IOException { - OpenSSHKeyFile keyFile = new OpenSSHKeyFile(); + OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile(); keyFile.init(new File("src/test/resources/keytypes/test_ed25519")); String expected = "256 MD5:d3:5e:40:72:db:08:f1:6d:0c:d7:6d:35:0d:ba:7c:32 root@sshj (ED25519)\n"; PublicKey aPublic = keyFile.getPublic(); @@ -150,6 +153,15 @@ public void shouldHaveCorrectFingerprintForED25519() throws IOException { assertThat(expected, containsString(sshjFingerprintSshjKey)); } + @Test + public void shouldLoadED25519PrivateKey() throws IOException { + OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile(); + keyFile.init(new File("src/test/resources/keytypes/test_ed25519")); + String expected = "256 MD5:d3:5e:40:72:db:08:f1:6d:0c:d7:6d:35:0d:ba:7c:32 root@sshj (ED25519)\n"; + PrivateKey aPrivate = keyFile.getPrivate(); + assertThat(aPrivate.getAlgorithm(), equalTo("ed-25519")); + } + @Before public void setup() throws UnsupportedEncodingException, GeneralSecurityException { @@ -171,4 +183,4 @@ private String readFile(String pathname) scanner.close(); } } -} \ No newline at end of file +} From f59bbccc5fec2fddb017bdc8a8348a4914263341 Mon Sep 17 00:00:00 2001 From: Jeroen van Erp Date: Fri, 28 Oct 2016 14:45:16 +0200 Subject: [PATCH 4/6] Fixed ed-25519 and openssh-key-v1 formats --- .../sshj/signature/Ed25519PublicKey.java | 4 +- .../keyprovider/OpenSSHKeyV1KeyFile.java | 160 ++++++++++++++++++ .../java/net/schmizz/sshj/DefaultConfig.java | 2 +- src/main/java/net/schmizz/sshj/SSHClient.java | 11 +- .../keyprovider/BaseFileKeyProvider.java | 2 +- .../sshj/userauth/keyprovider/KeyFormat.java | 1 + .../userauth/keyprovider/KeyProviderUtil.java | 7 +- .../keyprovider/OpenSSHKeyV1KeyFile.java | 117 ------------- .../userauth/keyprovider/PuTTYKeyFile.java | 82 ++++----- .../com/hierynomus/sshj/IntegrationTest.java | 8 +- .../sshj/keyprovider/OpenSSHKeyFileTest.java | 4 +- 11 files changed, 221 insertions(+), 177 deletions(-) create mode 100644 src/main/java/com/hierynomus/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java delete mode 100644 src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java diff --git a/src/main/java/com/hierynomus/sshj/signature/Ed25519PublicKey.java b/src/main/java/com/hierynomus/sshj/signature/Ed25519PublicKey.java index 6796309f0..a9f49bf25 100644 --- a/src/main/java/com/hierynomus/sshj/signature/Ed25519PublicKey.java +++ b/src/main/java/com/hierynomus/sshj/signature/Ed25519PublicKey.java @@ -23,6 +23,8 @@ import java.util.Arrays; +import static net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable.CURVE_ED25519_SHA512; + /** * Our own extension of the EdDSAPublicKey that comes from ECC-25519, as that class does not implement equality. * The code uses the equality of the keys as an indicator whether they're the same during host key verification. @@ -32,7 +34,7 @@ public class Ed25519PublicKey extends EdDSAPublicKey { public Ed25519PublicKey(EdDSAPublicKeySpec spec) { super(spec); - EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512"); + EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(CURVE_ED25519_SHA512); if (!spec.getParams().getCurve().equals(ed25519.getCurve())) { throw new SSHRuntimeException("Cannot create Ed25519 Public Key from wrong spec"); } diff --git a/src/main/java/com/hierynomus/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java b/src/main/java/com/hierynomus/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java new file mode 100644 index 000000000..93a5038cf --- /dev/null +++ b/src/main/java/com/hierynomus/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java @@ -0,0 +1,160 @@ +/* + * Copyright (C)2009 - SSHJ Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.hierynomus.sshj.userauth.keyprovider; + +import java.io.BufferedReader; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.PublicKey; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.i2p.crypto.eddsa.EdDSAPrivateKey; +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; +import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; +import net.schmizz.sshj.common.*; +import net.schmizz.sshj.common.Buffer.PlainBuffer; +import net.schmizz.sshj.userauth.keyprovider.BaseFileKeyProvider; +import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider; +import net.schmizz.sshj.userauth.keyprovider.KeyFormat; + +import static net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable.CURVE_ED25519_SHA512; + +/** + * Reads a key file in the new OpenSSH format. + * The format is described in the following document: https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key + */ +public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider { + private static final Logger logger = LoggerFactory.getLogger(OpenSSHKeyV1KeyFile.class); + private static final String BEGIN = "-----BEGIN "; + private static final String END = "-----END "; + private static final byte[] AUTH_MAGIC = "openssh-key-v1\0".getBytes(); + public static final String OPENSSH_PRIVATE_KEY = "OPENSSH PRIVATE KEY-----"; + + public static class Factory + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public FileKeyProvider create() { + return new OpenSSHKeyV1KeyFile(); + } + + @Override + public String getName() { + return KeyFormat.OpenSSHv1.name(); + } + } + + @Override + protected KeyPair readKeyPair() throws IOException { + BufferedReader reader = new BufferedReader(resource.getReader()); + try { + if (!checkHeader(reader)) { + throw new IOException("This key is not in 'openssh-key-v1' format"); + } + + String keyFile = readKeyFile(reader); + byte[] decode = Base64.decode(keyFile); + PlainBuffer keyBuffer = new PlainBuffer(decode); + return readDecodedKeyPair(keyBuffer); + + } catch (GeneralSecurityException e) { + throw new SSHRuntimeException(e); + } finally { + IOUtils.closeQuietly(reader); + } + } + + private KeyPair readDecodedKeyPair(final PlainBuffer keyBuffer) throws IOException, GeneralSecurityException { + byte[] bytes = new byte[AUTH_MAGIC.length]; + keyBuffer.readRawBytes(bytes); // byte[] AUTH_MAGIC + if (!ByteArrayUtils.equals(bytes, 0, AUTH_MAGIC, 0, AUTH_MAGIC.length)) { + throw new IOException("This key does not contain the 'openssh-key-v1' format magic header"); + } + + String cipherName = keyBuffer.readString(); // string ciphername + String kdfName = keyBuffer.readString(); // string kdfname + String kdfOptions = keyBuffer.readString(); // string kdfoptions + + int nrKeys = keyBuffer.readUInt32AsInt(); // int number of keys N; Should be 1 + if (nrKeys != 1) { + throw new IOException("We don't support having more than 1 key in the file (yet)."); + } + PublicKey publicKey = readPublicKey(new PlainBuffer(keyBuffer.readBytes())); // string publickey1 + PlainBuffer privateKeyBuffer = new PlainBuffer(keyBuffer.readBytes()); // string (possibly) encrypted, padded list of private keys + if ("none".equals(cipherName)) { + logger.debug("Reading unencrypted keypair"); + return readUnencrypted(privateKeyBuffer, publicKey); + } else { + logger.info("Keypair is encrypted with: " + cipherName + ", " + kdfName + ", " + kdfOptions); + throw new IOException("Cannot read encrypted keypair with " + cipherName + " yet.."); + } + } + + private PublicKey readPublicKey(final PlainBuffer plainBuffer) throws Buffer.BufferException, GeneralSecurityException { + return KeyType.fromString(plainBuffer.readString()).readPubKeyFromBuffer(plainBuffer); + } + + private String readKeyFile(final BufferedReader reader) throws IOException { + StringBuilder sb = new StringBuilder(); + String line = reader.readLine(); + while (!line.startsWith(END)) { + sb.append(line); + line = reader.readLine(); + } + return sb.toString(); + } + + private boolean checkHeader(final BufferedReader reader) throws IOException { + String line = reader.readLine(); + while (line != null && !line.startsWith(BEGIN)) { + line = reader.readLine(); + } + line = line.substring(BEGIN.length()); + return line.startsWith(OPENSSH_PRIVATE_KEY); + } + + private KeyPair readUnencrypted(final PlainBuffer keyBuffer, final PublicKey publicKey) throws IOException, GeneralSecurityException { + int privKeyListSize = keyBuffer.available(); + if (privKeyListSize % 8 != 0) { + throw new IOException("The private key section must be a multiple of the block size (8)"); + } + int checkInt1 = keyBuffer.readUInt32AsInt(); // uint32 checkint1 + int checkInt2 = keyBuffer.readUInt32AsInt(); // uint32 checkint2 + if (checkInt1 != checkInt2) { + throw new IOException("The checkInts differed, the key was not correctly decoded."); + } + // The private key section contains both the public key and the private key + String keyType = keyBuffer.readString(); // string keytype + logger.info("Read key type: {}", keyType); + + byte[] pubKey = keyBuffer.readBytes(); // string publickey (again...) + keyBuffer.readUInt32(); + byte[] privKey = new byte[32]; + keyBuffer.readRawBytes(privKey); // string privatekey + keyBuffer.readRawBytes(new byte[32]); // string publickey (again...) + String comment = keyBuffer.readString(); // string comment + byte[] padding = new byte[keyBuffer.available()]; + keyBuffer.readRawBytes(padding); // char[] padding + for (int i = 0; i < padding.length; i++) { + if ((int) padding[i] != i + 1) { + throw new IOException("Padding of key format contained wrong byte at position: " + i); + } + } + return new KeyPair(publicKey, new EdDSAPrivateKey(new EdDSAPrivateKeySpec(privKey, EdDSANamedCurveTable.getByName(CURVE_ED25519_SHA512)))); + } +} diff --git a/src/main/java/net/schmizz/sshj/DefaultConfig.java b/src/main/java/net/schmizz/sshj/DefaultConfig.java index 8ed0906f3..9f3573bf2 100644 --- a/src/main/java/net/schmizz/sshj/DefaultConfig.java +++ b/src/main/java/net/schmizz/sshj/DefaultConfig.java @@ -33,7 +33,7 @@ import net.schmizz.sshj.transport.random.JCERandom; import net.schmizz.sshj.transport.random.SingletonRandomFactory; import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile; -import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; +import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile; import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile; import org.slf4j.Logger; diff --git a/src/main/java/net/schmizz/sshj/SSHClient.java b/src/main/java/net/schmizz/sshj/SSHClient.java index 4c84cdde5..0a12698f3 100644 --- a/src/main/java/net/schmizz/sshj/SSHClient.java +++ b/src/main/java/net/schmizz/sshj/SSHClient.java @@ -316,7 +316,7 @@ public void authPassword(String username, PasswordFinder pfinder, PasswordUpdate public void authPublickey(String username) throws UserAuthException, TransportException { final String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator; - authPublickey(username, base + "id_rsa", base + "id_dsa"); + authPublickey(username, base + "id_rsa", base + "id_dsa", base + "id_ed25519", base + "id_ecdsa"); } /** @@ -524,8 +524,13 @@ public KeyProvider loadKeys(String location, char[] passphrase) } /** - * Creates a {@link KeyProvider} instance from given location on the file system. Currently only PKCS8 format - * private key files are supported (OpenSSH uses this format). + * Creates a {@link KeyProvider} instance from given location on the file system. Currently the following private key files are supported: + *
    + *
  • PKCS8 (OpenSSH uses this format)
  • + *
  • PKCS5
  • + *
  • Putty keyfile
  • + *
  • openssh-key-v1 (New OpenSSH keyfile format)
  • + *
*

* * @param location the location of the key file diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java index c98427f3a..d209e0579 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/BaseFileKeyProvider.java @@ -25,7 +25,7 @@ import net.schmizz.sshj.common.KeyType; import net.schmizz.sshj.userauth.password.*; -abstract class BaseFileKeyProvider implements FileKeyProvider { +public abstract class BaseFileKeyProvider implements FileKeyProvider { protected Resource resource; protected PasswordFinder pwdf; protected KeyPair kp; diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyFormat.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyFormat.java index 816b2bd89..6b3f5e2a4 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyFormat.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyFormat.java @@ -22,6 +22,7 @@ public enum KeyFormat { PKCS5, PKCS8, OpenSSH, + OpenSSHv1, PuTTY, Unknown } diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java index 41dc1d9ac..4df8aca20 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java @@ -18,6 +18,7 @@ import net.schmizz.sshj.common.IOUtils; import java.io.*; +import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; public class KeyProviderUtil { @@ -88,10 +89,12 @@ private static String readHeader(Reader privateKey) throws IOException { private static KeyFormat keyFormatFromHeader(String header, boolean separatePubKey) { if (header.startsWith("-----BEGIN") && header.endsWith("PRIVATE KEY-----")) { - if (separatePubKey) { + if (separatePubKey && header.contains(OpenSSHKeyV1KeyFile.OPENSSH_PRIVATE_KEY)) { + return KeyFormat.OpenSSHv1; + } else if (separatePubKey) { // Can delay asking for password since have unencrypted pubkey return KeyFormat.OpenSSH; - } else if (header.indexOf("BEGIN PRIVATE KEY") != -1 || header.indexOf("BEGIN ENCRYPTED PRIVATE KEY") != -1) { + } else if (header.contains("BEGIN PRIVATE KEY") || header.contains("BEGIN ENCRYPTED PRIVATE KEY")) { return KeyFormat.PKCS8; } else { return KeyFormat.PKCS5; diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java deleted file mode 100644 index 0597b82c9..000000000 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C)2009 - SSHJ Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.schmizz.sshj.userauth.keyprovider; - -import java.io.BufferedReader; -import java.io.IOException; -import java.security.KeyPair; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.schmizz.sshj.common.Base64; -import net.schmizz.sshj.common.Buffer; -import net.schmizz.sshj.common.ByteArrayUtils; -import net.schmizz.sshj.common.IOUtils; - -public class OpenSSHKeyV1KeyFile extends BaseFileKeyProvider { - private static final Logger logger = LoggerFactory.getLogger(OpenSSHKeyV1KeyFile.class); - private static final String BEGIN = "-----BEGIN "; - private static final String END = "-----END "; - private static final byte[] AUTH_MAGIC = "openssh-key-v1\0".getBytes(); - - public static class Factory - implements net.schmizz.sshj.common.Factory.Named { - - @Override - public FileKeyProvider create() { - return new OpenSSHKeyV1KeyFile(); - } - - @Override - public String getName() { - return "openssh-key-v1"; - } - } - - @Override - protected KeyPair readKeyPair() throws IOException { - BufferedReader reader = new BufferedReader(resource.getReader()); - try { - String line = reader.readLine(); - while (line != null && !line.startsWith(BEGIN)) { - line = reader.readLine(); - } - line = line.substring(BEGIN.length()); - if (!line.startsWith("OPENSSH PRIVATE KEY-----")) { - throw new IOException("This key is not in 'openssh-key-v1' format"); - } - - StringBuffer stringBuffer = new StringBuffer(); - line = reader.readLine(); - while (!line.startsWith(END)) { - stringBuffer.append(line); - line = reader.readLine(); - } - byte[] decode = Base64.decode(stringBuffer.toString()); - System.out.println(ByteArrayUtils.printHex(decode, 0, decode.length)); - Buffer.PlainBuffer keyBuffer = new Buffer.PlainBuffer(decode); - byte[] bytes = new byte[AUTH_MAGIC.length]; - keyBuffer.readRawBytes(bytes); - if (!ByteArrayUtils.equals(bytes, 0, AUTH_MAGIC, 0, AUTH_MAGIC.length)) { - throw new IOException("This key does not contain the 'openssh-key-v1' format header"); - } - - String cipherName = keyBuffer.readString(); - String kdfName = keyBuffer.readString(); - String kdfOptions = keyBuffer.readString(); - - if ("none".equals(cipherName)) { - return readUnencrypted(keyBuffer); - } else { - logger.debug("Reading encrypted openssh-key-v1 file with cipher: " + cipherName); - - System.out.println(cipherName + " " + kdfName + " " + kdfOptions); - } - - } finally { - IOUtils.closeQuietly(reader); - } - - return null; - } - - private KeyPair readUnencrypted(final Buffer.PlainBuffer keyBuffer) throws IOException { - int i = keyBuffer.readUInt32AsInt(); - if (i != 1) { - throw new IOException("We don't support having more than 1 key in the file (yet)."); - } - logger.info("reading {} keys", i); - byte[] pubKey = keyBuffer.readBytes(); - logger.info("read key: {}", ByteArrayUtils.printHex(pubKey, 0, pubKey.length)); - int privKeyListSize = keyBuffer.readUInt32AsInt(); - if (privKeyListSize % 8 != 0) { - throw new IOException("The private key section must be a multiple of the block size (8)"); - } - int checkInt1 = keyBuffer.readUInt32AsInt(); - int checkInt2 = keyBuffer.readUInt32AsInt(); - logger.info("Read checkInts: {}, {}", checkInt1, checkInt2); - byte[] privKey = keyBuffer.readBytes(); - logger.info("read key: {}", ByteArrayUtils.printHex(privKey, 0, privKey.length)); - - return null; - } -} diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/PuTTYKeyFile.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/PuTTYKeyFile.java index a991d15f0..54d9f08b4 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/PuTTYKeyFile.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/PuTTYKeyFile.java @@ -15,21 +15,21 @@ */ package net.schmizz.sshj.userauth.keyprovider; -import net.schmizz.sshj.common.Base64; -import net.schmizz.sshj.common.KeyType; -import net.schmizz.sshj.userauth.password.*; -import org.bouncycastle.util.encoders.Hex; - -import javax.crypto.Cipher; -import javax.crypto.Mac; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.math.BigInteger; import java.security.*; import java.security.spec.*; import java.util.HashMap; import java.util.Map; +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import org.bouncycastle.util.encoders.Hex; + +import net.schmizz.sshj.common.Base64; +import net.schmizz.sshj.common.KeyType; +import net.schmizz.sshj.userauth.password.PasswordUtils; /** *

Sample PuTTY file format

@@ -100,7 +100,7 @@ public boolean isEncrypted() { protected KeyPair readKeyPair() throws IOException { this.parseKeyPair(); - if(KeyType.RSA.equals(this.getType())) { + if (KeyType.RSA.equals(this.getType())) { final KeyReader publicKeyReader = new KeyReader(publicKey); publicKeyReader.skip(); // skip this // public key exponent @@ -115,8 +115,7 @@ protected KeyPair readKeyPair() throws IOException { final KeyFactory factory; try { factory = KeyFactory.getInstance("RSA"); - } - catch(NoSuchAlgorithmException s) { + } catch (NoSuchAlgorithmException s) { throw new IOException(s.getMessage(), s); } try { @@ -124,12 +123,11 @@ protected KeyPair readKeyPair() throws IOException { factory.generatePublic(new RSAPublicKeySpec(n, e)), factory.generatePrivate(new RSAPrivateKeySpec(n, d)) ); - } - catch(InvalidKeySpecException i) { + } catch (InvalidKeySpecException i) { throw new IOException(i.getMessage(), i); } } - if(KeyType.DSA.equals(this.getType())) { + if (KeyType.DSA.equals(this.getType())) { final KeyReader publicKeyReader = new KeyReader(publicKey); publicKeyReader.skip(); // skip this BigInteger p = publicKeyReader.readInt(); @@ -144,8 +142,7 @@ protected KeyPair readKeyPair() throws IOException { final KeyFactory factory; try { factory = KeyFactory.getInstance("DSA"); - } - catch(NoSuchAlgorithmException s) { + } catch (NoSuchAlgorithmException s) { throw new IOException(s.getMessage(), s); } try { @@ -153,12 +150,10 @@ protected KeyPair readKeyPair() throws IOException { factory.generatePublic(new DSAPublicKeySpec(y, p, q, g)), factory.generatePrivate(new DSAPrivateKeySpec(x, p, q, g)) ); - } - catch(InvalidKeySpecException e) { + } catch (InvalidKeySpecException e) { throw new IOException(e.getMessage(), e); } - } - else { + } else { throw new IOException(String.format("Unknown key type %s", this.getType())); } } @@ -169,18 +164,16 @@ protected void parseKeyPair() throws IOException { try { String headerName = null; String line; - while((line = r.readLine()) != null) { + while ((line = r.readLine()) != null) { int idx = line.indexOf(": "); - if(idx > 0) { + if (idx > 0) { headerName = line.substring(0, idx); headers.put(headerName, line.substring(idx + 2)); - } - else { + } else { String s = payload.get(headerName); - if(s == null) { + if (s == null) { s = line; - } - else { + } else { // Append to previous line s += line; } @@ -188,29 +181,25 @@ protected void parseKeyPair() throws IOException { payload.put(headerName, s); } } - } - finally { + } finally { r.close(); } // Retrieve keys from payload publicKey = Base64.decode(payload.get("Public-Lines")); - if(this.isEncrypted()) { + if (this.isEncrypted()) { final char[] passphrase; - if(pwdf != null) { + if (pwdf != null) { passphrase = pwdf.reqPassword(resource); - } - else { + } else { passphrase = "".toCharArray(); } try { privateKey = this.decrypt(Base64.decode(payload.get("Private-Lines")), new String(passphrase)); this.verify(new String(passphrase)); - } - finally { + } finally { PasswordUtils.blankOut(passphrase); } - } - else { + } else { privateKey = Base64.decode(payload.get("Private-Lines")); } } @@ -242,8 +231,7 @@ private byte[] toKey(final String passphrase) throws IOException { System.arraycopy(key2, 0, r, 20, 12); return r; - } - catch(NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { throw new IOException(e.getMessage(), e); } } @@ -256,7 +244,7 @@ private void verify(final String passphrase) throws IOException { // The key to the MAC is itself a SHA-1 hash of: MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.update("putty-private-key-file-mac-key".getBytes()); - if(passphrase != null) { + if (passphrase != null) { digest.update(passphrase.getBytes()); } final byte[] key = digest.digest(); @@ -284,11 +272,10 @@ private void verify(final String passphrase) throws IOException { final String encoded = Hex.toHexString(mac.doFinal(out.toByteArray())); final String reference = headers.get("Private-MAC"); - if(!encoded.equals(reference)) { + if (!encoded.equals(reference)) { throw new IOException("Invalid passphrase"); } - } - catch(GeneralSecurityException e) { + } catch (GeneralSecurityException e) { throw new IOException(e.getMessage(), e); } } @@ -305,8 +292,7 @@ private byte[] decrypt(final byte[] key, final String passphrase) throws IOExcep cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(expanded, 0, 32, "AES"), new IvParameterSpec(new byte[16])); // initial vector=0 return cipher.doFinal(key); - } - catch(GeneralSecurityException e) { + } catch (GeneralSecurityException e) { throw new IOException(e.getMessage(), e); } } @@ -327,14 +313,14 @@ public KeyReader(byte[] key) { */ public void skip() throws IOException { final int read = di.readInt(); - if(read != di.skipBytes(read)) { + if (read != di.skipBytes(read)) { throw new IOException(String.format("Failed to skip %d bytes", read)); } } private byte[] read() throws IOException { int len = di.readInt(); - if(len <= 0 || len > 513) { + if (len <= 0 || len > 513) { throw new IOException(String.format("Invalid length %d", len)); } byte[] r = new byte[len]; diff --git a/src/test/java/com/hierynomus/sshj/IntegrationTest.java b/src/test/java/com/hierynomus/sshj/IntegrationTest.java index 52af7e7f9..6b77b6ff2 100644 --- a/src/test/java/com/hierynomus/sshj/IntegrationTest.java +++ b/src/test/java/com/hierynomus/sshj/IntegrationTest.java @@ -18,6 +18,8 @@ import net.schmizz.sshj.DefaultConfig; import net.schmizz.sshj.SSHClient; import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts; +import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; + import org.junit.Ignore; import org.junit.Test; @@ -32,8 +34,10 @@ public class IntegrationTest { public void shouldConnect() throws IOException { SSHClient sshClient = new SSHClient(new DefaultConfig()); sshClient.addHostKeyVerifier(new OpenSSHKnownHosts(new File("/Users/ajvanerp/.ssh/known_hosts"))); - sshClient.connect("172.16.37.129"); - sshClient.authPassword("jeroen", "jeroen"); + sshClient.connect("172.16.37.147"); +// OpenSSHKeyV1KeyFile openSSHKeyV1KeyFile = new OpenSSHKeyV1KeyFile(); +// openSSHKeyV1KeyFile.init(new File("/Users/ajvanerp/.ssh/id_ed25519")); + sshClient.authPublickey("jeroen"); assertThat("Is connected", sshClient.isAuthenticated()); } } diff --git a/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java b/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java index 402fefc8a..fdf388194 100644 --- a/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java +++ b/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java @@ -18,7 +18,7 @@ import net.schmizz.sshj.common.KeyType; import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider; import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile; -import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; +import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; import net.schmizz.sshj.userauth.password.PasswordFinder; import net.schmizz.sshj.userauth.password.PasswordUtils; import net.schmizz.sshj.userauth.password.Resource; @@ -159,7 +159,7 @@ public void shouldLoadED25519PrivateKey() throws IOException { keyFile.init(new File("src/test/resources/keytypes/test_ed25519")); String expected = "256 MD5:d3:5e:40:72:db:08:f1:6d:0c:d7:6d:35:0d:ba:7c:32 root@sshj (ED25519)\n"; PrivateKey aPrivate = keyFile.getPrivate(); - assertThat(aPrivate.getAlgorithm(), equalTo("ed-25519")); + assertThat(aPrivate.getAlgorithm(), equalTo("EdDSA")); } @Before From 179b30ef4eee4144b25d3facf314ba233410f337 Mon Sep 17 00:00:00 2001 From: Jeroen van Erp Date: Fri, 28 Oct 2016 14:50:37 +0200 Subject: [PATCH 5/6] Fixed some codacy warnings --- .../java/com/hierynomus/sshj/IntegrationTest.java | 14 +++++--------- .../sshj/keyprovider/OpenSSHKeyFileTest.java | 1 - 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/hierynomus/sshj/IntegrationTest.java b/src/test/java/com/hierynomus/sshj/IntegrationTest.java index 6b77b6ff2..b6f977680 100644 --- a/src/test/java/com/hierynomus/sshj/IntegrationTest.java +++ b/src/test/java/com/hierynomus/sshj/IntegrationTest.java @@ -15,16 +15,14 @@ */ package com.hierynomus.sshj; -import net.schmizz.sshj.DefaultConfig; -import net.schmizz.sshj.SSHClient; -import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts; -import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; - +import java.io.File; +import java.io.IOException; import org.junit.Ignore; import org.junit.Test; -import java.io.File; -import java.io.IOException; +import net.schmizz.sshj.DefaultConfig; +import net.schmizz.sshj.SSHClient; +import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts; import static org.hamcrest.MatcherAssert.assertThat; @@ -35,8 +33,6 @@ public void shouldConnect() throws IOException { SSHClient sshClient = new SSHClient(new DefaultConfig()); sshClient.addHostKeyVerifier(new OpenSSHKnownHosts(new File("/Users/ajvanerp/.ssh/known_hosts"))); sshClient.connect("172.16.37.147"); -// OpenSSHKeyV1KeyFile openSSHKeyV1KeyFile = new OpenSSHKeyV1KeyFile(); -// openSSHKeyV1KeyFile.init(new File("/Users/ajvanerp/.ssh/id_ed25519")); sshClient.authPublickey("jeroen"); assertThat("Is connected", sshClient.isAuthenticated()); } diff --git a/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java b/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java index fdf388194..d39443b75 100644 --- a/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java +++ b/src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java @@ -157,7 +157,6 @@ public void shouldHaveCorrectFingerprintForED25519() throws IOException { public void shouldLoadED25519PrivateKey() throws IOException { OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile(); keyFile.init(new File("src/test/resources/keytypes/test_ed25519")); - String expected = "256 MD5:d3:5e:40:72:db:08:f1:6d:0c:d7:6d:35:0d:ba:7c:32 root@sshj (ED25519)\n"; PrivateKey aPrivate = keyFile.getPrivate(); assertThat(aPrivate.getAlgorithm(), equalTo("EdDSA")); } From 677f482a69c0656317aa62fd731e637259606760 Mon Sep 17 00:00:00 2001 From: Jeroen van Erp Date: Fri, 28 Oct 2016 16:31:23 +0200 Subject: [PATCH 6/6] Fixed text --- .../sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/hierynomus/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java b/src/main/java/com/hierynomus/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java index 93a5038cf..1d28f1487 100644 --- a/src/main/java/com/hierynomus/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java +++ b/src/main/java/com/hierynomus/sshj/userauth/keyprovider/OpenSSHKeyV1KeyFile.java @@ -101,7 +101,7 @@ private KeyPair readDecodedKeyPair(final PlainBuffer keyBuffer) throws IOExcepti return readUnencrypted(privateKeyBuffer, publicKey); } else { logger.info("Keypair is encrypted with: " + cipherName + ", " + kdfName + ", " + kdfOptions); - throw new IOException("Cannot read encrypted keypair with " + cipherName + " yet.."); + throw new IOException("Cannot read encrypted keypair with " + cipherName + " yet."); } }