private Cipher genCipher()
 {
     try
     {
         Type t;
         t=Type.GetType(jsch.getConfig("3des-cbc"));
         cipher=(Cipher)(Activator.CreateInstance(t));
     }
     catch//(Exception e)
     {
     }
     return cipher;
 }
        private byte[] encrypt(byte[] plain, byte[][] _iv)
        {
            if(passphrase==null) return plain;

            if(cipher==null) cipher=genCipher();
            byte[] iv=_iv[0]=new byte[cipher.getIVSize()];

            if(random==null) random=genRandom();
            random.fill(iv, 0, iv.Length);

            byte[] key=genKey(passphrase, iv);
            byte[] encoded=plain;
            int bsize=cipher.getBlockSize();
            if(encoded.Length%bsize!=0)
            {
                byte[] foo=new byte[(encoded.Length/bsize+1)*bsize];
                Array.Copy(encoded, 0, foo, 0, encoded.Length);
                encoded=foo;
            }

            try
            {
                cipher.init(Cipher.ENCRYPT_MODE, key, iv);
                cipher.update(encoded, 0, encoded.Length, encoded, 0);
            }
            catch(Exception e)
            {
                Console.WriteLine(e);
            }
            return encoded;
        }
        internal IdentityFile(String identity, JSch jsch)
        {
            this.identity=identity;
            this.jsch=jsch;
            try
            {
                Type c=Type.GetType(jsch.getConfig("3des-cbc"));
                cipher=(Cipher)Activator.CreateInstance(c);
                key=new byte[cipher.getBlockSize()];   // 24
                iv=new byte[cipher.getIVSize()];       // 8
                c=Type.GetType(jsch.getConfig("md5"));
                hash=(HASH)(Activator.CreateInstance(c));
                hash.init();
                FileInfo file=new FileInfo(identity);
                FileStream fis = File.OpenRead(identity);
                byte[] buf=new byte[(int)(file.Length)];
                int len=fis.Read(buf, 0, buf.Length);
                fis.Close();

                int i=0;
                while(i<len)
                {
                    if(buf[i]=='B'&& buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I')
                    {
                        i+=6;
                        if(buf[i]=='D'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=DSS; }
                        else if(buf[i]=='R'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=RSA; }
                        else if(buf[i]=='S'&& buf[i+1]=='S'&& buf[i+2]=='H')
                        { // FSecure
                            type=UNKNOWN;
                            keytype=FSECURE;
                        }
                        else
                        {
                            //System.out.println("invalid format: "+identity);
                            throw new JSchException("invaid privatekey: "+identity);
                        }
                        i+=3;
                        continue;
                    }
                    if(buf[i]=='C'&& buf[i+1]=='B'&& buf[i+2]=='C'&& buf[i+3]==',')
                    {
                        i+=4;
                        for(int ii=0; ii<iv.Length; ii++)
                        {
                            iv[ii]=(byte)(((a2b(buf[i++])<<4)&0xf0)+
                                (a2b(buf[i++])&0xf));
                        }
                        continue;
                    }
                    if(buf[i]==0x0d &&
                        i+1<buf.Length && buf[i+1]==0x0a)
                    {
                        i++;
                        continue;
                    }
                    if(buf[i]==0x0a && i+1<buf.Length)
                    {
                        if(buf[i+1]==0x0a){ i+=2; break; }
                        if(buf[i+1]==0x0d &&
                            i+2<buf.Length && buf[i+2]==0x0a)
                        {
                            i+=3; break;
                        }
                        bool inheader=false;
                        for(int j=i+1; j<buf.Length; j++)
                        {
                            if(buf[j]==0x0a) break;
                            //if(buf[j]==0x0d) break;
                            if(buf[j]==':'){inheader=true; break;}
                        }
                        if(!inheader)
                        {
                            i++;
                            encrypted=false;    // no passphrase
                            break;
                        }
                    }
                    i++;
                }

                if(type==ERROR)
                {
                    throw new JSchException("invaid privatekey: "+identity);
                }

                int start=i;
                while(i<len)
                {
                    if(buf[i]==0x0a)
                    {
                        bool xd=(buf[i-1]==0x0d);
                        Array.Copy(buf, i+1,
                            buf,
                            i-(xd ? 1 : 0),
                            len-i-1-(xd ? 1 : 0)
                            );
                        if(xd)len--;
                        len--;
                        continue;
                    }
                    if(buf[i]=='-'){  break; }
                    i++;
                }
                encoded_data=Util.fromBase64(buf, start, i-start);

                if(encoded_data.Length>4 &&            // FSecure
                    encoded_data[0]==(byte)0x3f &&
                    encoded_data[1]==(byte)0x6f &&
                    encoded_data[2]==(byte)0xf9 &&
                    encoded_data[3]==(byte)0xeb)
                {

                    Buffer _buf=new Buffer(encoded_data);
                    _buf.getInt();  // 0x3f6ff9be
                    _buf.getInt();
                    byte[]_type=_buf.getString();
                    //System.out.println("type: "+new String(_type));
                    byte[] _cipher=_buf.getString();
                    String s_cipher=System.Text.Encoding.Default.GetString(_cipher);
                    //System.out.println("cipher: "+cipher);
                    if(s_cipher.Equals("3des-cbc"))
                    {
                        _buf.getInt();
                        byte[] foo=new byte[encoded_data.Length-_buf.getOffSet()];
                        _buf.getByte(foo);
                        encoded_data=foo;
                        encrypted=true;
                        throw new JSchException("unknown privatekey format: "+identity);
                    }
                    else if(s_cipher.Equals("none"))
                    {
                        _buf.getInt();
                        //_buf.getInt();

                        encrypted=false;

                        byte[] foo=new byte[encoded_data.Length-_buf.getOffSet()];
                        _buf.getByte(foo);
                        encoded_data=foo;
                    }

                }

                try
                {
                    file=new FileInfo(identity+".pub");
                    fis=File.OpenRead(identity+".pub");
                    buf=new byte[(int)(file.Length)];
                    len=fis.Read(buf, 0, buf.Length);
                    fis.Close();
                }
                catch
                {
                    return;
                }

                if(buf.Length>4 &&             // FSecure's public key
                    buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-')
                {

                    i=0;
                    do{i++;}while(buf.Length>i && buf[i]!=0x0a);
                    if(buf.Length<=i) return;

                    while(true)
                    {
                        if(buf[i]==0x0a)
                        {
                            bool inheader=false;
                            for(int j=i+1; j<buf.Length; j++)
                            {
                                if(buf[j]==0x0a) break;
                                if(buf[j]==':'){inheader=true; break;}
                            }
                            if(!inheader)
                            {
                                i++;
                                break;
                            }
                        }
                        i++;
                    }
                    if(buf.Length<=i) return;

                    start=i;
                    while(i<len)
                    {
                        if(buf[i]==0x0a)
                        {
                            Array.Copy(buf, i+1, buf, i, len-i-1);
                            len--;
                            continue;
                        }
                        if(buf[i]=='-'){  break; }
                        i++;
                    }
                    publickeyblob=Util.fromBase64(buf, start, i-start);

                    if(type==UNKNOWN)
                    {
                        if(publickeyblob[8]=='d')
                        {
                            type=DSS;
                        }
                        else if(publickeyblob[8]=='r')
                        {
                            type=RSA;
                        }
                    }
                }
                else
                {
                    if(buf[0]!='s'|| buf[1]!='s'|| buf[2]!='h'|| buf[3]!='-') return;
                    i=0;
                    while(i<len){ if(buf[i]==' ')break; i++;} i++;
                    if(i>=len) return;
                    start=i;
                    while(i<len){ if(buf[i]==' ')break; i++;}
                    publickeyblob=Util.fromBase64(buf, start, i-start);
                }

            }
            catch(Exception e)
            {
                Console.WriteLine("Identity: "+e);
                if(e is JSchException) throw (JSchException)e;
                throw new JSchException(e.ToString());
            }
        }
        internal byte[] genKey(byte[] passphrase, byte[] iv)
        {
            if(cipher==null) cipher=genCipher();
            if(hash==null) hash=genHash();

            byte[] key=new byte[cipher.getBlockSize()];
            int hsize=hash.getBlockSize();
            byte[] hn=new byte[key.Length/hsize*hsize+
                (key.Length%hsize==0?0:hsize)];
            try
            {
                byte[] tmp=null;
                if(vendor==VENDOR_OPENSSH)
                {
                    for(int index=0; index+hsize<=hn.Length;)
                    {
                        if(tmp!=null){ hash.update(tmp, 0, tmp.Length); }
                        hash.update(passphrase, 0, passphrase.Length);
                        hash.update(iv, 0, iv.Length);
                        tmp=hash.digest();
                        Array.Copy(tmp, 0, hn, index, tmp.Length);
                        index+=tmp.Length;
                    }
                    Array.Copy(hn, 0, key, 0, key.Length);
                }
                else if(vendor==VENDOR_FSECURE)
                {
                    for(int index=0; index+hsize<=hn.Length;)
                    {
                        if(tmp!=null){ hash.update(tmp, 0, tmp.Length); }
                        hash.update(passphrase, 0, passphrase.Length);
                        tmp=hash.digest();
                        Array.Copy(tmp, 0, hn, index, tmp.Length);
                        index+=tmp.Length;
                    }
                    Array.Copy(hn, 0, key, 0, key.Length);
                }
            }
            catch(Exception e)
            {
                Console.WriteLine(e);
            }
            return key;
        }
        private void updateKeys(KeyExchange kex)
        {
            byte[] K=kex.getK();
            byte[] H=kex.getH();
            HASH hash=kex.getHash();

            String[] guess=kex._guess;

            if(session_id==null)
            {
                session_id=new byte[H.Length];
                SharpSSH.SharpSsh.java.System.arraycopy(H, 0, session_id, 0, H.Length);
            }

            /*
              Initial IV client to server:     HASH (K || H || "A" || session_id)
              Initial IV server to client:     HASH (K || H || "B" || session_id)
              Encryption key client to server: HASH (K || H || "C" || session_id)
              Encryption key server to client: HASH (K || H || "D" || session_id)
              Integrity key client to server:  HASH (K || H || "E" || session_id)
              Integrity key server to client:  HASH (K || H || "F" || session_id)
            */

            buf.reset();
            buf.putMPInt(K);
            buf.putByte(H);
            buf.putByte((byte)0x41);
            buf.putByte(session_id);
            hash.update(buf.buffer, 0, buf.index);
            IVc2s=hash.digest();

            int j=buf.index-session_id.Length-1;

            buf.buffer[j]++;
            hash.update(buf.buffer, 0, buf.index);
            IVs2c=hash.digest();

            buf.buffer[j]++;
            hash.update(buf.buffer, 0, buf.index);
            Ec2s=hash.digest();

            buf.buffer[j]++;
            hash.update(buf.buffer, 0, buf.index);
            Es2c=hash.digest();

            buf.buffer[j]++;
            hash.update(buf.buffer, 0, buf.index);
            MACc2s=hash.digest();

            buf.buffer[j]++;
            hash.update(buf.buffer, 0, buf.index);
            MACs2c=hash.digest();

            try
            {
                Class c;

                c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC]));
                s2ccipher=(Cipher)(c.newInstance());
                while(s2ccipher.getBlockSize()>Es2c.Length)
                {
                    buf.reset();
                    buf.putMPInt(K);
                    buf.putByte(H);
                    buf.putByte(Es2c);
                    hash.update(buf.buffer, 0, buf.index);
                    byte[] foo=hash.digest();
                    byte[] bar=new byte[Es2c.Length+foo.Length];
                    SharpSSH.SharpSsh.java.System.arraycopy(Es2c, 0, bar, 0, Es2c.Length);
                    SharpSSH.SharpSsh.java.System.arraycopy(foo, 0, bar, Es2c.Length, foo.Length);
                    Es2c=bar;
                }
                s2ccipher.init(Cipher.DECRYPT_MODE, Es2c, IVs2c);
                cipher_size=s2ccipher.getIVSize();
                c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_MAC_ALGS_STOC]));
                s2cmac=(MAC)(c.newInstance());
                s2cmac.init(MACs2c);
                mac_buf=new byte[s2cmac.getBlockSize()];

                c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS]));
                c2scipher=(Cipher)(c.newInstance());
                while(c2scipher.getBlockSize()>Ec2s.Length)
                {
                    buf.reset();
                    buf.putMPInt(K);
                    buf.putByte(H);
                    buf.putByte(Ec2s);
                    hash.update(buf.buffer, 0, buf.index);
                    byte[] foo=hash.digest();
                    byte[] bar=new byte[Ec2s.Length+foo.Length];
                    SharpSSH.SharpSsh.java.System.arraycopy(Ec2s, 0, bar, 0, Ec2s.Length);
                    SharpSSH.SharpSsh.java.System.arraycopy(foo, 0, bar, Ec2s.Length, foo.Length);
                    Ec2s=bar;
                }
                c2scipher.init(Cipher.ENCRYPT_MODE, Ec2s, IVc2s);

                c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_MAC_ALGS_CTOS]));
                c2smac=(MAC)(c.newInstance());
                c2smac.init(MACc2s);

                if(!guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS].equals("none"))
                {
                    String foo=getConfig(guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS]);
                    if(foo!=null)
                    {
                        try
                        {
                            c=Class.forName(foo);
                            deflater=(Compression)(c.newInstance());
                            int level=6;
                            try{ level=Integer.parseInt(getConfig("compression_level"));}
                            catch(Exception ee){ }
                            deflater.init(Compression.DEFLATER, level);
                        }
                        catch(Exception ee)
                        {
                            System.Console.Error.WriteLine(foo+" isn't accessible.");
                        }
                    }
                }
                else
                {
                    if(deflater!=null)
                    {
                        deflater=null;
                    }
                }
                if(!guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC].equals("none"))
                {
                    String foo=getConfig(guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC]);
                    if(foo!=null)
                    {
                        try
                        {
                            c=Class.forName(foo);
                            inflater=(Compression)(c.newInstance());
                            inflater.init(Compression.INFLATER, 0);
                        }
                        catch(Exception ee)
                        {
                            System.Console.Error.WriteLine(foo+" isn't accessible.");
                        }
                    }
                }
                else
                {
                    if(inflater!=null)
                    {
                        inflater=null;
                    }
                }
            }
            catch(Exception e){ System.Console.Error.WriteLine("updatekeys: "+e); }
        }