1 | /******************************************************************************
|
---|
2 | *
|
---|
3 | * Copyright (c) 1998,99 by Mindbright Technology AB, Stockholm, Sweden.
|
---|
4 | * www.mindbright.se, [email protected]
|
---|
5 | *
|
---|
6 | * This program is free software; you can redistribute it and/or modify
|
---|
7 | * it under the terms of the GNU General Public License as published by
|
---|
8 | * the Free Software Foundation; either version 2 of the License, or
|
---|
9 | * (at your option) any later version.
|
---|
10 | *
|
---|
11 | * This program is distributed in the hope that it will be useful,
|
---|
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | * GNU General Public License for more details.
|
---|
15 | *
|
---|
16 | *****************************************************************************
|
---|
17 | * $Author: mats $
|
---|
18 | * $Date: 2000/08/01 22:30:52 $
|
---|
19 | * $Name: rel1-2-1 $
|
---|
20 | *****************************************************************************/
|
---|
21 | package mindbright.ssh;
|
---|
22 |
|
---|
23 | import java.io.*;
|
---|
24 | import java.math.BigInteger;
|
---|
25 |
|
---|
26 | import mindbright.security.*;
|
---|
27 |
|
---|
28 | public abstract class SSH {
|
---|
29 |
|
---|
30 | public static boolean DEBUG = false;
|
---|
31 | public static boolean DEBUGMORE = false;
|
---|
32 |
|
---|
33 | public final static boolean NETSCAPE_SECURITY_MODEL = false;
|
---|
34 |
|
---|
35 | public final static int SSH_VER_MAJOR = 1;
|
---|
36 | public final static int SSH_VER_MINOR = 5;
|
---|
37 | public final static String VER_SSHPKG = "v1.2.1";
|
---|
38 | public final static String VER_MINDTERM = "MindTerm " + VER_SSHPKG;
|
---|
39 | public final static String VER_MINDTUNL = "MindTunnel " + VER_SSHPKG;
|
---|
40 | public final static String CVS_NAME = "$Name: rel1-2-1 $";
|
---|
41 | public final static String CVS_DATE = "$Date: 2000/08/01 22:30:52 $";
|
---|
42 |
|
---|
43 | public final static int DEFAULTPORT = 22;
|
---|
44 | public final static int SESSION_KEY_LENGTH = 256; // !!! Must be multiple of 8
|
---|
45 | public final static int SERVER_KEY_LENGTH = 768;
|
---|
46 | public final static int HOST_KEY_LENGTH = 1024;
|
---|
47 |
|
---|
48 | public final static int PROTOFLAG_SCREEN_NUMBER = 1;
|
---|
49 | public final static int PROTOFLAG_HOST_IN_FWD_OPEN = 2;
|
---|
50 |
|
---|
51 | public final static int MSG_ANY = -1; // !!! Not part of protocol
|
---|
52 | public final static int MSG_NONE = 0;
|
---|
53 | public final static int MSG_DISCONNECT = 1;
|
---|
54 | public final static int SMSG_PUBLIC_KEY = 2;
|
---|
55 | public final static int CMSG_SESSION_KEY = 3;
|
---|
56 | public final static int CMSG_USER = 4;
|
---|
57 | public final static int CMSG_AUTH_RHOSTS = 5;
|
---|
58 | public final static int CMSG_AUTH_RSA = 6;
|
---|
59 | public final static int SMSG_AUTH_RSA_CHALLENGE = 7;
|
---|
60 | public final static int CMSG_AUTH_RSA_RESPONSE = 8;
|
---|
61 | public final static int CMSG_AUTH_PASSWORD = 9;
|
---|
62 | public final static int CMSG_REQUEST_PTY = 10;
|
---|
63 | public final static int CMSG_WINDOW_SIZE = 11;
|
---|
64 | public final static int CMSG_EXEC_SHELL = 12;
|
---|
65 | public final static int CMSG_EXEC_CMD = 13;
|
---|
66 | public final static int SMSG_SUCCESS = 14;
|
---|
67 | public final static int SMSG_FAILURE = 15;
|
---|
68 | public final static int CMSG_STDIN_DATA = 16;
|
---|
69 | public final static int SMSG_STDOUT_DATA = 17;
|
---|
70 | public final static int SMSG_STDERR_DATA = 18;
|
---|
71 | public final static int CMSG_EOF = 19;
|
---|
72 | public final static int SMSG_EXITSTATUS = 20;
|
---|
73 | public final static int MSG_CHANNEL_OPEN_CONFIRMATION = 21;
|
---|
74 | public final static int MSG_CHANNEL_OPEN_FAILURE = 22;
|
---|
75 | public final static int MSG_CHANNEL_DATA = 23;
|
---|
76 | public final static int MSG_CHANNEL_CLOSE = 24;
|
---|
77 | public final static int MSG_CHANNEL_CLOSE_CONFIRMATION = 25;
|
---|
78 | public final static int MSG_CHANNEL_INPUT_EOF = 24;
|
---|
79 | public final static int MSG_CHANNEL_OUTPUT_CLOSED = 25;
|
---|
80 | // OBSOLETE CMSG_X11_REQUEST_FORWARDING = 26;
|
---|
81 | public final static int SMSG_X11_OPEN = 27;
|
---|
82 | public final static int CMSG_PORT_FORWARD_REQUEST = 28;
|
---|
83 | public final static int MSG_PORT_OPEN = 29;
|
---|
84 | public final static int CMSG_AGENT_REQUEST_FORWARDING = 30;
|
---|
85 | public final static int SMSG_AGENT_OPEN = 31;
|
---|
86 | public final static int MSG_IGNORE = 32;
|
---|
87 | public final static int CMSG_EXIT_CONFIRMATION = 33;
|
---|
88 | public final static int CMSG_X11_REQUEST_FORWARDING = 34;
|
---|
89 | public final static int CMSG_AUTH_RHOSTS_RSA = 35;
|
---|
90 | public final static int MSG_DEBUG = 36;
|
---|
91 | public final static int CMSG_REQUEST_COMPRESSION = 37;
|
---|
92 | public final static int CMSG_MAX_PACKET_SIZE = 38;
|
---|
93 | public final static int CMSG_AUTH_TIS = 39;
|
---|
94 | public final static int SMSG_AUTH_TIS_CHALLENGE = 40;
|
---|
95 | public final static int CMSG_AUTH_TIS_RESPONSE = 41;
|
---|
96 |
|
---|
97 | public final static int CMSG_AUTH_SDI = 16; // !!! OUCH
|
---|
98 | public final static int CMSG_ACM_OK = 64;
|
---|
99 | public final static int CMSG_ACM_ACCESS_DENIED = 65;
|
---|
100 | public final static int CMSG_ACM_NEXT_CODE_REQUIRED = 66;
|
---|
101 | public final static int CMSG_ACM_NEXT_CODE = 67;
|
---|
102 | public final static int CMSG_ACM_NEW_PIN_REQUIRED = 68;
|
---|
103 | public final static int CMSG_ACM_NEW_PIN_ACCEPTED = 69;
|
---|
104 | public final static int CMSG_ACM_NEW_PIN_REJECTED = 70;
|
---|
105 | public final static int CMSG_ACM_NEW_PIN = 71;
|
---|
106 |
|
---|
107 | public final static int IDX_CIPHER_CLASS = 0;
|
---|
108 | public final static int IDX_CIPHER_NAME = 1;
|
---|
109 |
|
---|
110 | public final static String[][] cipherClasses = {
|
---|
111 | { "NoEncrypt", "none" }, // No encryption
|
---|
112 | { "IDEA", "idea" }, // IDEA in CFB mode
|
---|
113 | { "DES", "des" }, // DES in CBC mode
|
---|
114 | { "DES3", "3des" }, // Triple-DES in CBC mode
|
---|
115 | { null, "tss" }, // An experimental stream cipher
|
---|
116 | { "RC4", "rc4" }, // RC4
|
---|
117 | { "Blowfish", "blowfish" }, // Bruce Schneier's Blowfish
|
---|
118 | { null, "reserved" } // (not implemented now, might be though... see above)
|
---|
119 | };
|
---|
120 | public final static int CIPHER_NONE = 0; // No encryption
|
---|
121 | public final static int CIPHER_IDEA = 1; // IDEA in CFB mode
|
---|
122 | public final static int CIPHER_DES = 2; // DES in CBC mode
|
---|
123 | public final static int CIPHER_3DES = 3; // Triple-DES in CBC mode
|
---|
124 | public final static int CIPHER_TSS = 4; // An experimental stream cipher
|
---|
125 | public final static int CIPHER_RC4 = 5; // RC4
|
---|
126 | public final static int CIPHER_BLOWFISH = 6; // Bruce Schneier's Blowfish */
|
---|
127 | public final static int CIPHER_RESERVED = 7; // Reserved for 40 bit crippled encryption,
|
---|
128 | // Bernard Perrot <[email protected]>
|
---|
129 | public final static int CIPHER_NOTSUPPORTED = 8; // Indicates an unsupported cipher
|
---|
130 | public final static int CIPHER_DEFAULT = CIPHER_3DES; // Triple-DES is default block-cipher
|
---|
131 |
|
---|
132 | public final static String[] authTypeDesc = {
|
---|
133 | "_N/A_",
|
---|
134 | "rhosts",
|
---|
135 | "rsa",
|
---|
136 | "passwd",
|
---|
137 | "rhostsrsa",
|
---|
138 | "tis",
|
---|
139 | "kerberos",
|
---|
140 | "kerbtgt",
|
---|
141 | "sdi-token"
|
---|
142 | };
|
---|
143 | public final static int AUTH_RHOSTS = 1;
|
---|
144 | public final static int AUTH_RSA = 2;
|
---|
145 | public final static int AUTH_PASSWORD = 3;
|
---|
146 | public final static int AUTH_RHOSTS_RSA = 4;
|
---|
147 | public final static int AUTH_TIS = 5;
|
---|
148 | public final static int AUTH_KERBEROS = 6;
|
---|
149 | public final static int PASS_KERBEROS_TGT = 7;
|
---|
150 |
|
---|
151 | public final static int AUTH_SDI = 8;
|
---|
152 |
|
---|
153 |
|
---|
154 | public final static int AUTH_NOTSUPPORTED = authTypeDesc.length;
|
---|
155 | public final static int AUTH_DEFAULT = AUTH_PASSWORD;
|
---|
156 |
|
---|
157 |
|
---|
158 | final static String[] proxyTypes = { "none", "http", "socks4",
|
---|
159 | "socks5-proxy-dns",
|
---|
160 | "socks5-local-dns" };
|
---|
161 |
|
---|
162 | final static int[] defaultProxyPorts = { 0, 8080, 1080, 1080, 1080 };
|
---|
163 |
|
---|
164 |
|
---|
165 | public final static int PROXY_NONE = 0;
|
---|
166 | public final static int PROXY_HTTP = 1;
|
---|
167 | public final static int PROXY_SOCKS4 = 2;
|
---|
168 | public final static int PROXY_SOCKS5_DNS = 3;
|
---|
169 | public final static int PROXY_SOCKS5_IP = 4;
|
---|
170 | public final static int PROXY_NOTSUPPORTED = proxyTypes.length;
|
---|
171 |
|
---|
172 |
|
---|
173 | public final static int TTY_OP_END = 0;
|
---|
174 | public final static int TTY_OP_ISPEED = 192;
|
---|
175 | public final static int TTY_OP_OSPEED = 193;
|
---|
176 |
|
---|
177 | // These are special "channels" not associated with a channel-number
|
---|
178 | // in "SSH-sense".
|
---|
179 | //
|
---|
180 | public final static int MAIN_CHAN_NUM = -1;
|
---|
181 | public final static int CONNECT_CHAN_NUM = -2;
|
---|
182 | public final static int LISTEN_CHAN_NUM = -3;
|
---|
183 | public final static int UNKNOWN_CHAN_NUM = -4;
|
---|
184 |
|
---|
185 | // Default name of file containing set of known hosts
|
---|
186 | //
|
---|
187 | public final static String KNOWN_HOSTS_FILE = "known_hosts";
|
---|
188 |
|
---|
189 | // When verifying the server's host-key to the set of known hosts, the
|
---|
190 | // possible outcome is one of these.
|
---|
191 | //
|
---|
192 | public final static int SRV_HOSTKEY_KNOWN = 0;
|
---|
193 | public final static int SRV_HOSTKEY_NEW = 1;
|
---|
194 | public final static int SRV_HOSTKEY_CHANGED = 2;
|
---|
195 |
|
---|
196 | public static SecureRandom secureRandom;
|
---|
197 |
|
---|
198 | //
|
---|
199 | //
|
---|
200 | protected byte[] sessionKey;
|
---|
201 | protected byte[] sessionId;
|
---|
202 |
|
---|
203 | //
|
---|
204 | //
|
---|
205 | protected Cipher sndCipher;
|
---|
206 | protected Cipher rcvCipher;
|
---|
207 | protected int cipherType;
|
---|
208 |
|
---|
209 | // Server data fields
|
---|
210 | //
|
---|
211 | protected byte[] srvCookie;
|
---|
212 | protected KeyPair srvServerKey;
|
---|
213 | protected KeyPair srvHostKey;
|
---|
214 | protected int protocolFlags;
|
---|
215 | protected int supportedCiphers;
|
---|
216 | protected int supportedAuthTypes;
|
---|
217 |
|
---|
218 | protected boolean isAnSSHClient = true;
|
---|
219 |
|
---|
220 | public static String getVersionId(boolean client) {
|
---|
221 | String idStr = "SSH-" + SSH_VER_MAJOR + "." + SSH_VER_MINOR + "-";
|
---|
222 | idStr += (client ? VER_MINDTERM : VER_MINDTUNL);
|
---|
223 | return idStr;
|
---|
224 | }
|
---|
225 |
|
---|
226 | public static String[] getProxyTypes() {
|
---|
227 | return proxyTypes;
|
---|
228 | }
|
---|
229 |
|
---|
230 | public static int getProxyType(String typeName) throws IllegalArgumentException {
|
---|
231 | int i;
|
---|
232 | for(i = 0; i < proxyTypes.length; i++) {
|
---|
233 | if(proxyTypes[i].equalsIgnoreCase(typeName))
|
---|
234 | break;
|
---|
235 | }
|
---|
236 | if(i == PROXY_NOTSUPPORTED)
|
---|
237 | throw new IllegalArgumentException("Proxytype " + typeName + " not supported");
|
---|
238 |
|
---|
239 | return i;
|
---|
240 | }
|
---|
241 |
|
---|
242 | public static String listSupportedProxyTypes() {
|
---|
243 | String list = "";
|
---|
244 | int i;
|
---|
245 | for(i = 0; i < proxyTypes.length; i++) {
|
---|
246 | list += proxyTypes[i] + " ";
|
---|
247 | }
|
---|
248 | return list;
|
---|
249 | }
|
---|
250 |
|
---|
251 | public static String getCipherName(int cipherType) {
|
---|
252 | return cipherClasses[cipherType][IDX_CIPHER_NAME];
|
---|
253 | }
|
---|
254 |
|
---|
255 | public static int getCipherType(String cipherName) {
|
---|
256 | int i;
|
---|
257 | for(i = 0; i < cipherClasses.length; i++) {
|
---|
258 | String clN = cipherClasses[i][IDX_CIPHER_CLASS];
|
---|
259 | String ciN = cipherClasses[i][IDX_CIPHER_NAME];
|
---|
260 | if(ciN.equalsIgnoreCase(cipherName)) {
|
---|
261 | if(cipherClasses[i][0] == null)
|
---|
262 | i = cipherClasses.length;
|
---|
263 | break;
|
---|
264 | }
|
---|
265 | }
|
---|
266 | return i;
|
---|
267 | }
|
---|
268 |
|
---|
269 | public static String getAuthName(int authType) {
|
---|
270 | return authTypeDesc[authType];
|
---|
271 | }
|
---|
272 |
|
---|
273 | public static int getAuthType(String authName) throws IllegalArgumentException {
|
---|
274 | int i;
|
---|
275 | for(i = 1; i < SSH.authTypeDesc.length; i++) {
|
---|
276 | if(SSH.authTypeDesc[i].equalsIgnoreCase(authName))
|
---|
277 | break;
|
---|
278 | }
|
---|
279 | if(i == AUTH_NOTSUPPORTED)
|
---|
280 | throw new IllegalArgumentException("Authtype " + authName + " not supported");
|
---|
281 |
|
---|
282 | return i;
|
---|
283 | }
|
---|
284 |
|
---|
285 | static int cntListSize(String authList) {
|
---|
286 | int cnt = 1;
|
---|
287 | int i = 0, n;
|
---|
288 | while(i < authList.length() && (n = authList.indexOf(',', i)) != -1) {
|
---|
289 | i = n + 1;
|
---|
290 | cnt++;
|
---|
291 | }
|
---|
292 | return cnt;
|
---|
293 | }
|
---|
294 |
|
---|
295 | public static int[] getAuthTypes(String authList) throws IllegalArgumentException {
|
---|
296 | int len = cntListSize(authList);
|
---|
297 | int[] authTypes = new int[len];
|
---|
298 | int r, l = 0;
|
---|
299 | String type;
|
---|
300 |
|
---|
301 | for(int i = 0; i < len; i++) {
|
---|
302 | r = authList.indexOf(',', l);
|
---|
303 | if(r == -1)
|
---|
304 | r = authList.length();
|
---|
305 | type = authList.substring(l, r).trim();
|
---|
306 | authTypes[i] = getAuthType(type);
|
---|
307 | l = r + 1;
|
---|
308 | }
|
---|
309 |
|
---|
310 | return authTypes;
|
---|
311 | }
|
---|
312 |
|
---|
313 | public static String listSupportedCiphers() {
|
---|
314 | String list = "";
|
---|
315 | int i;
|
---|
316 | for(i = 0; i < cipherClasses.length; i++) {
|
---|
317 | if(cipherClasses[i][0] != null)
|
---|
318 | list += cipherClasses[i][1] + " ";
|
---|
319 | }
|
---|
320 | return list;
|
---|
321 | }
|
---|
322 |
|
---|
323 | public static String[] getCiphers() {
|
---|
324 | int i, n = 0;
|
---|
325 | for(i = 0; i < cipherClasses.length; i++) {
|
---|
326 | if(cipherClasses[i][0] != null)
|
---|
327 | n++;
|
---|
328 | }
|
---|
329 | String[] ciphers = new String[n];
|
---|
330 | n = 0;
|
---|
331 | for(i = 0; i < cipherClasses.length; i++) {
|
---|
332 | if(cipherClasses[i][0] != null)
|
---|
333 | ciphers[n++] = cipherClasses[i][1];
|
---|
334 | }
|
---|
335 | return ciphers;
|
---|
336 | }
|
---|
337 |
|
---|
338 | public static String listSupportedAuthTypes() {
|
---|
339 | String list = "";
|
---|
340 | int i;
|
---|
341 | for(i = 1; i < authTypeDesc.length; i++) {
|
---|
342 | list += authTypeDesc[i] + " ";
|
---|
343 | }
|
---|
344 | return list;
|
---|
345 | }
|
---|
346 |
|
---|
347 | public static String[] getAuthTypeList() {
|
---|
348 | String[] auths = new String[authTypeDesc.length];
|
---|
349 | for(int i = 1; i < authTypeDesc.length; i++) {
|
---|
350 | auths[i - 1] = authTypeDesc[i];
|
---|
351 | }
|
---|
352 | auths[authTypeDesc.length - 1] = "custom...";
|
---|
353 | return auths;
|
---|
354 | }
|
---|
355 |
|
---|
356 | boolean isCipherSupported(int cipherType) {
|
---|
357 | int cipherMask = (0x01 << cipherType);
|
---|
358 | if((cipherMask & supportedCiphers) != 0)
|
---|
359 | return true;
|
---|
360 | return false;
|
---|
361 | }
|
---|
362 |
|
---|
363 | boolean isAuthTypeSupported(int authType) {
|
---|
364 | int authTypeMask = (0x01 << authType);
|
---|
365 | if((authTypeMask & supportedAuthTypes) != 0)
|
---|
366 | return true;
|
---|
367 | return false;
|
---|
368 | }
|
---|
369 |
|
---|
370 | boolean isProtocolFlagSet(int protFlag) {
|
---|
371 | int protFlagMask = (0x01 << protFlag);
|
---|
372 | if((protFlagMask & protocolFlags) != 0)
|
---|
373 | return true;
|
---|
374 | return false;
|
---|
375 | }
|
---|
376 |
|
---|
377 | public static void initSeedGenerator() {
|
---|
378 | if(secureRandom != null)
|
---|
379 | return;
|
---|
380 | secureRandom = new SecureRandom();
|
---|
381 | }
|
---|
382 |
|
---|
383 | public static SecureRandom secureRandom() {
|
---|
384 | if(secureRandom == null) {
|
---|
385 | secureRandom = new SecureRandom();
|
---|
386 | }
|
---|
387 | return secureRandom;
|
---|
388 | }
|
---|
389 |
|
---|
390 | public static void log(String msg) {
|
---|
391 | if(DEBUG) System.out.println(msg);
|
---|
392 | }
|
---|
393 |
|
---|
394 | public static void logExtra(String msg) {
|
---|
395 | if(DEBUGMORE) System.out.println(msg);
|
---|
396 | }
|
---|
397 |
|
---|
398 | public static void logDebug(String msg) {
|
---|
399 | if(DEBUG) System.out.println(msg);
|
---|
400 | }
|
---|
401 |
|
---|
402 | public static void logIgnore(SSHPduInputStream pdu) {
|
---|
403 | if(DEBUG) System.out.println("MSG_IGNORE received...(len = " + pdu.length + ")");
|
---|
404 | }
|
---|
405 |
|
---|
406 | void generateSessionId() throws IOException {
|
---|
407 | byte[] message;
|
---|
408 | byte[] srvKey = ((RSAPublicKey)srvServerKey.getPublic()).getN().toByteArray();
|
---|
409 | byte[] hstKey = ((RSAPublicKey)srvHostKey.getPublic()).getN().toByteArray();
|
---|
410 | int i, len = srvKey.length + hstKey.length + srvCookie.length;
|
---|
411 |
|
---|
412 | if(srvKey[0] == 0)
|
---|
413 | len -= 1;
|
---|
414 | if(hstKey[0] == 0)
|
---|
415 | len -= 1;
|
---|
416 |
|
---|
417 | message = new byte[len];
|
---|
418 |
|
---|
419 | if(hstKey[0] == 0) {
|
---|
420 | System.arraycopy(hstKey, 1, message, 0, hstKey.length - 1);
|
---|
421 | len = hstKey.length - 1;
|
---|
422 | } else {
|
---|
423 | System.arraycopy(hstKey, 0, message, 0, hstKey.length);
|
---|
424 | len = hstKey.length;
|
---|
425 | }
|
---|
426 |
|
---|
427 | if(srvKey[0] == 0) {
|
---|
428 | System.arraycopy(srvKey, 1, message, len, srvKey.length - 1);
|
---|
429 | len += srvKey.length - 1;
|
---|
430 | } else {
|
---|
431 | System.arraycopy(srvKey, 0, message, len, srvKey.length);
|
---|
432 | len += srvKey.length;
|
---|
433 | }
|
---|
434 |
|
---|
435 | System.arraycopy(srvCookie, 0, message, len, srvCookie.length);
|
---|
436 |
|
---|
437 | try {
|
---|
438 | MessageDigest md5;
|
---|
439 | md5 = MessageDigest.getInstance("MD5");
|
---|
440 | md5.update(message);
|
---|
441 | sessionId = md5.digest();
|
---|
442 | } catch(Exception e) {
|
---|
443 | throw new IOException("MD5 not implemented, can't generate session-id");
|
---|
444 | }
|
---|
445 | }
|
---|
446 |
|
---|
447 | protected void initClientCipher() throws IOException {
|
---|
448 | initCipher(false);
|
---|
449 | }
|
---|
450 |
|
---|
451 | protected void initServerCipher() throws IOException {
|
---|
452 | initCipher(true);
|
---|
453 | }
|
---|
454 |
|
---|
455 | protected void initCipher(boolean server) throws IOException {
|
---|
456 | sndCipher = Cipher.getInstance(cipherClasses[cipherType][0]);
|
---|
457 | rcvCipher = Cipher.getInstance(cipherClasses[cipherType][0]);
|
---|
458 |
|
---|
459 | if(sndCipher == null) {
|
---|
460 | throw new IOException("Cipher " + cipherClasses[cipherType][1] + " not found, can't use it");
|
---|
461 | }
|
---|
462 |
|
---|
463 | if(cipherType == CIPHER_RC4) {
|
---|
464 | if(server) {
|
---|
465 | int len = sessionKey.length / 2;
|
---|
466 | byte[] key = new byte[len];
|
---|
467 | System.arraycopy(sessionKey, 0, key, 0, len);
|
---|
468 | sndCipher.setKey(key);
|
---|
469 | System.arraycopy(sessionKey, len, key, 0, len);
|
---|
470 | rcvCipher.setKey(key);
|
---|
471 | } else {
|
---|
472 | int len = sessionKey.length / 2;
|
---|
473 | byte[] key = new byte[len];
|
---|
474 | System.arraycopy(sessionKey, 0, key, 0, len);
|
---|
475 | rcvCipher.setKey(key);
|
---|
476 | System.arraycopy(sessionKey, len, key, 0, len);
|
---|
477 | sndCipher.setKey(key);
|
---|
478 | }
|
---|
479 | } else {
|
---|
480 | sndCipher.setKey(sessionKey);
|
---|
481 | rcvCipher.setKey(sessionKey);
|
---|
482 | }
|
---|
483 | }
|
---|
484 |
|
---|
485 | public static String generateKeyFiles(KeyPair kp, String fileName, String passwd, String comment)
|
---|
486 | throws IOException {
|
---|
487 | SSHRSAKeyFile.createKeyFile(kp, passwd, fileName, comment);
|
---|
488 | RSAPublicKey pubKey = (RSAPublicKey)kp.getPublic();
|
---|
489 | SSHRSAPublicKeyString pks = new SSHRSAPublicKeyString("", comment,
|
---|
490 | pubKey.getE(), pubKey.getN());
|
---|
491 | pks.toFile(fileName + ".pub");
|
---|
492 | return pks.toString();
|
---|
493 | }
|
---|
494 |
|
---|
495 | public static KeyPair generateRSAKeyPair(int bits, SecureRandom secRand) {
|
---|
496 | KeyPair kp;
|
---|
497 | RSACipher cipher;
|
---|
498 | BigInteger p;
|
---|
499 | BigInteger q;
|
---|
500 | BigInteger t;
|
---|
501 | BigInteger p_1;
|
---|
502 | BigInteger q_1;
|
---|
503 | BigInteger phi;
|
---|
504 | BigInteger G;
|
---|
505 | BigInteger F;
|
---|
506 | BigInteger e;
|
---|
507 | BigInteger d;
|
---|
508 | BigInteger u;
|
---|
509 | BigInteger n;
|
---|
510 | BigInteger one = new BigInteger("1");
|
---|
511 |
|
---|
512 | for(;;) {
|
---|
513 | int l = secRand.secureLevel;
|
---|
514 | secRand.secureLevel = 2;
|
---|
515 | p = new BigInteger(bits / 2, 64, secRand);
|
---|
516 | q = new BigInteger(bits - (bits / 2), 64, secRand);
|
---|
517 | secRand.secureLevel = l;
|
---|
518 |
|
---|
519 | if(p.compareTo(q) == 0) {
|
---|
520 | continue;
|
---|
521 | } else if(q.compareTo(p) < 0) {
|
---|
522 | t = q;
|
---|
523 | q = p;
|
---|
524 | p = t;
|
---|
525 | }
|
---|
526 |
|
---|
527 | t = p.gcd(q);
|
---|
528 | if(t.compareTo(one) != 0) {
|
---|
529 | continue;
|
---|
530 | }
|
---|
531 |
|
---|
532 | p_1 = p.subtract(one);
|
---|
533 | q_1 = q.subtract(one);
|
---|
534 | phi = p_1.multiply(q_1);
|
---|
535 | G = p_1.gcd(q_1);
|
---|
536 | F = phi.divide(G);
|
---|
537 |
|
---|
538 | e = one.shiftLeft(5);
|
---|
539 | e = e.subtract(one);
|
---|
540 | do {
|
---|
541 | e = e.add(one.add(one));
|
---|
542 | t = e.gcd(phi);
|
---|
543 | } while(t.compareTo(one) != 0);
|
---|
544 |
|
---|
545 | // !!! d = e.modInverse(F);
|
---|
546 | d = e.modInverse(phi);
|
---|
547 | n = p.multiply(q);
|
---|
548 | u = p.modInverse(q);
|
---|
549 |
|
---|
550 | kp = new KeyPair(new RSAPublicKey(e, n),
|
---|
551 | new RSAPrivateKey(e, n, d, u, p, q));
|
---|
552 |
|
---|
553 | // !!!
|
---|
554 | break;
|
---|
555 | }
|
---|
556 |
|
---|
557 | return kp;
|
---|
558 | }
|
---|
559 |
|
---|
560 | /* !!! USED FOR DEBUG !!!
|
---|
561 | void printSrvKeys() {
|
---|
562 | BigInteger big;
|
---|
563 | byte[] theId = new byte[sessionId.length + 1];
|
---|
564 | theId[0] = 0;
|
---|
565 | System.arraycopy(sessionId, 0, theId, 1, sessionId.length);
|
---|
566 | big = new BigInteger(theId);
|
---|
567 | System.out.println("sessionId: " + big.toString(16));
|
---|
568 | byte[] theKey = new byte[sessionKey.length + 1];
|
---|
569 | theKey[0] = 0;
|
---|
570 | System.arraycopy(sessionKey, 0, theKey, 1, sessionKey.length);
|
---|
571 | big = new BigInteger(theKey);
|
---|
572 | System.out.println("sessionkey: " + big.toString(16));
|
---|
573 |
|
---|
574 | System.out.println("srvkey n: " + ((RSAPublicKey)srvServerKey.getPublic()).getN().toString(16));
|
---|
575 | System.out.println("srvkey e: " + ((RSAPublicKey)srvServerKey.getPublic()).getE().toString(16));
|
---|
576 | System.out.println("srvkey bits: " + ((RSAPublicKey)srvServerKey.getPublic()).bitLength());
|
---|
577 | System.out.println("hstkey n: " + ((RSAPublicKey)srvHostKey.getPublic()).getN().toString(16));
|
---|
578 | System.out.println("hstkey e: " + ((RSAPublicKey)srvHostKey.getPublic()).getE().toString(16));
|
---|
579 | System.out.println("hstkey bits: " + ((RSAPublicKey)srvHostKey.getPublic()).bitLength());
|
---|
580 | }
|
---|
581 | */
|
---|
582 |
|
---|
583 | }
|
---|
584 |
|
---|