mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
Merge pull request #279 from hierynomus/issue-276
Support for OpenSSH new key file format (fixes #276)
This commit is contained in:
@@ -23,6 +23,8 @@ import net.schmizz.sshj.common.SSHRuntimeException;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
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.
|
* 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.
|
* 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) {
|
public Ed25519PublicKey(EdDSAPublicKeySpec spec) {
|
||||||
super(spec);
|
super(spec);
|
||||||
|
|
||||||
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName("ed25519-sha-512");
|
EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(CURVE_ED25519_SHA512);
|
||||||
if (!spec.getParams().getCurve().equals(ed25519.getCurve())) {
|
if (!spec.getParams().getCurve().equals(ed25519.getCurve())) {
|
||||||
throw new SSHRuntimeException("Cannot create Ed25519 Public Key from wrong spec");
|
throw new SSHRuntimeException("Cannot create Ed25519 Public Key from wrong spec");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<FileKeyProvider> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileKeyProvider create() {
|
||||||
|
return new OpenSSHKeyV1KeyFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return KeyFormat.OpenSSHv1.name();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KeyPair readKeyPair() throws IOException {
|
||||||
|
BufferedReader reader = new BufferedReader(resource.getReader());
|
||||||
|
try {
|
||||||
|
if (!checkHeader(reader)) {
|
||||||
|
throw new IOException("This key is not in 'openssh-key-v1' format");
|
||||||
|
}
|
||||||
|
|
||||||
|
String keyFile = readKeyFile(reader);
|
||||||
|
byte[] decode = Base64.decode(keyFile);
|
||||||
|
PlainBuffer keyBuffer = new PlainBuffer(decode);
|
||||||
|
return readDecodedKeyPair(keyBuffer);
|
||||||
|
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
throw new SSHRuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeyPair readDecodedKeyPair(final PlainBuffer keyBuffer) throws IOException, GeneralSecurityException {
|
||||||
|
byte[] bytes = new byte[AUTH_MAGIC.length];
|
||||||
|
keyBuffer.readRawBytes(bytes); // byte[] AUTH_MAGIC
|
||||||
|
if (!ByteArrayUtils.equals(bytes, 0, AUTH_MAGIC, 0, AUTH_MAGIC.length)) {
|
||||||
|
throw new IOException("This key does not contain the 'openssh-key-v1' format magic header");
|
||||||
|
}
|
||||||
|
|
||||||
|
String cipherName = keyBuffer.readString(); // string ciphername
|
||||||
|
String kdfName = keyBuffer.readString(); // string kdfname
|
||||||
|
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))));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ import net.schmizz.sshj.transport.random.BouncyCastleRandom;
|
|||||||
import net.schmizz.sshj.transport.random.JCERandom;
|
import net.schmizz.sshj.transport.random.JCERandom;
|
||||||
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
import net.schmizz.sshj.transport.random.SingletonRandomFactory;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
|
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
|
||||||
|
import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
|
import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile;
|
import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -113,7 +114,7 @@ public class DefaultConfig
|
|||||||
|
|
||||||
protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) {
|
protected void initFileKeyProviderFactories(boolean bouncyCastleRegistered) {
|
||||||
if (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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ public class SSHClient
|
|||||||
public void authPublickey(String username)
|
public void authPublickey(String username)
|
||||||
throws UserAuthException, TransportException {
|
throws UserAuthException, TransportException {
|
||||||
final String base = System.getProperty("user.home") + File.separator + ".ssh" + File.separator;
|
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 class SSHClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link KeyProvider} instance from given location on the file system. Currently only PKCS8 format
|
* Creates a {@link KeyProvider} instance from given location on the file system. Currently the following private key files are supported:
|
||||||
* private key files are supported (OpenSSH uses this format).
|
* <ul>
|
||||||
|
* <li>PKCS8 (OpenSSH uses this format)</li>
|
||||||
|
* <li>PKCS5</li>
|
||||||
|
* <li>Putty keyfile</li>
|
||||||
|
* <li>openssh-key-v1 (New OpenSSH keyfile format)</li>
|
||||||
|
* </ul>
|
||||||
* <p/>
|
* <p/>
|
||||||
*
|
*
|
||||||
* @param location the location of the key file
|
* @param location the location of the key file
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
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.*;
|
||||||
|
|
||||||
|
public 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;
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ public enum KeyFormat {
|
|||||||
PKCS5,
|
PKCS5,
|
||||||
PKCS8,
|
PKCS8,
|
||||||
OpenSSH,
|
OpenSSH,
|
||||||
|
OpenSSHv1,
|
||||||
PuTTY,
|
PuTTY,
|
||||||
Unknown
|
Unknown
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package net.schmizz.sshj.userauth.keyprovider;
|
|||||||
import net.schmizz.sshj.common.IOUtils;
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile;
|
||||||
|
|
||||||
public class KeyProviderUtil {
|
public class KeyProviderUtil {
|
||||||
|
|
||||||
@@ -88,10 +89,12 @@ public class KeyProviderUtil {
|
|||||||
|
|
||||||
private static KeyFormat keyFormatFromHeader(String header, boolean separatePubKey) {
|
private static KeyFormat keyFormatFromHeader(String header, boolean separatePubKey) {
|
||||||
if (header.startsWith("-----BEGIN") && header.endsWith("PRIVATE KEY-----")) {
|
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
|
// Can delay asking for password since have unencrypted pubkey
|
||||||
return KeyFormat.OpenSSH;
|
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;
|
return KeyFormat.PKCS8;
|
||||||
} else {
|
} else {
|
||||||
return KeyFormat.PKCS5;
|
return KeyFormat.PKCS5;
|
||||||
|
|||||||
@@ -15,28 +15,28 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.userauth.keyprovider;
|
package net.schmizz.sshj.userauth.keyprovider;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.Base64;
|
import java.io.BufferedReader;
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
import java.io.EOFException;
|
||||||
import net.schmizz.sshj.common.KeyType;
|
import java.io.IOException;
|
||||||
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.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.spec.*;
|
import java.security.spec.*;
|
||||||
import java.util.Arrays;
|
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.
|
* Represents a PKCS5-encoded key file. This is the format typically used by OpenSSH, OpenSSL, Amazon, etc.
|
||||||
*/
|
*/
|
||||||
public class PKCS5KeyFile
|
public class PKCS5KeyFile extends BaseFileKeyProvider {
|
||||||
implements FileKeyProvider {
|
|
||||||
|
|
||||||
public static class Factory
|
public static class Factory
|
||||||
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||||
@@ -74,67 +74,8 @@ public class PKCS5KeyFile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PasswordFinder pwdf;
|
|
||||||
protected Resource<?> resource;
|
|
||||||
protected KeyPair kp;
|
|
||||||
protected KeyType type;
|
|
||||||
protected byte[] data;
|
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()
|
protected KeyPair readKeyPair()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.userauth.keyprovider;
|
package net.schmizz.sshj.userauth.keyprovider;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
import java.io.IOException;
|
||||||
import net.schmizz.sshj.common.KeyType;
|
import java.security.KeyPair;
|
||||||
import net.schmizz.sshj.userauth.password.*;
|
|
||||||
import org.bouncycastle.openssl.EncryptionException;
|
import org.bouncycastle.openssl.EncryptionException;
|
||||||
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
|
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
|
||||||
import org.bouncycastle.openssl.PEMKeyPair;
|
import org.bouncycastle.openssl.PEMKeyPair;
|
||||||
@@ -27,16 +26,11 @@ import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
import java.io.IOException;
|
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
||||||
import java.io.Reader;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
/** Represents a PKCS8-encoded key file. This is the format used by OpenSSH and OpenSSL. */
|
/** Represents a PKCS8-encoded key file. This is the format used by (old-style) OpenSSH and OpenSSL. */
|
||||||
public class PKCS8KeyFile
|
public class PKCS8KeyFile extends BaseFileKeyProvider {
|
||||||
implements FileKeyProvider {
|
|
||||||
|
|
||||||
public static class Factory
|
public static class Factory
|
||||||
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||||
@@ -53,68 +47,9 @@ public class PKCS8KeyFile
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
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
|
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()
|
protected KeyPair readKeyPair()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|||||||
@@ -15,21 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.userauth.keyprovider;
|
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.io.*;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.spec.*;
|
import java.security.spec.*;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <h2>Sample PuTTY file format</h2>
|
* <h2>Sample PuTTY file format</h2>
|
||||||
@@ -56,7 +56,7 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @version $Id:$
|
* @version $Id:$
|
||||||
*/
|
*/
|
||||||
public class PuTTYKeyFile implements FileKeyProvider {
|
public class PuTTYKeyFile extends BaseFileKeyProvider {
|
||||||
|
|
||||||
public static class Factory
|
public static class Factory
|
||||||
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||||
@@ -75,56 +75,6 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
private byte[] privateKey;
|
private byte[] privateKey;
|
||||||
private byte[] publicKey;
|
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.
|
* Key type. Either "ssh-rsa" for RSA key, or "ssh-dss" for DSA key.
|
||||||
*/
|
*/
|
||||||
@@ -165,8 +115,7 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
final KeyFactory factory;
|
final KeyFactory factory;
|
||||||
try {
|
try {
|
||||||
factory = KeyFactory.getInstance("RSA");
|
factory = KeyFactory.getInstance("RSA");
|
||||||
}
|
} catch (NoSuchAlgorithmException s) {
|
||||||
catch(NoSuchAlgorithmException s) {
|
|
||||||
throw new IOException(s.getMessage(), s);
|
throw new IOException(s.getMessage(), s);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -174,8 +123,7 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
factory.generatePublic(new RSAPublicKeySpec(n, e)),
|
factory.generatePublic(new RSAPublicKeySpec(n, e)),
|
||||||
factory.generatePrivate(new RSAPrivateKeySpec(n, d))
|
factory.generatePrivate(new RSAPrivateKeySpec(n, d))
|
||||||
);
|
);
|
||||||
}
|
} catch (InvalidKeySpecException i) {
|
||||||
catch(InvalidKeySpecException i) {
|
|
||||||
throw new IOException(i.getMessage(), i);
|
throw new IOException(i.getMessage(), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,8 +142,7 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
final KeyFactory factory;
|
final KeyFactory factory;
|
||||||
try {
|
try {
|
||||||
factory = KeyFactory.getInstance("DSA");
|
factory = KeyFactory.getInstance("DSA");
|
||||||
}
|
} catch (NoSuchAlgorithmException s) {
|
||||||
catch(NoSuchAlgorithmException s) {
|
|
||||||
throw new IOException(s.getMessage(), s);
|
throw new IOException(s.getMessage(), s);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -203,12 +150,10 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
factory.generatePublic(new DSAPublicKeySpec(y, p, q, g)),
|
factory.generatePublic(new DSAPublicKeySpec(y, p, q, g)),
|
||||||
factory.generatePrivate(new DSAPrivateKeySpec(x, p, q, g))
|
factory.generatePrivate(new DSAPrivateKeySpec(x, p, q, g))
|
||||||
);
|
);
|
||||||
}
|
} catch (InvalidKeySpecException e) {
|
||||||
catch(InvalidKeySpecException e) {
|
|
||||||
throw new IOException(e.getMessage(), e);
|
throw new IOException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw new IOException(String.format("Unknown key type %s", this.getType()));
|
throw new IOException(String.format("Unknown key type %s", this.getType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,13 +169,11 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
headerName = line.substring(0, idx);
|
headerName = line.substring(0, idx);
|
||||||
headers.put(headerName, line.substring(idx + 2));
|
headers.put(headerName, line.substring(idx + 2));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
String s = payload.get(headerName);
|
String s = payload.get(headerName);
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
s = line;
|
s = line;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Append to previous line
|
// Append to previous line
|
||||||
s += line;
|
s += line;
|
||||||
}
|
}
|
||||||
@@ -238,8 +181,7 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
payload.put(headerName, s);
|
payload.put(headerName, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
r.close();
|
r.close();
|
||||||
}
|
}
|
||||||
// Retrieve keys from payload
|
// Retrieve keys from payload
|
||||||
@@ -248,19 +190,16 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
final char[] passphrase;
|
final char[] passphrase;
|
||||||
if (pwdf != null) {
|
if (pwdf != null) {
|
||||||
passphrase = pwdf.reqPassword(resource);
|
passphrase = pwdf.reqPassword(resource);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
passphrase = "".toCharArray();
|
passphrase = "".toCharArray();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
privateKey = this.decrypt(Base64.decode(payload.get("Private-Lines")), new String(passphrase));
|
privateKey = this.decrypt(Base64.decode(payload.get("Private-Lines")), new String(passphrase));
|
||||||
this.verify(new String(passphrase));
|
this.verify(new String(passphrase));
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
PasswordUtils.blankOut(passphrase);
|
PasswordUtils.blankOut(passphrase);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
privateKey = Base64.decode(payload.get("Private-Lines"));
|
privateKey = Base64.decode(payload.get("Private-Lines"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,8 +231,7 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
System.arraycopy(key2, 0, r, 20, 12);
|
System.arraycopy(key2, 0, r, 20, 12);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
} catch (NoSuchAlgorithmException e) {
|
||||||
catch(NoSuchAlgorithmException e) {
|
|
||||||
throw new IOException(e.getMessage(), e);
|
throw new IOException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,8 +275,7 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
if (!encoded.equals(reference)) {
|
if (!encoded.equals(reference)) {
|
||||||
throw new IOException("Invalid passphrase");
|
throw new IOException("Invalid passphrase");
|
||||||
}
|
}
|
||||||
}
|
} catch (GeneralSecurityException e) {
|
||||||
catch(GeneralSecurityException e) {
|
|
||||||
throw new IOException(e.getMessage(), e);
|
throw new IOException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,8 +292,7 @@ public class PuTTYKeyFile implements FileKeyProvider {
|
|||||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(expanded, 0, 32, "AES"),
|
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(expanded, 0, 32, "AES"),
|
||||||
new IvParameterSpec(new byte[16])); // initial vector=0
|
new IvParameterSpec(new byte[16])); // initial vector=0
|
||||||
return cipher.doFinal(key);
|
return cipher.doFinal(key);
|
||||||
}
|
} catch (GeneralSecurityException e) {
|
||||||
catch(GeneralSecurityException e) {
|
|
||||||
throw new IOException(e.getMessage(), e);
|
throw new IOException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.hierynomus.sshj;
|
package com.hierynomus.sshj;
|
||||||
|
|
||||||
import net.schmizz.sshj.DefaultConfig;
|
import java.io.File;
|
||||||
import net.schmizz.sshj.SSHClient;
|
import java.io.IOException;
|
||||||
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.File;
|
import net.schmizz.sshj.DefaultConfig;
|
||||||
import java.io.IOException;
|
import net.schmizz.sshj.SSHClient;
|
||||||
|
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
@@ -32,8 +32,8 @@ public class IntegrationTest {
|
|||||||
public void shouldConnect() throws IOException {
|
public void shouldConnect() throws IOException {
|
||||||
SSHClient sshClient = new SSHClient(new DefaultConfig());
|
SSHClient sshClient = new SSHClient(new DefaultConfig());
|
||||||
sshClient.addHostKeyVerifier(new OpenSSHKnownHosts(new File("/Users/ajvanerp/.ssh/known_hosts")));
|
sshClient.addHostKeyVerifier(new OpenSSHKnownHosts(new File("/Users/ajvanerp/.ssh/known_hosts")));
|
||||||
sshClient.connect("172.16.37.129");
|
sshClient.connect("172.16.37.147");
|
||||||
sshClient.authPassword("jeroen", "jeroen");
|
sshClient.authPublickey("jeroen");
|
||||||
assertThat("Is connected", sshClient.isAuthenticated());
|
assertThat("Is connected", sshClient.isAuthenticated());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package net.schmizz.sshj.keyprovider;
|
|||||||
import net.schmizz.sshj.common.KeyType;
|
import net.schmizz.sshj.common.KeyType;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
|
import net.schmizz.sshj.userauth.keyprovider.FileKeyProvider;
|
||||||
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
|
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
|
||||||
|
import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile;
|
||||||
import net.schmizz.sshj.userauth.password.PasswordFinder;
|
import net.schmizz.sshj.userauth.password.PasswordFinder;
|
||||||
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
||||||
import net.schmizz.sshj.userauth.password.Resource;
|
import net.schmizz.sshj.userauth.password.Resource;
|
||||||
@@ -30,11 +31,13 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -142,7 +145,7 @@ public class OpenSSHKeyFileTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldHaveCorrectFingerprintForED25519() throws IOException {
|
public void shouldHaveCorrectFingerprintForED25519() throws IOException {
|
||||||
OpenSSHKeyFile keyFile = new OpenSSHKeyFile();
|
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
|
||||||
keyFile.init(new File("src/test/resources/keytypes/test_ed25519"));
|
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";
|
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();
|
PublicKey aPublic = keyFile.getPublic();
|
||||||
@@ -150,6 +153,14 @@ public class OpenSSHKeyFileTest {
|
|||||||
assertThat(expected, containsString(sshjFingerprintSshjKey));
|
assertThat(expected, containsString(sshjFingerprintSshjKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldLoadED25519PrivateKey() throws IOException {
|
||||||
|
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
|
||||||
|
keyFile.init(new File("src/test/resources/keytypes/test_ed25519"));
|
||||||
|
PrivateKey aPrivate = keyFile.getPrivate();
|
||||||
|
assertThat(aPrivate.getAlgorithm(), equalTo("EdDSA"));
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup()
|
public void setup()
|
||||||
throws UnsupportedEncodingException, GeneralSecurityException {
|
throws UnsupportedEncodingException, GeneralSecurityException {
|
||||||
|
|||||||
Reference in New Issue
Block a user