001: /*
002: * SSHTools - Java SSH2 API
003: *
004: * Copyright (C) 2002-2003 Lee David Painter and Contributors.
005: *
006: * Contributions made by:
007: *
008: * Brett Smith
009: * Richard Pernavas
010: * Erwin Bolwidt
011: *
012: * This program is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU General Public License
014: * as published by the Free Software Foundation; either version 2
015: * of the License, or (at your option) any later version.
016: *
017: * This program is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
020: * GNU General Public License for more details.
021: *
022: * You should have received a copy of the GNU General Public License
023: * along with this program; if not, write to the Free Software
024: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
025: */
026: package com.sshtools.j2ssh.transport.publickey;
027:
028: import com.sshtools.j2ssh.configuration.ConfigurationLoader;
029: import com.sshtools.j2ssh.io.ByteArrayReader;
030: import com.sshtools.j2ssh.io.ByteArrayWriter;
031: import com.sshtools.j2ssh.util.Hash;
032:
033: import java.io.IOException;
034:
035: import java.security.Key;
036: import java.security.NoSuchAlgorithmException;
037: import java.security.spec.KeySpec;
038:
039: import javax.crypto.Cipher;
040: import javax.crypto.SecretKeyFactory;
041: import javax.crypto.spec.DESedeKeySpec;
042: import javax.crypto.spec.IvParameterSpec;
043:
044: /**
045: *
046: *
047: * @author $author$
048: * @version $Revision: 1.22 $
049: */
050: public class SshtoolsPrivateKeyFormat extends Base64EncodedFileFormat
051: implements SshPrivateKeyFormat {
052: private static String BEGIN = "---- BEGIN SSHTOOLS ENCRYPTED PRIVATE KEY ----";
053: private static String END = "---- END SSHTOOLS ENCRYPTED PRIVATE KEY ----";
054: private int cookie = 0x52f37abe;
055:
056: /**
057: * Creates a new SshtoolsPrivateKeyFormat object.
058: *
059: * @param subject
060: * @param comment
061: */
062: public SshtoolsPrivateKeyFormat(String subject, String comment) {
063: super (BEGIN, END);
064: setHeaderValue("Subject", subject);
065: setHeaderValue("Comment", comment);
066: }
067:
068: /**
069: * Creates a new SshtoolsPrivateKeyFormat object.
070: */
071: public SshtoolsPrivateKeyFormat() {
072: super (BEGIN, END);
073: }
074:
075: /**
076: *
077: *
078: * @return
079: */
080: public String getFormatType() {
081: return "SSHTools-PrivateKey-" + super .getFormatType();
082: }
083:
084: /**
085: *
086: *
087: * @param formattedKey
088: *
089: * @return
090: */
091: public boolean isPassphraseProtected(byte[] formattedKey) {
092: try {
093: ByteArrayReader bar = new ByteArrayReader(
094: getKeyBlob(formattedKey));
095: String type = bar.readString();
096:
097: if (type.equals("none")) {
098: return false;
099: }
100:
101: if (type.equalsIgnoreCase("3des-cbc")) {
102: return true;
103: }
104: } catch (IOException ioe) {
105: }
106:
107: return false;
108: }
109:
110: /**
111: *
112: *
113: * @param formattedKey
114: * @param passphrase
115: *
116: * @return
117: *
118: * @throws InvalidSshKeyException
119: */
120: public byte[] decryptKeyblob(byte[] formattedKey, String passphrase)
121: throws InvalidSshKeyException {
122: try {
123: byte[] keyblob = getKeyBlob(formattedKey);
124: ByteArrayReader bar = new ByteArrayReader(keyblob);
125: String type = bar.readString();
126:
127: if (type.equalsIgnoreCase("3des-cbc")) {
128: // Decrypt the key
129: byte[] keydata = makePassphraseKey(passphrase);
130: byte[] iv = new byte[8];
131:
132: if (type.equals("3DES-CBC")) {
133: bar.read(iv);
134: }
135:
136: keyblob = bar.readBinaryString();
137:
138: Cipher cipher = Cipher
139: .getInstance("DESede/CBC/PKCS5Padding");
140: KeySpec keyspec = new DESedeKeySpec(keydata);
141: Key key = SecretKeyFactory.getInstance("DESede")
142: .generateSecret(keyspec);
143: cipher.init(Cipher.DECRYPT_MODE, key,
144: new IvParameterSpec(iv, 0, cipher
145: .getBlockSize()));
146:
147: ByteArrayReader data = new ByteArrayReader(cipher
148: .doFinal(keyblob));
149:
150: if (data.readInt() == cookie) {
151: keyblob = data.readBinaryString();
152: } else {
153: throw new InvalidSshKeyException(
154: "The host key is invalid, check the passphrase supplied");
155: }
156: } else {
157: keyblob = bar.readBinaryString();
158: }
159:
160: return keyblob;
161: } catch (Exception aoe) {
162: throw new InvalidSshKeyException("Failed to read host key");
163: }
164: }
165:
166: /**
167: *
168: *
169: * @param keyblob
170: * @param passphrase
171: *
172: * @return
173: */
174: public byte[] encryptKeyblob(byte[] keyblob, String passphrase) {
175: try {
176: ByteArrayWriter baw = new ByteArrayWriter();
177: String type = "none";
178:
179: if (passphrase != null) {
180: if (!passphrase.trim().equals("")) {
181: // Encrypt the data
182: type = "3DES-CBC";
183:
184: // Decrypt the key
185: byte[] keydata = makePassphraseKey(passphrase);
186: byte[] iv = new byte[8];
187: ConfigurationLoader.getRND().nextBytes(iv);
188:
189: Cipher cipher = Cipher
190: .getInstance("DESede/CBC/PKCS5Padding");
191: KeySpec keyspec = new DESedeKeySpec(keydata);
192: Key key = SecretKeyFactory.getInstance("DESede")
193: .generateSecret(keyspec);
194: cipher.init(Cipher.ENCRYPT_MODE, key,
195: new IvParameterSpec(iv, 0, cipher
196: .getBlockSize()));
197:
198: ByteArrayWriter data = new ByteArrayWriter();
199: baw.writeString(type);
200: baw.write(iv);
201: data.writeInt(cookie);
202: data.writeBinaryString(keyblob);
203:
204: // Encrypt and write
205: baw.writeBinaryString(cipher.doFinal(data
206: .toByteArray()));
207:
208: return formatKey(baw.toByteArray());
209: }
210: }
211:
212: // Write the type of encryption
213: baw.writeString(type);
214:
215: // Write the key blob
216: baw.writeBinaryString(keyblob);
217:
218: // Now set the keyblob to our new encrpyted (or not) blob
219: return formatKey(baw.toByteArray());
220: } catch (Exception ioe) {
221: return null;
222: }
223: }
224:
225: /**
226: *
227: *
228: * @param algorithm
229: *
230: * @return
231: */
232: public boolean supportsAlgorithm(String algorithm) {
233: return true;
234: }
235:
236: private byte[] makePassphraseKey(String passphrase) {
237: try {
238: // Generate the key using the passphrase
239: Hash md5 = new Hash("MD5");
240: md5.putBytes(passphrase.getBytes());
241:
242: byte[] key1 = md5.doFinal();
243: md5.reset();
244: md5.putBytes(passphrase.getBytes());
245: md5.putBytes(key1);
246:
247: byte[] key2 = md5.doFinal();
248: byte[] key = new byte[32];
249: System.arraycopy(key1, 0, key, 0, 16);
250: System.arraycopy(key2, 0, key, 16, 16);
251:
252: return key;
253: } catch (NoSuchAlgorithmException nsae) {
254: return null;
255: }
256: }
257: }
|