mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
Removed GNUmake-related files from source control
Removed 3rd-party JARs from source control Re-introduced original BouncyCastle-dependent PKCS5KeyFile class Re-named non-BouncyCastle-dependent PKCS8KeyFile class to PKCS5KeyFile, since it really only supports PKCS5 formats anyway
This commit is contained in:
46
GNUmakefile
46
GNUmakefile
@@ -1,46 +0,0 @@
|
||||
Default: all
|
||||
|
||||
TOP=$(realpath .)
|
||||
include $(TOP)/../DeveloperTools/install/common.mk
|
||||
|
||||
RSRC=rsrc
|
||||
LIBDIR=$(RSRC)/lib
|
||||
LIB=$(subst $(SPACE),$(CLN),$(filter %.jar %.zip, $(wildcard $(LIBDIR)/*)))
|
||||
BUILD=build
|
||||
SRC=src/main/java
|
||||
DOCS=docs
|
||||
CLASSPATH="$(CLASSLIB)$(CLN)$(LIB)$(CLN)$(SRC)"
|
||||
CWD=$(shell pwd)
|
||||
|
||||
include classes.mk
|
||||
|
||||
CLASS_FILES:=$(foreach class, $(CLASSES), $(BUILD)/$(subst .,/,$(class)).class)
|
||||
PACKAGES=$(sort $(basename $(CLASSES)))
|
||||
PACKAGEDIRS=$(subst .,/,$(PACKAGES))
|
||||
|
||||
all: sshj.jar
|
||||
|
||||
sshj.jar: classes
|
||||
$(JAR) cvf $@ -C $(BUILD)/ .
|
||||
|
||||
javadocs:
|
||||
mkdir -p $(DOCS)
|
||||
$(JAVA_HOME)/bin/javadoc -d $(DOCS) -classpath $(CLASSPATH) $(PACKAGES)
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD)
|
||||
|
||||
classes: classdirs $(CLASS_FILES)
|
||||
|
||||
install: all
|
||||
cp sshj.jar $(TOP)/../jOVAL-Commercial/components/wsmv/winrs/rsrc/lib
|
||||
cp sshj.jar $(TOP)/../jOVAL-Commercial/components/provider/remote/rsrc/lib
|
||||
cp sshj.jar $(TOP)/../jOVAL-Commercial/components/sdk/dist/3rd-party
|
||||
|
||||
classdirs: $(foreach pkg, $(PACKAGEDIRS), $(BUILD)/$(pkg)/)
|
||||
|
||||
$(BUILD)/%.class: $(SRC)/%.java
|
||||
$(JAVAC) $(JAVACFLAGS) -d $(BUILD) -classpath $(CLASSPATH) $<
|
||||
|
||||
$(BUILD)/%/:
|
||||
mkdir -p $(subst PKG,,$@)
|
||||
211
classes.mk
211
classes.mk
@@ -1,211 +0,0 @@
|
||||
CLASSES=\
|
||||
com.hierynomus.sshj.backport.JavaVersion \
|
||||
com.hierynomus.sshj.backport.Jdk7HttpProxySocket \
|
||||
com.hierynomus.sshj.backport.Sockets \
|
||||
com.hierynomus.sshj.secg.SecgUtils \
|
||||
com.hierynomus.sshj.signature.Ed25519PublicKey \
|
||||
com.hierynomus.sshj.signature.SignatureEdDSA \
|
||||
com.hierynomus.sshj.transport.cipher.BlockCiphers \
|
||||
com.hierynomus.sshj.transport.cipher.ExtendedBlockCiphers \
|
||||
com.hierynomus.sshj.transport.cipher.StreamCipher \
|
||||
com.hierynomus.sshj.transport.cipher.StreamCiphers \
|
||||
com.hierynomus.sshj.transport.IdentificationStringParser \
|
||||
net.schmizz.concurrent.ErrorDeliveryUtil \
|
||||
net.schmizz.concurrent.Event \
|
||||
net.schmizz.concurrent.ExceptionChainer \
|
||||
net.schmizz.concurrent.Promise \
|
||||
net.schmizz.keepalive.Heartbeater \
|
||||
net.schmizz.keepalive.KeepAlive \
|
||||
net.schmizz.keepalive.KeepAliveProvider \
|
||||
net.schmizz.keepalive.KeepAliveRunner \
|
||||
net.schmizz.sshj.AbstractService \
|
||||
net.schmizz.sshj.AndroidConfig \
|
||||
net.schmizz.sshj.common.Base64 \
|
||||
net.schmizz.sshj.common.Buffer \
|
||||
net.schmizz.sshj.common.ByteArrayUtils \
|
||||
net.schmizz.sshj.common.DisconnectReason \
|
||||
net.schmizz.sshj.common.ErrorNotifiable \
|
||||
net.schmizz.sshj.common.Factory \
|
||||
net.schmizz.sshj.common.IOUtils \
|
||||
net.schmizz.sshj.common.KeyType \
|
||||
net.schmizz.sshj.common.Message \
|
||||
net.schmizz.sshj.common.SecurityUtils \
|
||||
net.schmizz.sshj.common.SSHException \
|
||||
net.schmizz.sshj.common.SSHPacket \
|
||||
net.schmizz.sshj.common.SSHPacketHandler \
|
||||
net.schmizz.sshj.common.SSHRuntimeException \
|
||||
net.schmizz.sshj.common.StreamCopier \
|
||||
net.schmizz.sshj.Config \
|
||||
net.schmizz.sshj.ConfigImpl \
|
||||
net.schmizz.sshj.connection.channel.AbstractChannel \
|
||||
net.schmizz.sshj.connection.channel.Channel \
|
||||
net.schmizz.sshj.connection.channel.ChannelInputStream \
|
||||
net.schmizz.sshj.connection.channel.ChannelOutputStream \
|
||||
net.schmizz.sshj.connection.channel.direct.AbstractDirectChannel \
|
||||
net.schmizz.sshj.connection.channel.direct.LocalPortForwarder \
|
||||
net.schmizz.sshj.connection.channel.direct.PTYMode \
|
||||
net.schmizz.sshj.connection.channel.direct.Session \
|
||||
net.schmizz.sshj.connection.channel.direct.SessionChannel \
|
||||
net.schmizz.sshj.connection.channel.direct.SessionFactory \
|
||||
net.schmizz.sshj.connection.channel.direct.Signal \
|
||||
net.schmizz.sshj.connection.channel.forwarded.AbstractForwardedChannel \
|
||||
net.schmizz.sshj.connection.channel.forwarded.AbstractForwardedChannelOpener \
|
||||
net.schmizz.sshj.connection.channel.forwarded.ConnectListener \
|
||||
net.schmizz.sshj.connection.channel.forwarded.ForwardedChannelOpener \
|
||||
net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder \
|
||||
net.schmizz.sshj.connection.channel.forwarded.SocketForwardingConnectListener \
|
||||
net.schmizz.sshj.connection.channel.forwarded.X11Forwarder \
|
||||
net.schmizz.sshj.connection.channel.OpenFailException \
|
||||
net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor \
|
||||
net.schmizz.sshj.connection.channel.Window \
|
||||
net.schmizz.sshj.connection.Connection \
|
||||
net.schmizz.sshj.connection.ConnectionException \
|
||||
net.schmizz.sshj.connection.ConnectionImpl \
|
||||
net.schmizz.sshj.DefaultConfig \
|
||||
net.schmizz.sshj.Service \
|
||||
net.schmizz.sshj.sftp.FileAttributes \
|
||||
net.schmizz.sshj.sftp.FileMode \
|
||||
net.schmizz.sshj.sftp.OpenMode \
|
||||
net.schmizz.sshj.sftp.PacketReader \
|
||||
net.schmizz.sshj.sftp.PacketType \
|
||||
net.schmizz.sshj.sftp.PathComponents \
|
||||
net.schmizz.sshj.sftp.PathHelper \
|
||||
net.schmizz.sshj.sftp.RandomAccessRemoteFile \
|
||||
net.schmizz.sshj.sftp.RemoteDirectory \
|
||||
net.schmizz.sshj.sftp.RemoteFile \
|
||||
net.schmizz.sshj.sftp.RemoteResource \
|
||||
net.schmizz.sshj.sftp.RemoteResourceFilter \
|
||||
net.schmizz.sshj.sftp.RemoteResourceInfo \
|
||||
net.schmizz.sshj.sftp.Request \
|
||||
net.schmizz.sshj.sftp.Requester \
|
||||
net.schmizz.sshj.sftp.Response \
|
||||
net.schmizz.sshj.sftp.SFTPClient \
|
||||
net.schmizz.sshj.sftp.SFTPEngine \
|
||||
net.schmizz.sshj.sftp.SFTPException \
|
||||
net.schmizz.sshj.sftp.SFTPFileTransfer \
|
||||
net.schmizz.sshj.sftp.SFTPPacket \
|
||||
net.schmizz.sshj.sftp.StatefulSFTPClient \
|
||||
net.schmizz.sshj.signature.AbstractSignature \
|
||||
net.schmizz.sshj.signature.Signature \
|
||||
net.schmizz.sshj.signature.SignatureDSA \
|
||||
net.schmizz.sshj.signature.SignatureECDSA \
|
||||
net.schmizz.sshj.signature.SignatureRSA \
|
||||
net.schmizz.sshj.SocketClient \
|
||||
net.schmizz.sshj.SSHClient \
|
||||
net.schmizz.sshj.transport.cipher.AES128CBC \
|
||||
net.schmizz.sshj.transport.cipher.AES128CTR \
|
||||
net.schmizz.sshj.transport.cipher.AES192CBC \
|
||||
net.schmizz.sshj.transport.cipher.AES192CTR \
|
||||
net.schmizz.sshj.transport.cipher.AES256CBC \
|
||||
net.schmizz.sshj.transport.cipher.AES256CTR \
|
||||
net.schmizz.sshj.transport.cipher.BaseCipher \
|
||||
net.schmizz.sshj.transport.cipher.BlockCipher \
|
||||
net.schmizz.sshj.transport.cipher.BlowfishCBC \
|
||||
net.schmizz.sshj.transport.cipher.Cipher \
|
||||
net.schmizz.sshj.transport.cipher.NoneCipher \
|
||||
net.schmizz.sshj.transport.cipher.TripleDESCBC \
|
||||
net.schmizz.sshj.transport.compression.Compression \
|
||||
net.schmizz.sshj.transport.compression.DelayedZlibCompression \
|
||||
net.schmizz.sshj.transport.compression.NoneCompression \
|
||||
net.schmizz.sshj.transport.compression.ZlibCompression \
|
||||
net.schmizz.sshj.transport.Converter \
|
||||
net.schmizz.sshj.transport.Decoder \
|
||||
net.schmizz.sshj.transport.digest.BaseDigest \
|
||||
net.schmizz.sshj.transport.digest.Digest \
|
||||
net.schmizz.sshj.transport.digest.MD5 \
|
||||
net.schmizz.sshj.transport.digest.SHA1 \
|
||||
net.schmizz.sshj.transport.digest.SHA256 \
|
||||
net.schmizz.sshj.transport.digest.SHA384 \
|
||||
net.schmizz.sshj.transport.digest.SHA512 \
|
||||
net.schmizz.sshj.transport.DisconnectListener \
|
||||
net.schmizz.sshj.transport.Encoder \
|
||||
net.schmizz.sshj.transport.kex.AbstractDH \
|
||||
net.schmizz.sshj.transport.kex.AbstractDHG \
|
||||
net.schmizz.sshj.transport.kex.AbstractDHGex \
|
||||
net.schmizz.sshj.transport.kex.Curve25519DH \
|
||||
net.schmizz.sshj.transport.kex.Curve25519SHA256 \
|
||||
net.schmizz.sshj.transport.kex.DH \
|
||||
net.schmizz.sshj.transport.kex.DHBase \
|
||||
net.schmizz.sshj.transport.kex.DHG1 \
|
||||
net.schmizz.sshj.transport.kex.DHG14 \
|
||||
net.schmizz.sshj.transport.kex.DHGexSHA1 \
|
||||
net.schmizz.sshj.transport.kex.DHGexSHA256 \
|
||||
net.schmizz.sshj.transport.kex.DHGroupData \
|
||||
net.schmizz.sshj.transport.kex.ECDH \
|
||||
net.schmizz.sshj.transport.kex.ECDHNistP \
|
||||
net.schmizz.sshj.transport.kex.KeyExchange \
|
||||
net.schmizz.sshj.transport.kex.KeyExchangeBase \
|
||||
net.schmizz.sshj.transport.KeyExchanger \
|
||||
net.schmizz.sshj.transport.mac.BaseMAC \
|
||||
net.schmizz.sshj.transport.mac.HMACMD5 \
|
||||
net.schmizz.sshj.transport.mac.HMACMD596 \
|
||||
net.schmizz.sshj.transport.mac.HMACSHA1 \
|
||||
net.schmizz.sshj.transport.mac.HMACSHA196 \
|
||||
net.schmizz.sshj.transport.mac.HMACSHA2256 \
|
||||
net.schmizz.sshj.transport.mac.HMACSHA2512 \
|
||||
net.schmizz.sshj.transport.mac.MAC \
|
||||
net.schmizz.sshj.transport.NegotiatedAlgorithms \
|
||||
net.schmizz.sshj.transport.Proposal \
|
||||
net.schmizz.sshj.transport.random.BouncyCastleRandom \
|
||||
net.schmizz.sshj.transport.random.JCERandom \
|
||||
net.schmizz.sshj.transport.random.Random \
|
||||
net.schmizz.sshj.transport.random.SingletonRandomFactory \
|
||||
net.schmizz.sshj.transport.Reader \
|
||||
net.schmizz.sshj.transport.Transport \
|
||||
net.schmizz.sshj.transport.TransportException \
|
||||
net.schmizz.sshj.transport.TransportImpl \
|
||||
net.schmizz.sshj.transport.verification.AlgorithmsVerifier \
|
||||
net.schmizz.sshj.transport.verification.ConsoleKnownHostsVerifier \
|
||||
net.schmizz.sshj.transport.verification.HostKeyVerifier \
|
||||
net.schmizz.sshj.transport.verification.OpenSSHKnownHosts \
|
||||
net.schmizz.sshj.transport.verification.PromiscuousVerifier \
|
||||
net.schmizz.sshj.userauth.AuthParams \
|
||||
net.schmizz.sshj.userauth.keyprovider.FileKeyProvider \
|
||||
net.schmizz.sshj.userauth.keyprovider.KeyFormat \
|
||||
net.schmizz.sshj.userauth.keyprovider.KeyPairWrapper \
|
||||
net.schmizz.sshj.userauth.keyprovider.KeyProvider \
|
||||
net.schmizz.sshj.userauth.keyprovider.KeyProviderUtil \
|
||||
net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile \
|
||||
net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile \
|
||||
net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile \
|
||||
net.schmizz.sshj.userauth.method.AbstractAuthMethod \
|
||||
net.schmizz.sshj.userauth.method.AuthGssApiWithMic \
|
||||
net.schmizz.sshj.userauth.method.AuthHostbased \
|
||||
net.schmizz.sshj.userauth.method.AuthKeyboardInteractive \
|
||||
net.schmizz.sshj.userauth.method.AuthMethod \
|
||||
net.schmizz.sshj.userauth.method.AuthNone \
|
||||
net.schmizz.sshj.userauth.method.AuthPassword \
|
||||
net.schmizz.sshj.userauth.method.AuthPublickey \
|
||||
net.schmizz.sshj.userauth.method.ChallengeResponseProvider \
|
||||
net.schmizz.sshj.userauth.method.KeyedAuthMethod \
|
||||
net.schmizz.sshj.userauth.method.PasswordResponseProvider \
|
||||
net.schmizz.sshj.userauth.password.AccountResource \
|
||||
net.schmizz.sshj.userauth.password.PasswordFinder \
|
||||
net.schmizz.sshj.userauth.password.PasswordUpdateProvider \
|
||||
net.schmizz.sshj.userauth.password.PasswordUtils \
|
||||
net.schmizz.sshj.userauth.password.PrivateKeyFileResource \
|
||||
net.schmizz.sshj.userauth.password.PrivateKeyReaderResource \
|
||||
net.schmizz.sshj.userauth.password.PrivateKeyStringResource \
|
||||
net.schmizz.sshj.userauth.password.Resource \
|
||||
net.schmizz.sshj.userauth.UserAuth \
|
||||
net.schmizz.sshj.userauth.UserAuthException \
|
||||
net.schmizz.sshj.userauth.UserAuthImpl \
|
||||
net.schmizz.sshj.xfer.AbstractFileTransfer \
|
||||
net.schmizz.sshj.xfer.FilePermission \
|
||||
net.schmizz.sshj.xfer.FileSystemFile \
|
||||
net.schmizz.sshj.xfer.FileTransfer \
|
||||
net.schmizz.sshj.xfer.InMemoryDestFile \
|
||||
net.schmizz.sshj.xfer.InMemorySourceFile \
|
||||
net.schmizz.sshj.xfer.LocalDestFile \
|
||||
net.schmizz.sshj.xfer.LocalFileFilter \
|
||||
net.schmizz.sshj.xfer.LocalSourceFile \
|
||||
net.schmizz.sshj.xfer.LoggingTransferListener \
|
||||
net.schmizz.sshj.xfer.scp.AbstractSCPClient \
|
||||
net.schmizz.sshj.xfer.scp.ScpCommandLine \
|
||||
net.schmizz.sshj.xfer.scp.SCPDownloadClient \
|
||||
net.schmizz.sshj.xfer.scp.SCPEngine \
|
||||
net.schmizz.sshj.xfer.scp.SCPException \
|
||||
net.schmizz.sshj.xfer.scp.SCPFileTransfer \
|
||||
net.schmizz.sshj.xfer.scp.SCPRemoteException \
|
||||
net.schmizz.sshj.xfer.scp.SCPUploadClient \
|
||||
net.schmizz.sshj.xfer.TransferListener
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* 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 net.schmizz.sshj.common.Base64;
|
||||
import net.schmizz.sshj.common.IOUtils;
|
||||
import net.schmizz.sshj.common.KeyType;
|
||||
import net.schmizz.sshj.transport.cipher.AES128CBC;
|
||||
import net.schmizz.sshj.transport.cipher.AES192CBC;
|
||||
import net.schmizz.sshj.transport.cipher.AES256CBC;
|
||||
import net.schmizz.sshj.transport.cipher.Cipher;
|
||||
import net.schmizz.sshj.transport.cipher.NoneCipher;
|
||||
import net.schmizz.sshj.transport.cipher.TripleDESCBC;
|
||||
import net.schmizz.sshj.transport.digest.Digest;
|
||||
import net.schmizz.sshj.transport.digest.MD5;
|
||||
import net.schmizz.sshj.userauth.password.PasswordFinder;
|
||||
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
||||
import net.schmizz.sshj.userauth.password.PrivateKeyFileResource;
|
||||
import net.schmizz.sshj.userauth.password.PrivateKeyReaderResource;
|
||||
import net.schmizz.sshj.userauth.password.PrivateKeyStringResource;
|
||||
import net.schmizz.sshj.userauth.password.Resource;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.DSAPrivateKeySpec;
|
||||
import java.security.spec.DSAPublicKeySpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.RSAPrivateKeySpec;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.util.Arrays;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
/** Represents a PKCS5-encoded key file. This is the format typically used by OpenSSH, OpenSSL, Amazon, etc. */
|
||||
public class PKCS5KeyFile
|
||||
implements FileKeyProvider {
|
||||
|
||||
public static class Factory
|
||||
implements net.schmizz.sshj.common.Factory.Named<FileKeyProvider> {
|
||||
|
||||
@Override
|
||||
public FileKeyProvider create() {
|
||||
return new PKCS5KeyFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PKCS5";
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
BufferedReader reader = new BufferedReader(resource.getReader());
|
||||
try {
|
||||
String type = null;
|
||||
String line = null;
|
||||
Cipher cipher = new NoneCipher();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
byte[] iv = new byte[0]; // salt
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith("-----BEGIN ") && line.endsWith(" PRIVATE KEY-----")) {
|
||||
int end = line.length() - 17;
|
||||
if (end > 11) {
|
||||
type = line.substring(11, line.length() - 17);
|
||||
} else {
|
||||
type = "UNKNOWN";
|
||||
}
|
||||
} else if (line.startsWith("-----END")) {
|
||||
break;
|
||||
} else if (type != null) {
|
||||
if (line.startsWith("Proc-Type: ")) {
|
||||
if (!"4,ENCRYPTED".equals(line.substring(11))) {
|
||||
throw new IOException("Unrecognized Proc-Type: " + line.substring(11));
|
||||
}
|
||||
} else if (line.startsWith("DEK-Info: ")) {
|
||||
int ptr = line.indexOf(",");
|
||||
if (ptr == -1) {
|
||||
throw new IOException("Unrecognized DEK-Info: " + line.substring(10));
|
||||
} else {
|
||||
String algorithm = line.substring(10,ptr);
|
||||
if ("DES-EDE3-CBC".equals(algorithm)) {
|
||||
cipher = new TripleDESCBC();
|
||||
iv = DatatypeConverter.parseHexBinary(line.substring(ptr+1));
|
||||
} else if ("AES-128-CBC".equals(algorithm)) {
|
||||
cipher = new AES128CBC();
|
||||
iv = DatatypeConverter.parseHexBinary(line.substring(ptr+1));
|
||||
} else if ("AES-192-CBC".equals(algorithm)) {
|
||||
cipher = new AES192CBC();
|
||||
iv = Base64.decode(line.substring(ptr+1));
|
||||
} else if ("AES-256-CBC".equals(algorithm)) {
|
||||
cipher = new AES256CBC();
|
||||
iv = Base64.decode(line.substring(ptr+1));
|
||||
} else {
|
||||
throw new IOException("Not a supported algorithm: " + algorithm);
|
||||
}
|
||||
}
|
||||
} else if (line.length() > 0) {
|
||||
sb.append(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] data = Base64.decode(sb.toString());
|
||||
if (pwdf != null) {
|
||||
boolean decrypted = false;
|
||||
do {
|
||||
CharBuffer cb = CharBuffer.wrap(pwdf.reqPassword(resource));
|
||||
ByteBuffer bb = IOUtils.UTF8.encode(cb);
|
||||
byte[] passphrase = Arrays.copyOfRange(bb.array(), bb.position(), bb.limit());
|
||||
Arrays.fill(cb.array(), '\u0000');
|
||||
Arrays.fill(bb.array(), (byte)0);
|
||||
byte[] key = new byte[cipher.getBlockSize()];
|
||||
iv = Arrays.copyOfRange(iv, 0, cipher.getIVSize());
|
||||
Digest md5 = new MD5();
|
||||
md5.init();
|
||||
int hsize = md5.getBlockSize();
|
||||
byte[] hn = new byte[key.length / hsize * hsize + (key.length % hsize == 0 ? 0 : hsize)];
|
||||
byte[] tmp = null;
|
||||
for (int i=0; i + hsize <= hn.length;) {
|
||||
if (tmp != null) {
|
||||
md5.update(tmp, 0, tmp.length);
|
||||
}
|
||||
md5.update(passphrase, 0, passphrase.length);
|
||||
md5.update(iv, 0, iv.length > 8 ? 8 : iv.length);
|
||||
tmp = md5.digest();
|
||||
System.arraycopy(tmp, 0, hn, i, tmp.length);
|
||||
i += tmp.length;
|
||||
}
|
||||
Arrays.fill(passphrase, (byte)0);
|
||||
System.arraycopy(hn, 0, key, 0, key.length);
|
||||
cipher.init(Cipher.Mode.Decrypt, key, iv);
|
||||
Arrays.fill(key, (byte)0);
|
||||
cipher.update(data, 0, data.length);
|
||||
decrypted = 0x30 == data[0];
|
||||
} while (!decrypted && pwdf.shouldRetry(resource));
|
||||
}
|
||||
if (0x30 != data[0]) {
|
||||
throw new IOException("Failed to decrypt key");
|
||||
}
|
||||
|
||||
ASN1Data asn = new ASN1Data(data);
|
||||
if ("RSA".equals(type)) {
|
||||
KeyFactory factory = KeyFactory.getInstance("RSA");
|
||||
asn.readNext();
|
||||
BigInteger modulus = asn.readNext();
|
||||
BigInteger pubExp = asn.readNext();
|
||||
BigInteger prvExp = asn.readNext();
|
||||
PublicKey pubKey = factory.generatePublic(new RSAPublicKeySpec(modulus, pubExp));
|
||||
PrivateKey prvKey = factory.generatePrivate(new RSAPrivateKeySpec(modulus, prvExp));
|
||||
return new KeyPair(pubKey, prvKey);
|
||||
} else if ("DSA".equals(type)) {
|
||||
KeyFactory factory = KeyFactory.getInstance("DSA");
|
||||
asn.readNext();
|
||||
BigInteger p = asn.readNext();
|
||||
BigInteger q = asn.readNext();
|
||||
BigInteger g = asn.readNext();
|
||||
BigInteger pub = asn.readNext();
|
||||
BigInteger prv = asn.readNext();
|
||||
PublicKey pubKey = factory.generatePublic(new DSAPublicKeySpec(pub, p, q, g));
|
||||
PrivateKey prvKey = factory.generatePrivate(new DSAPrivateKeySpec(prv, p, q, g));
|
||||
return new KeyPair(pubKey, prvKey);
|
||||
} else {
|
||||
throw new IOException("Unrecognized key type: " + type);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IOException(e);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new IOException(e);
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PKCS5KeyFile{resource=" + resource + "}";
|
||||
}
|
||||
|
||||
class ASN1Data {
|
||||
private byte[] buff;
|
||||
private int index, length;
|
||||
|
||||
ASN1Data(byte[] buff) throws IOException {
|
||||
this.buff = buff;
|
||||
index = 0;
|
||||
if (buff[index++] != (byte)0x30) {
|
||||
throw new IOException("Not ASN.1 data");
|
||||
}
|
||||
length = buff[index++] & 0xff;
|
||||
if ((length & 0x80) != 0) {
|
||||
int counter = length & 0x7f;
|
||||
length = 0;
|
||||
while (counter-- > 0) {
|
||||
length = (length << 8) + (buff[index++] & 0xff);
|
||||
}
|
||||
}
|
||||
if ((index + length) > buff.length) {
|
||||
throw new IOException("Length mismatch: " + buff.length + " != " + (index + length));
|
||||
}
|
||||
}
|
||||
|
||||
BigInteger readNext() throws IOException {
|
||||
if (index >= length) {
|
||||
throw new EOFException();
|
||||
} else if (buff[index++] != 0x02) {
|
||||
throw new IOException("Not an int code: " + Integer.toHexString(0xff & buff[index]));
|
||||
}
|
||||
int length = buff[index++] & 0xff;
|
||||
if ((length & 0x80) != 0) {
|
||||
int counter = length & 0x7f;
|
||||
length = 0;
|
||||
while (counter-- > 0) {
|
||||
length = (length << 8) + (buff[index++] & 0xff);
|
||||
}
|
||||
}
|
||||
byte[] sequence = new byte[length];
|
||||
System.arraycopy(buff, index, sequence, 0, length);
|
||||
index += length;
|
||||
return new BigInteger(sequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,47 +15,29 @@
|
||||
*/
|
||||
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.AES128CBC;
|
||||
import net.schmizz.sshj.transport.cipher.AES192CBC;
|
||||
import net.schmizz.sshj.transport.cipher.AES256CBC;
|
||||
import net.schmizz.sshj.transport.cipher.Cipher;
|
||||
import net.schmizz.sshj.transport.cipher.NoneCipher;
|
||||
import net.schmizz.sshj.transport.cipher.TripleDESCBC;
|
||||
import net.schmizz.sshj.transport.digest.Digest;
|
||||
import net.schmizz.sshj.transport.digest.MD5;
|
||||
import net.schmizz.sshj.userauth.password.PasswordFinder;
|
||||
import net.schmizz.sshj.userauth.password.PasswordUtils;
|
||||
import net.schmizz.sshj.userauth.password.PrivateKeyFileResource;
|
||||
import net.schmizz.sshj.userauth.password.PrivateKeyReaderResource;
|
||||
import net.schmizz.sshj.userauth.password.PrivateKeyStringResource;
|
||||
import net.schmizz.sshj.userauth.password.Resource;
|
||||
|
||||
import org.bouncycastle.openssl.EncryptionException;
|
||||
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
|
||||
import org.bouncycastle.openssl.PEMKeyPair;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.DSAPrivateKeySpec;
|
||||
import java.security.spec.DSAPublicKeySpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.RSAPrivateKeySpec;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.util.Arrays;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
/** Represents a PKCS8-encoded key file. This is the format used by OpenSSH and OpenSSL. */
|
||||
public class PKCS8KeyFile
|
||||
@@ -141,173 +123,51 @@ public class PKCS8KeyFile
|
||||
|
||||
protected KeyPair readKeyPair()
|
||||
throws IOException {
|
||||
BufferedReader reader = new BufferedReader(resource.getReader());
|
||||
try {
|
||||
String type = null;
|
||||
String line = null;
|
||||
Cipher cipher = new NoneCipher();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
byte[] iv = new byte[0]; // salt
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith("-----BEGIN ") && line.endsWith(" PRIVATE KEY-----")) {
|
||||
int end = line.length() - 17;
|
||||
if (end > 11) {
|
||||
type = line.substring(11, line.length() - 17);
|
||||
} else {
|
||||
type = "UNKNOWN";
|
||||
}
|
||||
} else if (line.startsWith("-----END")) {
|
||||
break;
|
||||
} else if (type != null) {
|
||||
if (line.startsWith("Proc-Type: ")) {
|
||||
if (!"4,ENCRYPTED".equals(line.substring(11))) {
|
||||
throw new IOException("Unrecognized Proc-Type: " + line.substring(11));
|
||||
}
|
||||
} else if (line.startsWith("DEK-Info: ")) {
|
||||
int ptr = line.indexOf(",");
|
||||
if (ptr == -1) {
|
||||
throw new IOException("Unrecognized DEK-Info: " + line.substring(10));
|
||||
} else {
|
||||
String algorithm = line.substring(10,ptr);
|
||||
if ("DES-EDE3-CBC".equals(algorithm)) {
|
||||
cipher = new TripleDESCBC();
|
||||
iv = DatatypeConverter.parseHexBinary(line.substring(ptr+1));
|
||||
} else if ("AES-128-CBC".equals(algorithm)) {
|
||||
cipher = new AES128CBC();
|
||||
iv = DatatypeConverter.parseHexBinary(line.substring(ptr+1));
|
||||
} else if ("AES-192-CBC".equals(algorithm)) {
|
||||
cipher = new AES192CBC();
|
||||
iv = Base64.decode(line.substring(ptr+1));
|
||||
} else if ("AES-256-CBC".equals(algorithm)) {
|
||||
cipher = new AES256CBC();
|
||||
iv = Base64.decode(line.substring(ptr+1));
|
||||
} else {
|
||||
throw new IOException("Not a supported algorithm: " + algorithm);
|
||||
}
|
||||
}
|
||||
} else if (line.length() > 0) {
|
||||
sb.append(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
KeyPair kp = null;
|
||||
|
||||
byte[] data = Base64.decode(sb.toString());
|
||||
if (pwdf != null) {
|
||||
boolean decrypted = false;
|
||||
do {
|
||||
CharBuffer cb = CharBuffer.wrap(pwdf.reqPassword(resource));
|
||||
ByteBuffer bb = IOUtils.UTF8.encode(cb);
|
||||
byte[] passphrase = Arrays.copyOfRange(bb.array(), bb.position(), bb.limit());
|
||||
Arrays.fill(cb.array(), '\u0000');
|
||||
Arrays.fill(bb.array(), (byte)0);
|
||||
byte[] key = new byte[cipher.getBlockSize()];
|
||||
iv = Arrays.copyOfRange(iv, 0, cipher.getIVSize());
|
||||
Digest md5 = new MD5();
|
||||
md5.init();
|
||||
int hsize = md5.getBlockSize();
|
||||
byte[] hn = new byte[key.length / hsize * hsize + (key.length % hsize == 0 ? 0 : hsize)];
|
||||
byte[] tmp = null;
|
||||
for (int i=0; i + hsize <= hn.length;) {
|
||||
if (tmp != null) {
|
||||
md5.update(tmp, 0, tmp.length);
|
||||
}
|
||||
md5.update(passphrase, 0, passphrase.length);
|
||||
md5.update(iv, 0, iv.length > 8 ? 8 : iv.length);
|
||||
tmp = md5.digest();
|
||||
System.arraycopy(tmp, 0, hn, i, tmp.length);
|
||||
i += tmp.length;
|
||||
for (PEMParser r = null; ; ) {
|
||||
// while the PasswordFinder tells us we should retry
|
||||
try {
|
||||
r = new PEMParser(resource.getReader());
|
||||
final Object o = r.readObject();
|
||||
|
||||
final JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
|
||||
pemConverter.setProvider("BC");
|
||||
|
||||
if (o instanceof PEMEncryptedKeyPair) {
|
||||
final PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) o;
|
||||
JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder();
|
||||
decryptorBuilder.setProvider("BC");
|
||||
try {
|
||||
passphrase = pwdf == null ? null : pwdf.reqPassword(resource);
|
||||
kp = pemConverter.getKeyPair(encryptedKeyPair.decryptKeyPair(decryptorBuilder.build(passphrase)));
|
||||
} finally {
|
||||
PasswordUtils.blankOut(passphrase);
|
||||
}
|
||||
Arrays.fill(passphrase, (byte)0);
|
||||
System.arraycopy(hn, 0, key, 0, key.length);
|
||||
cipher.init(Cipher.Mode.Decrypt, key, iv);
|
||||
Arrays.fill(key, (byte)0);
|
||||
cipher.update(data, 0, data.length);
|
||||
decrypted = 0x30 == data[0];
|
||||
} while (!decrypted && pwdf.shouldRetry(resource));
|
||||
}
|
||||
if (0x30 != data[0]) {
|
||||
throw new IOException("Failed to decrypt key");
|
||||
}
|
||||
} else if (o instanceof PEMKeyPair) {
|
||||
kp = pemConverter.getKeyPair((PEMKeyPair) o);
|
||||
} else {
|
||||
log.debug("Expected PEMEncryptedKeyPair or PEMKeyPair, got: {}", o);
|
||||
}
|
||||
|
||||
ASN1Data asn = new ASN1Data(data);
|
||||
if ("RSA".equals(type)) {
|
||||
KeyFactory factory = KeyFactory.getInstance("RSA");
|
||||
asn.readNext();
|
||||
BigInteger modulus = asn.readNext();
|
||||
BigInteger pubExp = asn.readNext();
|
||||
BigInteger prvExp = asn.readNext();
|
||||
PublicKey pubKey = factory.generatePublic(new RSAPublicKeySpec(modulus, pubExp));
|
||||
PrivateKey prvKey = factory.generatePrivate(new RSAPrivateKeySpec(modulus, prvExp));
|
||||
return new KeyPair(pubKey, prvKey);
|
||||
} else if ("DSA".equals(type)) {
|
||||
KeyFactory factory = KeyFactory.getInstance("DSA");
|
||||
asn.readNext();
|
||||
BigInteger p = asn.readNext();
|
||||
BigInteger q = asn.readNext();
|
||||
BigInteger g = asn.readNext();
|
||||
BigInteger pub = asn.readNext();
|
||||
BigInteger prv = asn.readNext();
|
||||
PublicKey pubKey = factory.generatePublic(new DSAPublicKeySpec(pub, p, q, g));
|
||||
PrivateKey prvKey = factory.generatePrivate(new DSAPrivateKeySpec(prv, p, q, g));
|
||||
return new KeyPair(pubKey, prvKey);
|
||||
} else {
|
||||
throw new IOException("Unrecognized key type: " + type);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IOException(e);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new IOException(e);
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
} catch (EncryptionException e) {
|
||||
if (pwdf != null && pwdf.shouldRetry(resource))
|
||||
continue;
|
||||
else
|
||||
throw e;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(r);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (kp == null)
|
||||
throw new IOException("Could not read key pair from: " + resource);
|
||||
return kp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PKCS8KeyFile{resource=" + resource + "}";
|
||||
}
|
||||
|
||||
class ASN1Data {
|
||||
private byte[] buff;
|
||||
private int index, length;
|
||||
|
||||
ASN1Data(byte[] buff) throws IOException {
|
||||
this.buff = buff;
|
||||
index = 0;
|
||||
if (buff[index++] != (byte)0x30) {
|
||||
throw new IOException("Not ASN.1 data");
|
||||
}
|
||||
length = buff[index++] & 0xff;
|
||||
if ((length & 0x80) != 0) {
|
||||
int counter = length & 0x7f;
|
||||
length = 0;
|
||||
while (counter-- > 0) {
|
||||
length = (length << 8) + (buff[index++] & 0xff);
|
||||
}
|
||||
}
|
||||
if ((index + length) > buff.length) {
|
||||
throw new IOException("Length mismatch: " + buff.length + " != " + (index + length));
|
||||
}
|
||||
}
|
||||
|
||||
BigInteger readNext() throws IOException {
|
||||
if (index >= length) {
|
||||
throw new EOFException();
|
||||
} else if (buff[index++] != 0x02) {
|
||||
throw new IOException("Not an int code: " + Integer.toHexString(0xff & buff[index]));
|
||||
}
|
||||
int length = buff[index++] & 0xff;
|
||||
if ((length & 0x80) != 0) {
|
||||
int counter = length & 0x7f;
|
||||
length = 0;
|
||||
while (counter-- > 0) {
|
||||
length = (length << 8) + (buff[index++] & 0xff);
|
||||
}
|
||||
}
|
||||
byte[] sequence = new byte[length];
|
||||
System.arraycopy(buff, index, sequence, 0, length);
|
||||
index += length;
|
||||
return new BigInteger(sequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user