All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sshtools.publickey.SshtoolsPrivateKeyFile Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2003-2016 SSHTOOLS Limited. All Rights Reserved.
 *
 * For product documentation visit https://www.sshtools.com/
 *
 * This file is part of J2SSH Maverick.
 *
 * J2SSH Maverick is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * J2SSH Maverick is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with J2SSH Maverick.  If not, see .
 */
package com.sshtools.publickey;

import java.io.IOException;
import java.math.BigInteger;

import com.sshtools.ssh.SshException;
import com.sshtools.ssh.SshIOException;
import com.sshtools.ssh.components.ComponentManager;
import com.sshtools.ssh.components.Digest;
import com.sshtools.ssh.components.SshCipher;
import com.sshtools.ssh.components.SshDsaPrivateKey;
import com.sshtools.ssh.components.SshDsaPublicKey;
import com.sshtools.ssh.components.SshKeyPair;
import com.sshtools.ssh.components.SshRsaPrivateKey;
import com.sshtools.ssh.components.SshRsaPublicKey;
import com.sshtools.ssh.components.jce.TripleDesCbc;
import com.sshtools.util.ByteArrayReader;
import com.sshtools.util.ByteArrayWriter;

/**
 * @author Lee David Painter
 */
class SshtoolsPrivateKeyFile extends Base64EncodedFileFormat implements
		SshPrivateKeyFile {

	public static String BEGIN = "---- BEGIN SSHTOOLS ENCRYPTED PRIVATE KEY ----";
	public static String END = "---- END SSHTOOLS ENCRYPTED PRIVATE KEY ----";
	private int cookie = 0x52f37abe;

	byte[] keyblob;

	SshtoolsPrivateKeyFile(byte[] formattedkey) throws IOException {
		super(BEGIN, END);

		// Process the keyfile
		keyblob = getKeyBlob(formattedkey);
	}

	SshtoolsPrivateKeyFile(SshKeyPair pair, String passphrase, String comment)
			throws IOException {
		super(BEGIN, END);
		setHeaderValue("Comment", comment);
		ByteArrayWriter baw = new ByteArrayWriter();

		try {
			// Generate the keyblob
			if (pair.getPrivateKey() instanceof SshDsaPrivateKey) {

				SshDsaPrivateKey key = (SshDsaPrivateKey) pair.getPrivateKey();
				SshDsaPublicKey pub = key.getPublicKey();
				baw.writeString("ssh-dss");
				baw.writeBigInteger(pub.getP());
				baw.writeBigInteger(pub.getQ());
				baw.writeBigInteger(pub.getG());
				baw.writeBigInteger(key.getX());

				keyblob = encryptKey(baw.toByteArray(), passphrase);

			} else if (pair.getPrivateKey() instanceof SshRsaPrivateKey) {

				SshRsaPrivateKey pri = (SshRsaPrivateKey) pair.getPrivateKey();
				SshRsaPublicKey pub = (SshRsaPublicKey) pair.getPublicKey();

				baw.writeString("ssh-rsa");
				baw.writeBigInteger(pub.getPublicExponent());
				baw.writeBigInteger(pub.getModulus());
				baw.writeBigInteger(pri.getPrivateExponent());

				keyblob = encryptKey(baw.toByteArray(), passphrase);
			} else {
				throw new IOException("Unsupported private key type!");
			}

		} finally {
			try {
				baw.close();
			} catch (IOException e) {
			}
		}
	}

	public String getType() {
		return "SSHTools";
	}

	public boolean supportsPassphraseChange() {
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.sshtools.publickey.SshPrivateKeyFile#isPassphraseProtected()
	 */
	public boolean isPassphraseProtected() {
		ByteArrayReader bar = new ByteArrayReader(keyblob);

		try {
			String type = bar.readString();

			if (type.equals("none")) {
				return false;
			}

			if (type.equalsIgnoreCase("3des-cbc")) {
				return true;
			}
		} catch (IOException ioe) {
		} finally {
			try {
				bar.close();
			} catch (IOException e) {
			}
		}

		return false;
	}

	private byte[] encryptKey(byte[] key, String passphrase) throws IOException {

		ByteArrayWriter baw = new ByteArrayWriter();

		try {

			String type = "none";

			if (passphrase != null) {
				if (!passphrase.trim().equals("")) {
					// Encrypt the data
					type = "3DES-CBC";

					// Decrypt the key
					byte[] keydata = makePassphraseKey(passphrase);
					byte[] iv = new byte[8];

					ComponentManager.getInstance().getRND().nextBytes(iv);

					SshCipher cipher = new TripleDesCbc();
					cipher.init(SshCipher.ENCRYPT_MODE, iv, keydata);

					ByteArrayWriter data = new ByteArrayWriter();

					try {
						baw.writeString(type);
						baw.write(iv);

						data.writeInt(cookie);
						data.writeBinaryString(key);

						if (data.size() % cipher.getBlockSize() != 0) {
							int length = cipher.getBlockSize()
									- (data.size() % cipher.getBlockSize());
							byte[] padding = new byte[length];
							for (int i = 0; i < length; i++) {
								padding[i] = (byte) length;
							}

							data.write(padding);
						}

						byte[] blob = data.toByteArray();
						cipher.transform(blob, 0, blob, 0, blob.length);

						// Encrypt and write
						baw.writeBinaryString(blob);

						return baw.toByteArray();
					} finally {
						data.close();
					}
				}
			}

			// Write the type of encryption
			baw.writeString(type);

			// Write the key blob
			baw.writeBinaryString(key);

			// Now set the keyblob to our new encrpyted (or not) blob
			return baw.toByteArray();
		} catch (SshException e) {
			throw new SshIOException(e);
		} finally {
			try {
				baw.close();
			} catch (IOException e) {
			}
		}
	}

	private byte[] decryptKey(String passphrase) throws IOException,
			InvalidPassphraseException {

		ByteArrayReader bar = new ByteArrayReader(keyblob);

		try {
			byte[] decryptedkey;

			String type = bar.readString();

			if (type.equalsIgnoreCase("3des-cbc")) {
				// Decrypt the key
				byte[] keydata = makePassphraseKey(passphrase);
				byte[] iv = new byte[8];

				if (type.equals("3DES-CBC")) {
					bar.read(iv);
				}

				decryptedkey = bar.readBinaryString();

				SshCipher cipher = new TripleDesCbc();
				cipher.init(SshCipher.DECRYPT_MODE, iv, keydata);

				cipher.transform(decryptedkey, 0, decryptedkey, 0,
						decryptedkey.length);
				ByteArrayReader data = new ByteArrayReader(decryptedkey);

				try {
					if (data.readInt() == cookie) {
						decryptedkey = data.readBinaryString();
						// Process the key into an SshPrivatekey implentation
					} else {
						throw new InvalidPassphraseException();
					}
				} finally {
					data.close();
				}
			} else {
				decryptedkey = bar.readBinaryString();
			}

			return decryptedkey;
		} catch (SshException e) {
			throw new SshIOException(e);
		} finally {
			try {
				bar.close();
			} catch (IOException e) {
			}
		}
	}

	public byte[] getFormattedKey() throws IOException {
		return formatKey(keyblob);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.sshtools.publickey.SshPrivateKeyFile#toPrivateKey(java.lang.String)
	 */
	public SshKeyPair toKeyPair(String passphrase) throws IOException,
			InvalidPassphraseException {

		ByteArrayReader bar = new ByteArrayReader(decryptKey(passphrase));

		try {
			// Process the actual key and return the key pair

			String algorithm = bar.readString();

			if (algorithm.equals("ssh-dss")) {
				BigInteger p = bar.readBigInteger();
				BigInteger q = bar.readBigInteger();
				BigInteger g = bar.readBigInteger();
				BigInteger x = bar.readBigInteger();

				SshDsaPrivateKey prv = ComponentManager.getInstance()
						.createDsaPrivateKey(p, q, g, x, g.modPow(x, p));
				SshKeyPair pair = new SshKeyPair();

				pair.setPublicKey(prv.getPublicKey());
				pair.setPrivateKey(ComponentManager.getInstance()
						.createDsaPrivateKey(p, q, g, x, g.modPow(x, p)));

				return pair;

			} else if (algorithm.equals("ssh-rsa")) {

				BigInteger publicExponent = bar.readBigInteger();
				BigInteger modulus = bar.readBigInteger();

				// Read the private key
				BigInteger privateExponent = bar.readBigInteger();

				SshKeyPair pair = new SshKeyPair();
				pair.setPublicKey(ComponentManager.getInstance()
						.createRsaPublicKey(modulus, publicExponent));
				pair.setPrivateKey(ComponentManager.getInstance()
						.createRsaPrivateKey(modulus, privateExponent));

				return pair;

			} else {
				throw new IOException("Unsupported private key algorithm type "
						+ algorithm);
			}
		} catch (SshException e) {
			throw new SshIOException(e);
		} finally {
			try {
				bar.close();
			} catch (IOException e) {
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.sshtools.publickey.SshPrivateKeyFile#changePassphrase(java.lang.String
	 * , java.lang.String)
	 */
	public void changePassphrase(String oldpassphrase, String newpassphrase)
			throws IOException, InvalidPassphraseException {
		keyblob = encryptKey(decryptKey(oldpassphrase), newpassphrase);

	}

	private byte[] makePassphraseKey(String passphrase) throws SshException {

		// Generate the key using the passphrase
		Digest md5 = (Digest) ComponentManager.getInstance().supportedDigests()
				.getInstance("MD5");
		md5.putBytes(passphrase.getBytes());

		byte[] key1 = md5.doFinal();

		md5.reset();
		md5.putBytes(passphrase.getBytes());
		md5.putBytes(key1);

		byte[] key2 = md5.doFinal();

		byte[] key = new byte[32];
		System.arraycopy(key1, 0, key, 0, 16);
		System.arraycopy(key2, 0, key, 16, 16);

		return key;

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy