1 2 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 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 private byte[] n_array; private byte[] e_array; private byte[] d_array; 56 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 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()]; iv=new byte[cipher.getIVSize()]; 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 while(i<len){ 160 if(buf[i]=='B'&& buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I'){ 161 i+=6; 162 if(buf[i]=='D'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=DSS; } 163 else if(buf[i]=='R'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=RSA; } 164 else if(buf[i]=='S'&& buf[i+1]=='S'&& buf[i+2]=='H'){ type=UNKNOWN; 166 keytype=FSECURE; 167 } 168 else{ 169 throw new JSchException("invalid privatekey: "+identity); 171 } 172 i+=3; 173 continue; 174 } 175 if(buf[i]=='C'&& buf[i+1]=='B'&& buf[i+2]=='C'&& buf[i+3]==','){ 176 i+=4; 177 for(int ii=0; ii<iv.length; ii++){ 178 iv[ii]=(byte)(((a2b(buf[i++])<<4)&0xf0)+ 179 (a2b(buf[i++])&0xf)); 180 } 181 continue; 182 } 183 if(buf[i]==0x0d && 184 i+1<buf.length && buf[i+1]==0x0a){ 185 i++; 186 continue; 187 } 188 if(buf[i]==0x0a && i+1<buf.length){ 189 if(buf[i+1]==0x0a){ i+=2; break; } 190 if(buf[i+1]==0x0d && 191 i+2<buf.length && buf[i+2]==0x0a){ 192 i+=3; break; 193 } 194 boolean inheader=false; 195 for(int j=i+1; j<buf.length; j++){ 196 if(buf[j]==0x0a) break; 197 if(buf[j]==':'){inheader=true; break;} 199 } 200 if(!inheader){ 201 i++; 202 encrypted=false; break; 204 } 205 } 206 i++; 207 } 208 209 if(type==ERROR){ 210 throw new JSchException("invalid privatekey: "+identity); 211 } 212 213 int start=i; 214 while(i<len){ 215 if(buf[i]==0x0a){ 216 boolean xd=(buf[i-1]==0x0d); 217 System.arraycopy(buf, i+1, 218 buf, 219 i-(xd ? 1 : 0), 220 len-i-1-(xd ? 1 : 0) 221 ); 222 if(xd)len--; 223 len--; 224 continue; 225 } 226 if(buf[i]=='-'){ break; } 227 i++; 228 } 229 encoded_data=Util.fromBase64(buf, start, i-start); 230 231 if(encoded_data.length>4 && encoded_data[0]==(byte)0x3f && 233 encoded_data[1]==(byte)0x6f && 234 encoded_data[2]==(byte)0xf9 && 235 encoded_data[3]==(byte)0xeb){ 236 237 Buffer _buf=new Buffer(encoded_data); 238 _buf.getInt(); _buf.getInt(); 240 byte[]_type=_buf.getString(); 241 byte[] _cipher=_buf.getString(); 243 String cipher=new String (_cipher); 244 if(cipher.equals("3des-cbc")){ 246 _buf.getInt(); 247 byte[] foo=new byte[encoded_data.length-_buf.getOffSet()]; 248 _buf.getByte(foo); 249 encoded_data=foo; 250 encrypted=true; 251 throw new JSchException("unknown privatekey format: "+identity); 252 } 253 else if(cipher.equals("none")){ 254 _buf.getInt(); 255 257 encrypted=false; 258 259 byte[] foo=new byte[encoded_data.length-_buf.getOffSet()]; 260 _buf.getByte(foo); 261 encoded_data=foo; 262 } 263 264 } 265 266 if(pubkey==null){ 267 return; 268 } 269 270 buf=pubkey; 271 len=buf.length; 272 273 if(buf.length>4 && buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){ 275 i=0; 276 do{i++;}while(len>i && buf[i]!=0x0a); 277 if(len<=i) return; 278 while(i<len){ 279 if(buf[i]==0x0a){ 280 boolean inheader=false; 281 for(int j=i+1; j<len; j++){ 282 if(buf[j]==0x0a) break; 283 if(buf[j]==':'){inheader=true; break;} 284 } 285 if(!inheader){ 286 i++; 287 break; 288 } 289 } 290 i++; 291 } 292 if(len<=i) return; 293 294 start=i; 295 while(i<len){ 296 if(buf[i]==0x0a){ 297 System.arraycopy(buf, i+1, buf, i, len-i-1); 298 len--; 299 continue; 300 } 301 if(buf[i]=='-'){ break; } 302 i++; 303 } 304 publickeyblob=Util.fromBase64(buf, start, i-start); 305 306 if(type==UNKNOWN){ 307 if(publickeyblob[8]=='d'){ 308 type=DSS; 309 } 310 else if(publickeyblob[8]=='r'){ 311 type=RSA; 312 } 313 } 314 } 315 else{ 316 if(buf[0]!='s'|| buf[1]!='s'|| buf[2]!='h'|| buf[3]!='-') return; 317 i=0; 318 while(i<len){ if(buf[i]==' ')break; i++;} i++; 319 if(i>=len) return; 320 start=i; 321 while(i<len){ if(buf[i]==' ' || buf[i]=='\n')break; i++;} 322 publickeyblob=Util.fromBase64(buf, start, i-start); 323 } 324 } 325 catch(Exception e){ 326 if(e instanceof JSchException) throw (JSchException)e; 328 if(e instanceof Throwable ) 329 throw new JSchException(e.toString(), (Throwable )e); 330 throw new JSchException(e.toString()); 331 } 332 } 333 334 public String getAlgName(){ 335 if(type==RSA) return "ssh-rsa"; 336 return "ssh-dss"; 337 } 338 339 public boolean setPassphrase(byte[] _passphrase) throws JSchException{ 340 346 try{ 347 if(encrypted){ 348 if(_passphrase==null) return false; 349 byte[] passphrase=_passphrase; 350 int hsize=hash.getBlockSize(); 351 byte[] hn=new byte[key.length/hsize*hsize+ 352 (key.length%hsize==0?0:hsize)]; 353 byte[] tmp=null; 354 if(keytype==OPENSSH){ 355 for(int index=0; index+hsize<=hn.length;){ 356 if(tmp!=null){ hash.update(tmp, 0, tmp.length); } 357 hash.update(passphrase, 0, passphrase.length); 358 hash.update(iv, 0, iv.length); 359 tmp=hash.digest(); 360 System.arraycopy(tmp, 0, hn, index, tmp.length); 361 index+=tmp.length; 362 } 363 System.arraycopy(hn, 0, key, 0, key.length); 364 } 365 else if(keytype==FSECURE){ 366 for(int index=0; index+hsize<=hn.length;){ 367 if(tmp!=null){ hash.update(tmp, 0, tmp.length); } 368 hash.update(passphrase, 0, passphrase.length); 369 tmp=hash.digest(); 370 System.arraycopy(tmp, 0, hn, index, tmp.length); 371 index+=tmp.length; 372 } 373 System.arraycopy(hn, 0, key, 0, key.length); 374 } 375 Util.bzero(passphrase); 376 } 377 if(decrypt()){ 378 encrypted=false; 379 return true; 380 } 381 P_array=Q_array=G_array=pub_array=prv_array=null; 382 return false; 383 } 384 catch(Exception e){ 385 if(e instanceof JSchException) throw (JSchException)e; 386 if(e instanceof Throwable ) 387 throw new JSchException(e.toString(), (Throwable )e); 388 throw new JSchException(e.toString()); 389 } 390 } 391 392 public byte[] getPublicKeyBlob(){ 393 if(publickeyblob!=null) return publickeyblob; 394 if(type==RSA) return getPublicKeyBlob_rsa(); 395 return getPublicKeyBlob_dss(); 396 } 397 398 byte[] getPublicKeyBlob_rsa(){ 399 if(e_array==null) return null; 400 Buffer buf=new Buffer("ssh-rsa".length()+4+ 401 e_array.length+4+ 402 n_array.length+4); 403 buf.putString("ssh-rsa".getBytes()); 404 buf.putString(e_array); 405 buf.putString(n_array); 406 return buf.buffer; 407 } 408 409 byte[] getPublicKeyBlob_dss(){ 410 if(P_array==null) return null; 411 Buffer buf=new Buffer("ssh-dss".length()+4+ 412 P_array.length+4+ 413 Q_array.length+4+ 414 G_array.length+4+ 415 pub_array.length+4); 416 buf.putString("ssh-dss".getBytes()); 417 buf.putString(P_array); 418 buf.putString(Q_array); 419 buf.putString(G_array); 420 buf.putString(pub_array); 421 return buf.buffer; 422 } 423 424 public byte[] getSignature(byte[] data){ 425 if(type==RSA) return getSignature_rsa(data); 426 return getSignature_dss(data); 427 } 428 429 byte[] getSignature_rsa(byte[] data){ 430 try{ 431 Class c=Class.forName((String )jsch.getConfig("signature.rsa")); 432 SignatureRSA rsa=(SignatureRSA)(c.newInstance()); 433 434 rsa.init(); 435 rsa.setPrvKey(d_array, n_array); 436 437 rsa.update(data); 438 byte[] sig = rsa.sign(); 439 Buffer buf=new Buffer("ssh-rsa".length()+4+ 440 sig.length+4); 441 buf.putString("ssh-rsa".getBytes()); 442 buf.putString(sig); 443 return buf.buffer; 444 } 445 catch(Exception e){ 446 } 447 return null; 448 } 449 450 byte[] getSignature_dss(byte[] data){ 451 473 474 try{ 475 Class c=Class.forName((String )jsch.getConfig("signature.dss")); 476 SignatureDSA dsa=(SignatureDSA)(c.newInstance()); 477 dsa.init(); 478 dsa.setPrvKey(prv_array, P_array, Q_array, G_array); 479 480 dsa.update(data); 481 byte[] sig = dsa.sign(); 482 Buffer buf=new Buffer("ssh-dss".length()+4+ 483 sig.length+4); 484 buf.putString("ssh-dss".getBytes()); 485 buf.putString(sig); 486 return buf.buffer; 487 } 488 catch(Exception e){ 489 } 491 return null; 492 } 493 494 public boolean decrypt(){ 495 if(type==RSA) return decrypt_rsa(); 496 return decrypt_dss(); 497 } 498 499 boolean decrypt_rsa(){ 500 byte[] p_array; 501 byte[] q_array; 502 byte[] dmp1_array; 503 byte[] dmq1_array; 504 byte[] iqmp_array; 505 506 try{ 507 byte[] plain; 508 if(encrypted){ 509 if(keytype==OPENSSH){ 510 cipher.init(Cipher.DECRYPT_MODE, key, iv); 511 plain=new byte[encoded_data.length]; 512 cipher.update(encoded_data, 0, encoded_data.length, plain, 0); 513 } 514 else if(keytype==FSECURE){ 515 for(int i=0; i<iv.length; i++)iv[i]=0; 516 cipher.init(Cipher.DECRYPT_MODE, key, iv); 517 plain=new byte[encoded_data.length]; 518 cipher.update(encoded_data, 0, encoded_data.length, plain, 0); 519 } 520 else{ 521 return false; 522 } 523 } 524 else{ 525 if(n_array!=null) return true; 526 plain=encoded_data; 527 } 528 529 if(keytype==FSECURE){ Buffer buf=new Buffer(plain); 531 int foo=buf.getInt(); 532 if(plain.length!=foo+4){ 533 return false; 534 } 535 e_array=buf.getMPIntBits(); 536 d_array=buf.getMPIntBits(); 537 n_array=buf.getMPIntBits(); 538 byte[] u_array=buf.getMPIntBits(); 539 p_array=buf.getMPIntBits(); 540 q_array=buf.getMPIntBits(); 541 return true; 542 } 543 544 int index=0; 545 int length=0; 546 547 if(plain[index]!=0x30)return false; 548 index++; length=plain[index++]&0xff; 550 if((length&0x80)!=0){ 551 int foo=length&0x7f; length=0; 552 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 553 } 554 555 if(plain[index]!=0x02)return false; 556 index++; length=plain[index++]&0xff; 558 if((length&0x80)!=0){ 559 int foo=length&0x7f; length=0; 560 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 561 } 562 index+=length; 563 564 568 index++; 569 length=plain[index++]&0xff; 570 if((length&0x80)!=0){ 571 int foo=length&0x7f; length=0; 572 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 573 } 574 n_array=new byte[length]; 575 System.arraycopy(plain, index, n_array, 0, length); 576 index+=length; 577 584 index++; 585 length=plain[index++]&0xff; 586 if((length&0x80)!=0){ 587 int foo=length&0x7f; length=0; 588 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 589 } 590 e_array=new byte[length]; 591 System.arraycopy(plain, index, e_array, 0, length); 592 index+=length; 593 600 index++; 601 length=plain[index++]&0xff; 602 if((length&0x80)!=0){ 603 int foo=length&0x7f; length=0; 604 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 605 } 606 d_array=new byte[length]; 607 System.arraycopy(plain, index, d_array, 0, length); 608 index+=length; 609 616 617 index++; 618 length=plain[index++]&0xff; 619 if((length&0x80)!=0){ 620 int foo=length&0x7f; length=0; 621 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 622 } 623 p_array=new byte[length]; 624 System.arraycopy(plain, index, p_array, 0, length); 625 index+=length; 626 633 index++; 634 length=plain[index++]&0xff; 635 if((length&0x80)!=0){ 636 int foo=length&0x7f; length=0; 637 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 638 } 639 q_array=new byte[length]; 640 System.arraycopy(plain, index, q_array, 0, length); 641 index+=length; 642 649 index++; 650 length=plain[index++]&0xff; 651 if((length&0x80)!=0){ 652 int foo=length&0x7f; length=0; 653 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 654 } 655 dmp1_array=new byte[length]; 656 System.arraycopy(plain, index, dmp1_array, 0, length); 657 index+=length; 658 665 index++; 666 length=plain[index++]&0xff; 667 if((length&0x80)!=0){ 668 int foo=length&0x7f; length=0; 669 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 670 } 671 dmq1_array=new byte[length]; 672 System.arraycopy(plain, index, dmq1_array, 0, length); 673 index+=length; 674 681 index++; 682 length=plain[index++]&0xff; 683 if((length&0x80)!=0){ 684 int foo=length&0x7f; length=0; 685 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 686 } 687 iqmp_array=new byte[length]; 688 System.arraycopy(plain, index, iqmp_array, 0, length); 689 index+=length; 690 697 } 698 catch(Exception e){ 699 return false; 701 } 702 return true; 703 } 704 705 boolean decrypt_dss(){ 706 try{ 707 byte[] plain; 708 if(encrypted){ 709 if(keytype==OPENSSH){ 710 cipher.init(Cipher.DECRYPT_MODE, key, iv); 711 plain=new byte[encoded_data.length]; 712 cipher.update(encoded_data, 0, encoded_data.length, plain, 0); 713 719 } 720 else if(keytype==FSECURE){ 721 for(int i=0; i<iv.length; i++)iv[i]=0; 722 cipher.init(Cipher.DECRYPT_MODE, key, iv); 723 plain=new byte[encoded_data.length]; 724 cipher.update(encoded_data, 0, encoded_data.length, plain, 0); 725 } 726 else{ 727 return false; 728 } 729 } 730 else{ 731 if(P_array!=null) return true; 732 plain=encoded_data; 733 } 734 735 if(keytype==FSECURE){ Buffer buf=new Buffer(plain); 737 int foo=buf.getInt(); 738 if(plain.length!=foo+4){ 739 return false; 740 } 741 P_array=buf.getMPIntBits(); 742 G_array=buf.getMPIntBits(); 743 Q_array=buf.getMPIntBits(); 744 pub_array=buf.getMPIntBits(); 745 prv_array=buf.getMPIntBits(); 746 return true; 747 } 748 749 int index=0; 750 int length=0; 751 if(plain[index]!=0x30)return false; 752 index++; length=plain[index++]&0xff; 754 if((length&0x80)!=0){ 755 int foo=length&0x7f; length=0; 756 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 757 } 758 if(plain[index]!=0x02)return false; 759 index++; length=plain[index++]&0xff; 761 if((length&0x80)!=0){ 762 int foo=length&0x7f; length=0; 763 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 764 } 765 index+=length; 766 767 index++; 768 length=plain[index++]&0xff; 769 if((length&0x80)!=0){ 770 int foo=length&0x7f; length=0; 771 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 772 } 773 P_array=new byte[length]; 774 System.arraycopy(plain, index, P_array, 0, length); 775 index+=length; 776 777 index++; 778 length=plain[index++]&0xff; 779 if((length&0x80)!=0){ 780 int foo=length&0x7f; length=0; 781 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 782 } 783 Q_array=new byte[length]; 784 System.arraycopy(plain, index, Q_array, 0, length); 785 index+=length; 786 787 index++; 788 length=plain[index++]&0xff; 789 if((length&0x80)!=0){ 790 int foo=length&0x7f; length=0; 791 while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); } 792 } 793 G_array=new byte[length]; 794 System.arraycopy(plain, index, G_array, 0, length); 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 pub_array=new byte[length]; 804 System.arraycopy(plain, index, pub_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 prv_array=new byte[length]; 814 System.arraycopy(plain, index, prv_array, 0, length); 815 index+=length; 816 } 817 catch(Exception e){ 818 return false; 821 } 822 return true; 823 } 824 825 public boolean isEncrypted(){ 826 return encrypted; 827 } 828 829 public String getName(){ 830 return identity; 831 } 832 833 private byte a2b(byte c){ 834 if('0'<=c&&c<='9') return (byte)(c-'0'); 835 if('a'<=c&&c<='z') return (byte)(c-'a'+10); 836 return (byte)(c-'A'+10); 837 } 838 839 public boolean equals(Object o){ 840 if(!(o instanceof IdentityFile)) return super.equals(o); 841 IdentityFile foo=(IdentityFile)o; 842 return getName().equals(foo.getName()); 843 } 844 845 public void clear(){ 846 Util.bzero(encoded_data); 847 Util.bzero(prv_array); 848 Util.bzero(d_array); 849 Util.bzero(key); 850 Util.bzero(iv); 851 } 852 853 public void finalize (){ 854 clear(); 855 } 856 } 857 | Popular Tags |