]>
Commit | Line | Data |
---|---|---|
1 | /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ | |
2 | /* | |
3 | Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved. | |
4 | ||
5 | Redistribution and use in source and binary forms, with or without | |
6 | modification, are permitted provided that the following conditions are met: | |
7 | ||
8 | 1. Redistributions of source code must retain the above copyright notice, | |
9 | this list of conditions and the following disclaimer. | |
10 | ||
11 | 2. Redistributions in binary form must reproduce the above copyright | |
12 | notice, this list of conditions and the following disclaimer in | |
13 | the documentation and/or other materials provided with the distribution. | |
14 | ||
15 | 3. The names of the authors may not be used to endorse or promote products | |
16 | derived from this software without specific prior written permission. | |
17 | ||
18 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, | |
19 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
20 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, | |
21 | INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
24 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
27 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | */ | |
29 | ||
30 | package com.jcraft.jsch; | |
31 | ||
32 | import java.io.*; | |
33 | ||
34 | class IdentityFile implements Identity{ | |
35 | String identity; | |
36 | byte[] key; | |
37 | byte[] iv; | |
38 | private JSch jsch; | |
39 | private HASH hash; | |
40 | private byte[] encoded_data; | |
41 | ||
42 | private Cipher cipher; | |
43 | ||
44 | // DSA | |
45 | private byte[] P_array; | |
46 | private byte[] Q_array; | |
47 | private byte[] G_array; | |
48 | private byte[] pub_array; | |
49 | private byte[] prv_array; | |
50 | ||
51 | // RSA | |
52 | private byte[] n_array; // modulus | |
53 | private byte[] e_array; // public exponent | |
54 | private byte[] d_array; // private exponent | |
55 | ||
56 | // private String algname="ssh-dss"; | |
57 | private String algname="ssh-rsa"; | |
58 | ||
59 | private static final int ERROR=0; | |
60 | private static final int RSA=1; | |
61 | private static final int DSS=2; | |
62 | private static final int UNKNOWN=3; | |
63 | ||
64 | private static final int OPENSSH=0; | |
65 | private static final int FSECURE=1; | |
66 | private static final int PUTTY=2; | |
67 | ||
68 | private int type=ERROR; | |
69 | private int keytype=OPENSSH; | |
70 | ||
71 | private byte[] publickeyblob=null; | |
72 | ||
73 | private boolean encrypted=true; | |
74 | ||
75 | static IdentityFile newInstance(String prvfile, String pubfile, JSch jsch) throws JSchException{ | |
76 | byte[] prvkey=null; | |
77 | byte[] pubkey=null; | |
78 | ||
79 | File file=null; | |
80 | FileInputStream fis=null; | |
81 | try{ | |
82 | file=new File(prvfile); | |
83 | fis=new FileInputStream(prvfile); | |
84 | prvkey=new byte[(int)(file.length())]; | |
85 | int len=0; | |
86 | while(true){ | |
87 | int i=fis.read(prvkey, len, prvkey.length-len); | |
88 | if(i<=0) | |
89 | break; | |
90 | len+=i; | |
91 | } | |
92 | fis.close(); | |
93 | } | |
94 | catch(Exception e){ | |
95 | try{ if(fis!=null) fis.close();} | |
96 | catch(Exception ee){} | |
97 | if(e instanceof Throwable) | |
98 | throw new JSchException(e.toString(), (Throwable)e); | |
99 | throw new JSchException(e.toString()); | |
100 | } | |
101 | ||
102 | String _pubfile=pubfile; | |
103 | if(pubfile==null){ | |
104 | _pubfile=prvfile+".pub"; | |
105 | } | |
106 | ||
107 | try{ | |
108 | file=new File(_pubfile); | |
109 | fis = new FileInputStream(_pubfile); | |
110 | pubkey=new byte[(int)(file.length())]; | |
111 | int len=0; | |
112 | while(true){ | |
113 | int i=fis.read(pubkey, len, pubkey.length-len); | |
114 | if(i<=0) | |
115 | break; | |
116 | len+=i; | |
117 | } | |
118 | fis.close(); | |
119 | } | |
120 | catch(Exception e){ | |
121 | try{ if(fis!=null) fis.close();} | |
122 | catch(Exception ee){} | |
123 | if(pubfile!=null){ | |
124 | // The pubfile is explicitry given, but not accessible. | |
125 | if(e instanceof Throwable) | |
126 | throw new JSchException(e.toString(), (Throwable)e); | |
127 | throw new JSchException(e.toString()); | |
128 | } | |
129 | } | |
130 | return newInstance(prvfile, prvkey, pubkey, jsch); | |
131 | } | |
132 | ||
133 | static IdentityFile newInstance(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{ | |
134 | try{ | |
135 | return new IdentityFile(name, prvkey, pubkey, jsch); | |
136 | } | |
137 | finally{ | |
138 | Util.bzero(prvkey); | |
139 | } | |
140 | } | |
141 | ||
142 | private IdentityFile(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{ | |
143 | this.identity=name; | |
144 | this.jsch=jsch; | |
145 | try{ | |
146 | Class c; | |
147 | c=Class.forName((String)jsch.getConfig("3des-cbc")); | |
148 | cipher=(Cipher)(c.newInstance()); | |
149 | key=new byte[cipher.getBlockSize()]; // 24 | |
150 | iv=new byte[cipher.getIVSize()]; // 8 | |
151 | c=Class.forName((String)jsch.getConfig("md5")); | |
152 | hash=(HASH)(c.newInstance()); | |
153 | hash.init(); | |
154 | ||
155 | byte[] buf=prvkey; | |
156 | int len=buf.length; | |
157 | ||
158 | int i=0; | |
159 | ||
160 | while(i<len){ | |
161 | if(buf[i] == '-' && i+4<len && | |
162 | buf[i+1] == '-' && buf[i+2] == '-' && | |
163 | buf[i+3] == '-' && buf[i+4] == '-'){ | |
164 | break; | |
165 | } | |
166 | i++; | |
167 | } | |
168 | ||
169 | while(i<len){ | |
170 | if(buf[i]=='B'&& i+3<len && buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I'){ | |
171 | i+=6; | |
172 | if(buf[i]=='D'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=DSS; } | |
173 | else if(buf[i]=='R'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=RSA; } | |
174 | else if(buf[i]=='S'&& buf[i+1]=='S'&& buf[i+2]=='H'){ // FSecure | |
175 | type=UNKNOWN; | |
176 | keytype=FSECURE; | |
177 | } | |
178 | else{ | |
179 | //System.err.println("invalid format: "+identity); | |
180 | throw new JSchException("invalid privatekey: "+identity); | |
181 | } | |
182 | i+=3; | |
183 | continue; | |
184 | } | |
185 | if(buf[i]=='A'&& i+7<len && buf[i+1]=='E'&& buf[i+2]=='S'&& buf[i+3]=='-' && | |
186 | buf[i+4]=='2'&& buf[i+5]=='5'&& buf[i+6]=='6'&& buf[i+7]=='-'){ | |
187 | i+=8; | |
188 | if(Session.checkCipher((String)jsch.getConfig("aes256-cbc"))){ | |
189 | c=Class.forName((String)jsch.getConfig("aes256-cbc")); | |
190 | cipher=(Cipher)(c.newInstance()); | |
191 | key=new byte[cipher.getBlockSize()]; | |
192 | iv=new byte[cipher.getIVSize()]; | |
193 | } | |
194 | else{ | |
195 | throw new JSchException("privatekey: aes256-cbc is not available "+identity); | |
196 | } | |
197 | continue; | |
198 | } | |
199 | if(buf[i]=='C'&& i+3<len && buf[i+1]=='B'&& buf[i+2]=='C'&& buf[i+3]==','){ | |
200 | i+=4; | |
201 | for(int ii=0; ii<iv.length; ii++){ | |
202 | iv[ii]=(byte)(((a2b(buf[i++])<<4)&0xf0)+ | |
203 | (a2b(buf[i++])&0xf)); | |
204 | } | |
205 | continue; | |
206 | } | |
207 | if(buf[i]==0x0d && i+1<len && buf[i+1]==0x0a){ | |
208 | i++; | |
209 | continue; | |
210 | } | |
211 | if(buf[i]==0x0a && i+1<len){ | |
212 | if(buf[i+1]==0x0a){ i+=2; break; } | |
213 | if(buf[i+1]==0x0d && | |
214 | i+2<len && buf[i+2]==0x0a){ | |
215 | i+=3; break; | |
216 | } | |
217 | boolean inheader=false; | |
218 | for(int j=i+1; j<len; j++){ | |
219 | if(buf[j]==0x0a) break; | |
220 | //if(buf[j]==0x0d) break; | |
221 | if(buf[j]==':'){inheader=true; break;} | |
222 | } | |
223 | if(!inheader){ | |
224 | i++; | |
225 | encrypted=false; // no passphrase | |
226 | break; | |
227 | } | |
228 | } | |
229 | i++; | |
230 | } | |
231 | ||
232 | if(type==ERROR){ | |
233 | throw new JSchException("invalid privatekey: "+identity); | |
234 | } | |
235 | ||
236 | int start=i; | |
237 | while(i<len){ | |
238 | if(buf[i]==0x0a){ | |
239 | boolean xd=(buf[i-1]==0x0d); | |
240 | System.arraycopy(buf, i+1, | |
241 | buf, | |
242 | i-(xd ? 1 : 0), | |
243 | len-i-1-(xd ? 1 : 0) | |
244 | ); | |
245 | if(xd)len--; | |
246 | len--; | |
247 | continue; | |
248 | } | |
249 | if(buf[i]=='-'){ break; } | |
250 | i++; | |
251 | } | |
252 | encoded_data=Util.fromBase64(buf, start, i-start); | |
253 | ||
254 | if(encoded_data.length>4 && // FSecure | |
255 | encoded_data[0]==(byte)0x3f && | |
256 | encoded_data[1]==(byte)0x6f && | |
257 | encoded_data[2]==(byte)0xf9 && | |
258 | encoded_data[3]==(byte)0xeb){ | |
259 | ||
260 | Buffer _buf=new Buffer(encoded_data); | |
261 | _buf.getInt(); // 0x3f6ff9be | |
262 | _buf.getInt(); | |
263 | byte[]_type=_buf.getString(); | |
264 | //System.err.println("type: "+new String(_type)); | |
265 | byte[] _cipher=_buf.getString(); | |
266 | String cipher=Util.byte2str(_cipher); | |
267 | //System.err.println("cipher: "+cipher); | |
268 | if(cipher.equals("3des-cbc")){ | |
269 | _buf.getInt(); | |
270 | byte[] foo=new byte[encoded_data.length-_buf.getOffSet()]; | |
271 | _buf.getByte(foo); | |
272 | encoded_data=foo; | |
273 | encrypted=true; | |
274 | throw new JSchException("unknown privatekey format: "+identity); | |
275 | } | |
276 | else if(cipher.equals("none")){ | |
277 | _buf.getInt(); | |
278 | //_buf.getInt(); | |
279 | ||
280 | encrypted=false; | |
281 | ||
282 | byte[] foo=new byte[encoded_data.length-_buf.getOffSet()]; | |
283 | _buf.getByte(foo); | |
284 | encoded_data=foo; | |
285 | } | |
286 | ||
287 | } | |
288 | ||
289 | if(pubkey==null){ | |
290 | return; | |
291 | } | |
292 | ||
293 | buf=pubkey; | |
294 | len=buf.length; | |
295 | ||
296 | if(buf.length>4 && // FSecure's public key | |
297 | buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){ | |
298 | i=0; | |
299 | do{i++;}while(len>i && buf[i]!=0x0a); | |
300 | if(len<=i) return; | |
301 | while(i<len){ | |
302 | if(buf[i]==0x0a){ | |
303 | boolean inheader=false; | |
304 | for(int j=i+1; j<len; j++){ | |
305 | if(buf[j]==0x0a) break; | |
306 | if(buf[j]==':'){inheader=true; break;} | |
307 | } | |
308 | if(!inheader){ | |
309 | i++; | |
310 | break; | |
311 | } | |
312 | } | |
313 | i++; | |
314 | } | |
315 | if(len<=i) return; | |
316 | ||
317 | start=i; | |
318 | while(i<len){ | |
319 | if(buf[i]==0x0a){ | |
320 | System.arraycopy(buf, i+1, buf, i, len-i-1); | |
321 | len--; | |
322 | continue; | |
323 | } | |
324 | if(buf[i]=='-'){ break; } | |
325 | i++; | |
326 | } | |
327 | publickeyblob=Util.fromBase64(buf, start, i-start); | |
328 | ||
329 | if(type==UNKNOWN && publickeyblob.length>8){ | |
330 | if(publickeyblob[8]=='d'){ | |
331 | type=DSS; | |
332 | } | |
333 | else if(publickeyblob[8]=='r'){ | |
334 | type=RSA; | |
335 | } | |
336 | } | |
337 | } | |
338 | else{ | |
339 | if(buf[0]!='s'|| buf[1]!='s'|| buf[2]!='h'|| buf[3]!='-') return; | |
340 | i=0; | |
341 | while(i<len){ if(buf[i]==' ')break; i++;} i++; | |
342 | if(i>=len) return; | |
343 | start=i; | |
344 | while(i<len){ if(buf[i]==' ' || buf[i]=='\n')break; i++;} | |
345 | publickeyblob=Util.fromBase64(buf, start, i-start); | |
346 | if(publickeyblob.length<4+7){ // It must start with "ssh-XXX". | |
347 | if(JSch.getLogger().isEnabled(Logger.WARN)){ | |
348 | JSch.getLogger().log(Logger.WARN, | |
349 | "failed to parse the public key"); | |
350 | } | |
351 | publickeyblob=null; | |
352 | } | |
353 | } | |
354 | } | |
355 | catch(Exception e){ | |
356 | //System.err.println("IdentityFile: "+e); | |
357 | if(e instanceof JSchException) throw (JSchException)e; | |
358 | if(e instanceof Throwable) | |
359 | throw new JSchException(e.toString(), (Throwable)e); | |
360 | throw new JSchException(e.toString()); | |
361 | } | |
362 | } | |
363 | ||
364 | public String getAlgName(){ | |
365 | if(type==RSA) return "ssh-rsa"; | |
366 | return "ssh-dss"; | |
367 | } | |
368 | ||
369 | public boolean setPassphrase(byte[] _passphrase) throws JSchException{ | |
370 | /* | |
371 | hash is MD5 | |
372 | h(0) <- hash(passphrase, iv); | |
373 | h(n) <- hash(h(n-1), passphrase, iv); | |
374 | key <- (h(0),...,h(n))[0,..,key.length]; | |
375 | */ | |
376 | try{ | |
377 | if(encrypted){ | |
378 | if(_passphrase==null) return false; | |
379 | byte[] passphrase=_passphrase; | |
380 | int hsize=hash.getBlockSize(); | |
381 | byte[] hn=new byte[key.length/hsize*hsize+ | |
382 | (key.length%hsize==0?0:hsize)]; | |
383 | byte[] tmp=null; | |
384 | if(keytype==OPENSSH){ | |
385 | for(int index=0; index+hsize<=hn.length;){ | |
386 | if(tmp!=null){ hash.update(tmp, 0, tmp.length); } | |
387 | hash.update(passphrase, 0, passphrase.length); | |
388 | hash.update(iv, 0, iv.length > 8 ? 8: iv.length); | |
389 | tmp=hash.digest(); | |
390 | System.arraycopy(tmp, 0, hn, index, tmp.length); | |
391 | index+=tmp.length; | |
392 | } | |
393 | System.arraycopy(hn, 0, key, 0, key.length); | |
394 | } | |
395 | else if(keytype==FSECURE){ | |
396 | for(int index=0; index+hsize<=hn.length;){ | |
397 | if(tmp!=null){ hash.update(tmp, 0, tmp.length); } | |
398 | hash.update(passphrase, 0, passphrase.length); | |
399 | tmp=hash.digest(); | |
400 | System.arraycopy(tmp, 0, hn, index, tmp.length); | |
401 | index+=tmp.length; | |
402 | } | |
403 | System.arraycopy(hn, 0, key, 0, key.length); | |
404 | } | |
405 | Util.bzero(passphrase); | |
406 | } | |
407 | if(decrypt()){ | |
408 | encrypted=false; | |
409 | return true; | |
410 | } | |
411 | P_array=Q_array=G_array=pub_array=prv_array=null; | |
412 | return false; | |
413 | } | |
414 | catch(Exception e){ | |
415 | if(e instanceof JSchException) throw (JSchException)e; | |
416 | if(e instanceof Throwable) | |
417 | throw new JSchException(e.toString(), (Throwable)e); | |
418 | throw new JSchException(e.toString()); | |
419 | } | |
420 | } | |
421 | ||
422 | public byte[] getPublicKeyBlob(){ | |
423 | if(publickeyblob!=null) return publickeyblob; | |
424 | if(type==RSA) return getPublicKeyBlob_rsa(); | |
425 | return getPublicKeyBlob_dss(); | |
426 | } | |
427 | ||
428 | byte[] getPublicKeyBlob_rsa(){ | |
429 | if(e_array==null) return null; | |
430 | Buffer buf=new Buffer("ssh-rsa".length()+4+ | |
431 | e_array.length+4+ | |
432 | n_array.length+4); | |
433 | buf.putString(Util.str2byte("ssh-rsa")); | |
434 | buf.putString(e_array); | |
435 | buf.putString(n_array); | |
436 | return buf.buffer; | |
437 | } | |
438 | ||
439 | byte[] getPublicKeyBlob_dss(){ | |
440 | if(P_array==null) return null; | |
441 | Buffer buf=new Buffer("ssh-dss".length()+4+ | |
442 | P_array.length+4+ | |
443 | Q_array.length+4+ | |
444 | G_array.length+4+ | |
445 | pub_array.length+4); | |
446 | buf.putString(Util.str2byte("ssh-dss")); | |
447 | buf.putString(P_array); | |
448 | buf.putString(Q_array); | |
449 | buf.putString(G_array); | |
450 | buf.putString(pub_array); | |
451 | return buf.buffer; | |
452 | } | |
453 | ||
454 | public byte[] getSignature(byte[] data){ | |
455 | if(type==RSA) return getSignature_rsa(data); | |
456 | return getSignature_dss(data); | |
457 | } | |
458 | ||
459 | byte[] getSignature_rsa(byte[] data){ | |
460 | try{ | |
461 | Class c=Class.forName((String)jsch.getConfig("signature.rsa")); | |
462 | SignatureRSA rsa=(SignatureRSA)(c.newInstance()); | |
463 | ||
464 | rsa.init(); | |
465 | rsa.setPrvKey(d_array, n_array); | |
466 | ||
467 | rsa.update(data); | |
468 | byte[] sig = rsa.sign(); | |
469 | Buffer buf=new Buffer("ssh-rsa".length()+4+ | |
470 | sig.length+4); | |
471 | buf.putString(Util.str2byte("ssh-rsa")); | |
472 | buf.putString(sig); | |
473 | return buf.buffer; | |
474 | } | |
475 | catch(Exception e){ | |
476 | } | |
477 | return null; | |
478 | } | |
479 | ||
480 | byte[] getSignature_dss(byte[] data){ | |
481 | /* | |
482 | byte[] foo; | |
483 | int i; | |
484 | System.err.print("P "); | |
485 | foo=P_array; | |
486 | for(i=0; i<foo.length; i++){ | |
487 | System.err.print(Integer.toHexString(foo[i]&0xff)+":"); | |
488 | } | |
489 | System.err.println(""); | |
490 | System.err.print("Q "); | |
491 | foo=Q_array; | |
492 | for(i=0; i<foo.length; i++){ | |
493 | System.err.print(Integer.toHexString(foo[i]&0xff)+":"); | |
494 | } | |
495 | System.err.println(""); | |
496 | System.err.print("G "); | |
497 | foo=G_array; | |
498 | for(i=0; i<foo.length; i++){ | |
499 | System.err.print(Integer.toHexString(foo[i]&0xff)+":"); | |
500 | } | |
501 | System.err.println(""); | |
502 | */ | |
503 | ||
504 | try{ | |
505 | Class c=Class.forName((String)jsch.getConfig("signature.dss")); | |
506 | SignatureDSA dsa=(SignatureDSA)(c.newInstance()); | |
507 | dsa.init(); | |
508 | dsa.setPrvKey(prv_array, P_array, Q_array, G_array); | |
509 | ||
510 | dsa.update(data); | |
511 | byte[] sig = dsa.sign(); | |
512 | Buffer buf=new Buffer("ssh-dss".length()+4+ | |
513 | sig.length+4); | |
514 | buf.putString(Util.str2byte("ssh-dss")); | |
515 | buf.putString(sig); | |
516 | return buf.buffer; | |
517 | } | |
518 | catch(Exception e){ | |
519 | //System.err.println("e "+e); | |
520 | } | |
521 | return null; | |
522 | } | |
523 | ||
524 | public boolean decrypt(){ | |
525 | if(type==RSA) return decrypt_rsa(); | |
526 | return decrypt_dss(); | |
527 | } | |
528 | ||
529 | boolean decrypt_rsa(){ | |
530 | byte[] p_array; | |
531 | byte[] q_array; | |
532 | byte[] dmp1_array; | |
533 | byte[] dmq1_array; | |
534 | byte[] iqmp_array; | |
535 | ||
536 | try{ | |
537 | byte[] plain; | |
538 | if(encrypted){ | |
539 | if(keytype==OPENSSH){ | |
540 | cipher.init(Cipher.DECRYPT_MODE, key, iv); | |
541 | plain=new byte[encoded_data.length]; | |
542 | cipher.update(encoded_data, 0, encoded_data.length, plain, 0); | |
543 | } | |
544 | else if(keytype==FSECURE){ | |
545 | for(int i=0; i<iv.length; i++)iv[i]=0; | |
546 | cipher.init(Cipher.DECRYPT_MODE, key, iv); | |
547 | plain=new byte[encoded_data.length]; | |
548 | cipher.update(encoded_data, 0, encoded_data.length, plain, 0); | |
549 | } | |
550 | else{ | |
551 | return false; | |
552 | } | |
553 | } | |
554 | else{ | |
555 | if(n_array!=null) return true; | |
556 | plain=encoded_data; | |
557 | } | |
558 | ||
559 | if(keytype==FSECURE){ // FSecure | |
560 | Buffer buf=new Buffer(plain); | |
561 | int foo=buf.getInt(); | |
562 | if(plain.length!=foo+4){ | |
563 | return false; | |
564 | } | |
565 | e_array=buf.getMPIntBits(); | |
566 | d_array=buf.getMPIntBits(); | |
567 | n_array=buf.getMPIntBits(); | |
568 | byte[] u_array=buf.getMPIntBits(); | |
569 | p_array=buf.getMPIntBits(); | |
570 | q_array=buf.getMPIntBits(); | |
571 | return true; | |
572 | } | |
573 | ||
574 | int index=0; | |
575 | int length=0; | |
576 | ||
577 | if(plain[index]!=0x30)return false; | |
578 | index++; // SEQUENCE | |
579 | length=plain[index++]&0xff; | |
580 | if((length&0x80)!=0){ | |
581 | int foo=length&0x7f; length=0; | |
582 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
583 | } | |
584 | ||
585 | if(plain[index]!=0x02)return false; | |
586 | index++; // INTEGER | |
587 | length=plain[index++]&0xff; | |
588 | if((length&0x80)!=0){ | |
589 | int foo=length&0x7f; length=0; | |
590 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
591 | } | |
592 | index+=length; | |
593 | ||
594 | //System.err.println("int: len="+length); | |
595 | //System.err.print(Integer.toHexString(plain[index-1]&0xff)+":"); | |
596 | //System.err.println(""); | |
597 | ||
598 | index++; | |
599 | length=plain[index++]&0xff; | |
600 | if((length&0x80)!=0){ | |
601 | int foo=length&0x7f; length=0; | |
602 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
603 | } | |
604 | n_array=new byte[length]; | |
605 | System.arraycopy(plain, index, n_array, 0, length); | |
606 | index+=length; | |
607 | /* | |
608 | System.err.println("int: N len="+length); | |
609 | for(int i=0; i<n_array.length; i++){ | |
610 | System.err.print(Integer.toHexString(n_array[i]&0xff)+":"); | |
611 | } | |
612 | System.err.println(""); | |
613 | */ | |
614 | index++; | |
615 | length=plain[index++]&0xff; | |
616 | if((length&0x80)!=0){ | |
617 | int foo=length&0x7f; length=0; | |
618 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
619 | } | |
620 | e_array=new byte[length]; | |
621 | System.arraycopy(plain, index, e_array, 0, length); | |
622 | index+=length; | |
623 | /* | |
624 | System.err.println("int: E len="+length); | |
625 | for(int i=0; i<e_array.length; i++){ | |
626 | System.err.print(Integer.toHexString(e_array[i]&0xff)+":"); | |
627 | } | |
628 | System.err.println(""); | |
629 | */ | |
630 | index++; | |
631 | length=plain[index++]&0xff; | |
632 | if((length&0x80)!=0){ | |
633 | int foo=length&0x7f; length=0; | |
634 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
635 | } | |
636 | d_array=new byte[length]; | |
637 | System.arraycopy(plain, index, d_array, 0, length); | |
638 | index+=length; | |
639 | /* | |
640 | System.err.println("int: D len="+length); | |
641 | for(int i=0; i<d_array.length; i++){ | |
642 | System.err.print(Integer.toHexString(d_array[i]&0xff)+":"); | |
643 | } | |
644 | System.err.println(""); | |
645 | */ | |
646 | ||
647 | index++; | |
648 | length=plain[index++]&0xff; | |
649 | if((length&0x80)!=0){ | |
650 | int foo=length&0x7f; length=0; | |
651 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
652 | } | |
653 | p_array=new byte[length]; | |
654 | System.arraycopy(plain, index, p_array, 0, length); | |
655 | index+=length; | |
656 | /* | |
657 | System.err.println("int: P len="+length); | |
658 | for(int i=0; i<p_array.length; i++){ | |
659 | System.err.print(Integer.toHexString(p_array[i]&0xff)+":"); | |
660 | } | |
661 | System.err.println(""); | |
662 | */ | |
663 | index++; | |
664 | length=plain[index++]&0xff; | |
665 | if((length&0x80)!=0){ | |
666 | int foo=length&0x7f; length=0; | |
667 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
668 | } | |
669 | q_array=new byte[length]; | |
670 | System.arraycopy(plain, index, q_array, 0, length); | |
671 | index+=length; | |
672 | /* | |
673 | System.err.println("int: q len="+length); | |
674 | for(int i=0; i<q_array.length; i++){ | |
675 | System.err.print(Integer.toHexString(q_array[i]&0xff)+":"); | |
676 | } | |
677 | System.err.println(""); | |
678 | */ | |
679 | index++; | |
680 | length=plain[index++]&0xff; | |
681 | if((length&0x80)!=0){ | |
682 | int foo=length&0x7f; length=0; | |
683 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
684 | } | |
685 | dmp1_array=new byte[length]; | |
686 | System.arraycopy(plain, index, dmp1_array, 0, length); | |
687 | index+=length; | |
688 | /* | |
689 | System.err.println("int: dmp1 len="+length); | |
690 | for(int i=0; i<dmp1_array.length; i++){ | |
691 | System.err.print(Integer.toHexString(dmp1_array[i]&0xff)+":"); | |
692 | } | |
693 | System.err.println(""); | |
694 | */ | |
695 | index++; | |
696 | length=plain[index++]&0xff; | |
697 | if((length&0x80)!=0){ | |
698 | int foo=length&0x7f; length=0; | |
699 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
700 | } | |
701 | dmq1_array=new byte[length]; | |
702 | System.arraycopy(plain, index, dmq1_array, 0, length); | |
703 | index+=length; | |
704 | /* | |
705 | System.err.println("int: dmq1 len="+length); | |
706 | for(int i=0; i<dmq1_array.length; i++){ | |
707 | System.err.print(Integer.toHexString(dmq1_array[i]&0xff)+":"); | |
708 | } | |
709 | System.err.println(""); | |
710 | */ | |
711 | index++; | |
712 | length=plain[index++]&0xff; | |
713 | if((length&0x80)!=0){ | |
714 | int foo=length&0x7f; length=0; | |
715 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
716 | } | |
717 | iqmp_array=new byte[length]; | |
718 | System.arraycopy(plain, index, iqmp_array, 0, length); | |
719 | index+=length; | |
720 | /* | |
721 | System.err.println("int: iqmp len="+length); | |
722 | for(int i=0; i<iqmp_array.length; i++){ | |
723 | System.err.print(Integer.toHexString(iqmp_array[i]&0xff)+":"); | |
724 | } | |
725 | System.err.println(""); | |
726 | */ | |
727 | } | |
728 | catch(Exception e){ | |
729 | //System.err.println(e); | |
730 | return false; | |
731 | } | |
732 | return true; | |
733 | } | |
734 | ||
735 | boolean decrypt_dss(){ | |
736 | try{ | |
737 | byte[] plain; | |
738 | if(encrypted){ | |
739 | if(keytype==OPENSSH){ | |
740 | cipher.init(Cipher.DECRYPT_MODE, key, iv); | |
741 | plain=new byte[encoded_data.length]; | |
742 | cipher.update(encoded_data, 0, encoded_data.length, plain, 0); | |
743 | /* | |
744 | for(int i=0; i<plain.length; i++){ | |
745 | System.err.print(Integer.toHexString(plain[i]&0xff)+":"); | |
746 | } | |
747 | System.err.println(""); | |
748 | */ | |
749 | } | |
750 | else if(keytype==FSECURE){ | |
751 | for(int i=0; i<iv.length; i++)iv[i]=0; | |
752 | cipher.init(Cipher.DECRYPT_MODE, key, iv); | |
753 | plain=new byte[encoded_data.length]; | |
754 | cipher.update(encoded_data, 0, encoded_data.length, plain, 0); | |
755 | } | |
756 | else{ | |
757 | return false; | |
758 | } | |
759 | } | |
760 | else{ | |
761 | if(P_array!=null) return true; | |
762 | plain=encoded_data; | |
763 | } | |
764 | ||
765 | if(keytype==FSECURE){ // FSecure | |
766 | Buffer buf=new Buffer(plain); | |
767 | int foo=buf.getInt(); | |
768 | if(plain.length!=foo+4){ | |
769 | return false; | |
770 | } | |
771 | P_array=buf.getMPIntBits(); | |
772 | G_array=buf.getMPIntBits(); | |
773 | Q_array=buf.getMPIntBits(); | |
774 | pub_array=buf.getMPIntBits(); | |
775 | prv_array=buf.getMPIntBits(); | |
776 | return true; | |
777 | } | |
778 | ||
779 | int index=0; | |
780 | int length=0; | |
781 | if(plain[index]!=0x30)return false; | |
782 | index++; // SEQUENCE | |
783 | length=plain[index++]&0xff; | |
784 | if((length&0x80)!=0){ | |
785 | int foo=length&0x7f; length=0; | |
786 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
787 | } | |
788 | if(plain[index]!=0x02)return false; | |
789 | index++; // INTEGER | |
790 | length=plain[index++]&0xff; | |
791 | if((length&0x80)!=0){ | |
792 | int foo=length&0x7f; length=0; | |
793 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
794 | } | |
795 | index+=length; | |
796 | ||
797 | index++; | |
798 | length=plain[index++]&0xff; | |
799 | if((length&0x80)!=0){ | |
800 | int foo=length&0x7f; length=0; | |
801 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
802 | } | |
803 | P_array=new byte[length]; | |
804 | System.arraycopy(plain, index, P_array, 0, length); | |
805 | index+=length; | |
806 | ||
807 | index++; | |
808 | length=plain[index++]&0xff; | |
809 | if((length&0x80)!=0){ | |
810 | int foo=length&0x7f; length=0; | |
811 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
812 | } | |
813 | Q_array=new byte[length]; | |
814 | System.arraycopy(plain, index, Q_array, 0, length); | |
815 | index+=length; | |
816 | ||
817 | index++; | |
818 | length=plain[index++]&0xff; | |
819 | if((length&0x80)!=0){ | |
820 | int foo=length&0x7f; length=0; | |
821 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
822 | } | |
823 | G_array=new byte[length]; | |
824 | System.arraycopy(plain, index, G_array, 0, length); | |
825 | index+=length; | |
826 | ||
827 | index++; | |
828 | length=plain[index++]&0xff; | |
829 | if((length&0x80)!=0){ | |
830 | int foo=length&0x7f; length=0; | |
831 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
832 | } | |
833 | pub_array=new byte[length]; | |
834 | System.arraycopy(plain, index, pub_array, 0, length); | |
835 | index+=length; | |
836 | ||
837 | index++; | |
838 | length=plain[index++]&0xff; | |
839 | if((length&0x80)!=0){ | |
840 | int foo=length&0x7f; length=0; | |
841 | while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } | |
842 | } | |
843 | prv_array=new byte[length]; | |
844 | System.arraycopy(plain, index, prv_array, 0, length); | |
845 | index+=length; | |
846 | } | |
847 | catch(Exception e){ | |
848 | //System.err.println(e); | |
849 | //e.printStackTrace(); | |
850 | return false; | |
851 | } | |
852 | return true; | |
853 | } | |
854 | ||
855 | public boolean isEncrypted(){ | |
856 | return encrypted; | |
857 | } | |
858 | ||
859 | public String getName(){ | |
860 | return identity; | |
861 | } | |
862 | ||
863 | private byte a2b(byte c){ | |
864 | if('0'<=c&&c<='9') return (byte)(c-'0'); | |
865 | if('a'<=c&&c<='z') return (byte)(c-'a'+10); | |
866 | return (byte)(c-'A'+10); | |
867 | } | |
868 | ||
869 | public boolean equals(Object o){ | |
870 | if(!(o instanceof IdentityFile)) return super.equals(o); | |
871 | IdentityFile foo=(IdentityFile)o; | |
872 | return getName().equals(foo.getName()); | |
873 | } | |
874 | ||
875 | public void clear(){ | |
876 | Util.bzero(encoded_data); | |
877 | Util.bzero(prv_array); | |
878 | Util.bzero(d_array); | |
879 | Util.bzero(key); | |
880 | Util.bzero(iv); | |
881 | } | |
882 | ||
883 | public void finalize (){ | |
884 | clear(); | |
885 | } | |
886 | } |