1 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
3 Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
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.
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.
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.
30 package com.jcraft.jsch;
34 class IdentityFile implements Identity{
40 private byte[] encoded_data;
42 private Cipher cipher;
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;
52 private byte[] n_array; // modulus
53 private byte[] e_array; // public exponent
54 private byte[] d_array; // private exponent
56 // private String algname="ssh-dss";
57 private String algname="ssh-rsa";
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;
64 private static final int OPENSSH=0;
65 private static final int FSECURE=1;
66 private static final int PUTTY=2;
68 private int type=ERROR;
69 private int keytype=OPENSSH;
71 private byte[] publickeyblob=null;
73 private boolean encrypted=true;
75 static IdentityFile newInstance(String prvfile, String pubfile, JSch jsch) throws JSchException{
80 FileInputStream fis=null;
82 file=new File(prvfile);
83 fis=new FileInputStream(prvfile);
84 prvkey=new byte[(int)(file.length())];
87 int i=fis.read(prvkey, len, prvkey.length-len);
95 try{ if(fis!=null) fis.close();}
97 if(e instanceof Throwable)
98 throw new JSchException(e.toString(), (Throwable)e);
99 throw new JSchException(e.toString());
102 String _pubfile=pubfile;
104 _pubfile=prvfile+".pub";
108 file=new File(_pubfile);
109 fis = new FileInputStream(_pubfile);
110 pubkey=new byte[(int)(file.length())];
113 int i=fis.read(pubkey, len, pubkey.length-len);
121 try{ if(fis!=null) fis.close();}
122 catch(Exception ee){}
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());
130 return newInstance(prvfile, prvkey, pubkey, jsch);
133 static IdentityFile newInstance(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{
135 return new IdentityFile(name, prvkey, pubkey, jsch);
142 private IdentityFile(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{
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());
161 if(buf[i] == '-' && i+4<len &&
162 buf[i+1] == '-' && buf[i+2] == '-' &&
163 buf[i+3] == '-' && buf[i+4] == '-'){
170 if(buf[i]=='B'&& i+3<len && buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I'){
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
179 //System.err.println("invalid format: "+identity);
180 throw new JSchException("invalid privatekey: "+identity);
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]=='-'){
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()];
195 throw new JSchException("privatekey: aes256-cbc is not available "+identity);
199 if(buf[i]=='C'&& i+3<len && buf[i+1]=='B'&& buf[i+2]=='C'&& buf[i+3]==','){
201 for(int ii=0; ii<iv.length; ii++){
202 iv[ii]=(byte)(((a2b(buf[i++])<<4)&0xf0)+
203 (a2b(buf[i++])&0xf));
207 if(buf[i]==0x0d && i+1<len && buf[i+1]==0x0a){
211 if(buf[i]==0x0a && i+1<len){
212 if(buf[i+1]==0x0a){ i+=2; break; }
214 i+2<len && buf[i+2]==0x0a){
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;}
225 encrypted=false; // no passphrase
233 throw new JSchException("invalid privatekey: "+identity);
239 boolean xd=(buf[i-1]==0x0d);
240 System.arraycopy(buf, i+1,
249 if(buf[i]=='-'){ break; }
252 encoded_data=Util.fromBase64(buf, start, i-start);
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){
260 Buffer _buf=new Buffer(encoded_data);
261 _buf.getInt(); // 0x3f6ff9be
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")){
270 byte[] foo=new byte[encoded_data.length-_buf.getOffSet()];
274 throw new JSchException("unknown privatekey format: "+identity);
276 else if(cipher.equals("none")){
282 byte[] foo=new byte[encoded_data.length-_buf.getOffSet()];
296 if(buf.length>4 && // FSecure's public key
297 buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){
299 do{i++;}while(len>i && 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;}
320 System.arraycopy(buf, i+1, buf, i, len-i-1);
324 if(buf[i]=='-'){ break; }
327 publickeyblob=Util.fromBase64(buf, start, i-start);
329 if(type==UNKNOWN && publickeyblob.length>8){
330 if(publickeyblob[8]=='d'){
333 else if(publickeyblob[8]=='r'){
339 if(buf[0]!='s'|| buf[1]!='s'|| buf[2]!='h'|| buf[3]!='-') return;
341 while(i<len){ if(buf[i]==' ')break; i++;} 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");
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());
364 public String getAlgName(){
365 if(type==RSA) return "ssh-rsa";
369 public boolean setPassphrase(byte[] _passphrase) throws JSchException{
372 h(0) <- hash(passphrase, iv);
373 h(n) <- hash(h(n-1), passphrase, iv);
374 key <- (h(0),...,h(n))[0,..,key.length];
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)];
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);
390 System.arraycopy(tmp, 0, hn, index, tmp.length);
393 System.arraycopy(hn, 0, key, 0, key.length);
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);
400 System.arraycopy(tmp, 0, hn, index, tmp.length);
403 System.arraycopy(hn, 0, key, 0, key.length);
405 Util.bzero(passphrase);
411 P_array=Q_array=G_array=pub_array=prv_array=null;
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());
422 public byte[] getPublicKeyBlob(){
423 if(publickeyblob!=null) return publickeyblob;
424 if(type==RSA) return getPublicKeyBlob_rsa();
425 return getPublicKeyBlob_dss();
428 byte[] getPublicKeyBlob_rsa(){
429 if(e_array==null) return null;
430 Buffer buf=new Buffer("ssh-rsa".length()+4+
433 buf.putString(Util.str2byte("ssh-rsa"));
434 buf.putString(e_array);
435 buf.putString(n_array);
439 byte[] getPublicKeyBlob_dss(){
440 if(P_array==null) return null;
441 Buffer buf=new Buffer("ssh-dss".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);
454 public byte[] getSignature(byte[] data){
455 if(type==RSA) return getSignature_rsa(data);
456 return getSignature_dss(data);
459 byte[] getSignature_rsa(byte[] data){
461 Class c=Class.forName((String)jsch.getConfig("signature.rsa"));
462 SignatureRSA rsa=(SignatureRSA)(c.newInstance());
465 rsa.setPrvKey(d_array, n_array);
468 byte[] sig = rsa.sign();
469 Buffer buf=new Buffer("ssh-rsa".length()+4+
471 buf.putString(Util.str2byte("ssh-rsa"));
480 byte[] getSignature_dss(byte[] data){
484 System.err.print("P ");
486 for(i=0; i<foo.length; i++){
487 System.err.print(Integer.toHexString(foo[i]&0xff)+":");
489 System.err.println("");
490 System.err.print("Q ");
492 for(i=0; i<foo.length; i++){
493 System.err.print(Integer.toHexString(foo[i]&0xff)+":");
495 System.err.println("");
496 System.err.print("G ");
498 for(i=0; i<foo.length; i++){
499 System.err.print(Integer.toHexString(foo[i]&0xff)+":");
501 System.err.println("");
505 Class c=Class.forName((String)jsch.getConfig("signature.dss"));
506 SignatureDSA dsa=(SignatureDSA)(c.newInstance());
508 dsa.setPrvKey(prv_array, P_array, Q_array, G_array);
511 byte[] sig = dsa.sign();
512 Buffer buf=new Buffer("ssh-dss".length()+4+
514 buf.putString(Util.str2byte("ssh-dss"));
519 //System.err.println("e "+e);
524 public boolean decrypt(){
525 if(type==RSA) return decrypt_rsa();
526 return decrypt_dss();
529 boolean decrypt_rsa(){
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);
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);
555 if(n_array!=null) return true;
559 if(keytype==FSECURE){ // FSecure
560 Buffer buf=new Buffer(plain);
561 int foo=buf.getInt();
562 if(plain.length!=foo+4){
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();
577 if(plain[index]!=0x30)return false;
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); }
585 if(plain[index]!=0x02)return false;
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); }
594 //System.err.println("int: len="+length);
595 //System.err.print(Integer.toHexString(plain[index-1]&0xff)+":");
596 //System.err.println("");
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); }
604 n_array=new byte[length];
605 System.arraycopy(plain, index, n_array, 0, length);
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)+":");
612 System.err.println("");
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); }
620 e_array=new byte[length];
621 System.arraycopy(plain, index, e_array, 0, length);
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)+":");
628 System.err.println("");
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); }
636 d_array=new byte[length];
637 System.arraycopy(plain, index, d_array, 0, length);
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)+":");
644 System.err.println("");
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); }
653 p_array=new byte[length];
654 System.arraycopy(plain, index, p_array, 0, length);
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)+":");
661 System.err.println("");
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); }
669 q_array=new byte[length];
670 System.arraycopy(plain, index, q_array, 0, length);
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)+":");
677 System.err.println("");
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); }
685 dmp1_array=new byte[length];
686 System.arraycopy(plain, index, dmp1_array, 0, length);
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)+":");
693 System.err.println("");
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); }
701 dmq1_array=new byte[length];
702 System.arraycopy(plain, index, dmq1_array, 0, length);
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)+":");
709 System.err.println("");
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); }
717 iqmp_array=new byte[length];
718 System.arraycopy(plain, index, iqmp_array, 0, length);
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)+":");
725 System.err.println("");
729 //System.err.println(e);
735 boolean decrypt_dss(){
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);
744 for(int i=0; i<plain.length; i++){
745 System.err.print(Integer.toHexString(plain[i]&0xff)+":");
747 System.err.println("");
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);
761 if(P_array!=null) return true;
765 if(keytype==FSECURE){ // FSecure
766 Buffer buf=new Buffer(plain);
767 int foo=buf.getInt();
768 if(plain.length!=foo+4){
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();
781 if(plain[index]!=0x30)return false;
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); }
788 if(plain[index]!=0x02)return false;
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); }
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); }
803 P_array=new byte[length];
804 System.arraycopy(plain, index, P_array, 0, length);
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); }
813 Q_array=new byte[length];
814 System.arraycopy(plain, index, Q_array, 0, length);
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); }
823 G_array=new byte[length];
824 System.arraycopy(plain, index, G_array, 0, length);
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); }
833 pub_array=new byte[length];
834 System.arraycopy(plain, index, pub_array, 0, length);
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); }
843 prv_array=new byte[length];
844 System.arraycopy(plain, index, prv_array, 0, length);
848 //System.err.println(e);
849 //e.printStackTrace();
855 public boolean isEncrypted(){
859 public String getName(){
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);
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());
876 Util.bzero(encoded_data);
877 Util.bzero(prv_array);
883 public void finalize (){