Міністерство освіти і науки України
Національний університет «Львівська політехніка»
Кафедра ЕОМ
/
Звіт
з лабораторної роботи № 3
з дисципліни:
«Програмні технології захисту інформації»
Львів-2015
Тема: Протокол SSH. Створення простого SSH-клієнта.
Мета: Написати програму, яка буде підтримувати основні функції для роботи по протоколу SSH.
Хід роботи:
Для створення програмного продукту було реалізовано наступні класи:
UserAuthPubKey
public class UserAuthPubKey
{
public void Auth()
{
try
{
JSch jsch=new JSch();
OpenFileDialog chooser = new OpenFileDialog();
chooser.Title ="Choose your privatekey(ex. ~/.ssh/id_dsa)";
//chooser.setFileHidingEnabled(false);
DialogResult returnVal = chooser.ShowDialog();
if(returnVal == DialogResult.OK)
{
Console.WriteLine("You chose "+
chooser.FileName+".");
jsch.addIdentity(chooser.FileName
// , "passphrase"
);
}
else
{
Console.WriteLine("Error getting key file...");
return;
}
InputForm inForm = new InputForm();
inForm.Text = "Enter username@hostname";
inForm.textBox1.Text = Environment.UserName+"@localhost";
if (inForm.PromptForInput())
{
String host = inForm.textBox1.Text;
String user=host.Substring(0, host.IndexOf('@'));
host=host.Substring(host.IndexOf('@')+1);
Session session=jsch.getSession(user, host, 22);
// username and passphrase will be given via UserInfo interface.
UserInfo ui=new MyUserInfo();
session.setUserInfo(ui);
session.connect();
Channel channel=session.openChannel("shell");
channel.setInputStream(Console.OpenStandardInput());
channel.setOutputStream(Console.OpenStandardOutput());
channel.connect();
}
inForm.Close();
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
public class MyUserInfo : UserInfo
{
public String getPassword(){ return null; }
public bool promptYesNo(String str)
{
returnVal = MessageBox.Show(
str,
"SharpSSH",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning);
return (returnVal==DialogResult.Yes);
}
internal String passphrase;
//JTextField passphraseField=(JTextField)new JPasswordField(20);
//InputForm inForm = null;
DialogResult returnVal;
public String getPassphrase(){ return passphrase; }
public bool promptPassphrase(String message)
{
InputForm inForm = new InputForm();
inForm.Text = message;
inForm.PasswordField = true;
if ( inForm.PromptForInput() )
{
passphrase=inForm.textBox1.Text;
inForm.Close();
return true;
}
else
{
inForm.Close();
return false;
}
}
public bool promptPassword(String message){ return true; }
public void showMessage(String message)
{
MessageBox.Show(
message,
"SharpSSH",
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk);
}
}
Цей клас дозволяє аутентифікуватися в системі за допомогою публічного ключа. Користувач повинен ввести свій логін, адресу хоста, до якого відбувається підключення, приватний ключ і пароль. Якщо введені дані вірні, ви отримаєте доступ до оболонки.
ScpTO
public class ScpTo
{
public static void Send(string[] arg)
{
if(arg.Length!=2)
{
Console.WriteLine("usage: c# ScpTo file1 user@remotehost:file2");
Environment.Exit(-1);
}
try
{
String lfile=arg[0];
String user=arg[1].Substring(0, arg[1].IndexOf('@'));
arg[1]=arg[1].Substring(arg[1].IndexOf('@')+1);
String host=arg[1].Substring(0, arg[1].IndexOf(':'));
String rfile=arg[1].Substring(arg[1].IndexOf(':')+1);
JSch jsch=new JSch();
Session session=jsch.getSession(user, host, 22);
// username and password will be given via UserInfo interface.
UserInfo ui=new MyUserInfo();
session.setUserInfo(ui);
session.connect();
// exec 'scp -t rfile' remotely
String command="scp -p -t "+rfile;
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(command);
// get I/O streams for remote scp
Stream outs=channel.getOutputStream();
Stream ins=channel.getInputStream();
channel.connect();
byte[] tmp=new byte[1];
if(checkAck(ins)!=0)
{
Environment.Exit(0);
}
// send "C0644 filesize filename", where filename should not include '/'
int filesize=(int)(new FileInfo(lfile)).Length;
command="C0644 "+filesize+" ";
if(lfile.LastIndexOf('/')>0)
{
command+=lfile.Substring(lfile.LastIndexOf('/')+1);
}
else
{
command+=lfile;
}
command+="\n";
byte[] buff = Util.getBytes(command);
outs.Write(buff, 0, buff.Length); outs.Flush();
if(checkAck(ins)!=0)
{
Environment.Exit(0);
}
// send a content of lfile
FileStream fis=File.OpenRead(lfile);
byte[] buf=new byte[1024];
while(true)
{
int len=fis.Read(buf, 0, buf.Length);
if(len<=0) break;
outs.Write(buf, 0, len); outs.Flush();
Console.Write("#");
}
// send '\0'
buf[0]=0; outs.Write(buf, 0, 1); outs.Flush();
Console.Write(".");
if(checkAck(ins)!=0)
{
Environment.Exit(0);
}
Console.WriteLine("OK");
Environment.Exit(0);
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
static int checkAck(Stream ins)
{
Console.Write(".");
int b=ins.ReadByte();
Console.Write(".");
// b may be 0 for success,
// 1 for error,
// 2 for fatal error,
// -1
if(b==0) return b;
if(b==-1) return b;
if(b==1 || b==2)
{
StringBuilder sb=new StringBuilder();
int c;
do
{
c=ins.ReadByte();
sb.Append((char)c);
}
while(c!='\n');
if(b==1)
{ // error
Console.Write(sb.ToString());
}
if(b==2)
{ // fatal error
Console.Write(sb.ToString());
}
}
return b;
}
Даний клас призначений для передачі файлів по захищеному протоколі.
Пройшовши аутентифікацію, користувач має змогу відправити файли до віддаленого комп’ютера.
Sftp
public class Sftp
{
public static void Connect(String[] arg)
{
try
{
JSch jsch=new JSch();
InputForm inForm = new InputForm();
inForm.Text = "Enter username@hostname";
inForm.textBox1.Text = Environment.UserName+"@localhost";
if (!inForm.PromptForInput())
{
Console.WriteLine("Cancelled");
return;
}
String host = inForm.textBox1.Text;
String user=host.Substring(0, host.IndexOf('@'));
host=host.Substring(host.IndexOf('@')+1);
Session session=jsch.getSession(user, host, 22);
// username and password will be given via UserInfo interface.
UserInfo ui=new MyUserInfo();
session.setUserInfo(ui);
session.connect();
Channel channel=session.openChannel("sftp");
channel.connect();
ChannelSftp c=(ChannelSftp)channel;
Stream ins=Console.OpenStandardInput();
TextWriter outs=Console.Out;
ArrayList cmds=new ArrayList();
byte[] buf=new byte[1024];
int i;
String str;
int level=0;
while(true)
{
outs.Write("sftp> ");
cmds.Clear();
i=ins.Read(buf, 0, 1024);
if(i<=0)break;
i--;
if(i>0 && buf[i-1]==0x0d)i--;
//str=Util.getString(buf, 0, i);
//Console.WriteLine("|"+str+"|");
int s=0;
for(int ii=0; ii<i; ii++)
{
if(buf[ii]==' ')
{
if(ii-s>0){ cmds.Add(Util.getString(buf, s, ii-s)); }
while(ii<i){if(buf[ii]!=' ')break; ii++;}
s=ii;
}
}
if(s<i){ cmds.Add(Util.getString(buf, s, i-s)); }
if(cmds.Count==0)continue;
String cmd=(String)cmds[0];
if(cmd.Equals("quit"))
{
c.quit();
break;
}
if(cmd.Equals("exit"))
{
c.exit();
break;
}
if(cmd.Equals("rekey"))
{
session.rekey();
continue;
}
if(cmd.Equals("compression"))
{
if(cmds.Count<2)
{
outs.WriteLine("compression level: "+level);
continue;
}
try
{
level=int.Parse((String)cmds[1]);
Hashtable config=new Hashtable();
if(level==0)
{
config.Add("compression.s2c", "none");
config.Add("compression.c2s", "none");
}
else
{
config.Add("compression.s2c", "zlib,none");
config.Add("compression.c2s", "zlib,none");
}
session.setConfig(config);
}
catch{}//(Exception e){}
continue;
}
if(cmd.Equals("cd") || cmd.Equals("lcd"))
{
if(cmds.Count<2) continue;
String path=(String)cmds[1];
try
{
if(cmd.Equals("cd")) c.cd(path);
else c.lcd(path);
}
catch(SftpException e)
{
Console.WriteLine(e.message);
}
continue;
}
if(cmd.Equals("rm") || cmd.Equals("rmdir") || cmd.Equals("mkdir"))
{
if(cmds.Count<2) continue;
String path=(String)cmds[1];
try
{
if(cmd.Equals("rm")) c.rm(path);
else if(cmd.Equals("rmdir")) c.rmdir(path);
else c.mkdir(path);
}
catch(SftpException e)
{
Console.WriteLine(e.message);
}
continue;
}
if(cmd.Equals("chgrp") || cmd.Equals("chown") || cmd.Equals("chmod"))
{
if(cmds.Count!=3) continue;
String path=(String)cmds[2];
int foo=0;
if(cmd.Equals("chmod"))
{
byte[] bar=Util.getBytes((String)cmds[1]);
int k;
for(int j=0; j<bar.Length; j++)
{
k=bar[j];
if(k<'0'||k>'7'){foo=-1; break;}
foo<<=3;
foo|=(k-'0');
}
if(foo==-1)continue;
}
else
{
try{foo=int.Parse((String)cmds[1]);}
catch{}//(Exception e){continue;}
}
try
{
if(cmd.Equals("chgrp")){ c.chgrp(foo, path); }
else if(cmd.Equals("chown")){ c.chown(foo, path); }
else if(cmd.Equals("chmod")){ c.chmod(foo, path); }
}
catch(SftpException e)
{
Console.WriteLine(e.message);
}
continue;
}
if(cmd.Equals("pwd") || cmd.Equals("lpwd"))
{
str=(cmd.Equals("pwd")?"Remote":"Local");
str+=" working directory: ";
if(cmd.Equals("pwd")) str+=c.pwd();
else str+=c.lpwd();
outs.WriteLine(str);
continue;
}
if(cmd.Equals("ls") || cmd.Equals("dir"))
{
String path=".";
if(cmds.Count==2) path=(String)cmds[1];
try
{
ArrayList vv=c.ls(path);
if(vv!=null)
{
for(int ii=0; ii<vv.Count; ii++)
{
/*
Object obj=vv.elementAt(ii);
if(obj instanceof com.jcraft.jsch.ChannelSftp.Ssh_exp_name )
outs.WriteLine(((com.jcraft.jsch.ChannelSftp.Ssh_exp_name)obj).getLongname());
else if(obj instanceof java.lang.String)
outs.WriteLine(obj);
else
throw new Exception("opps, got an odd type back");
*/
outs.WriteLine(vv[ii]);
}
}
}
catch(SftpException e)
{
Console.WriteLine(e.message);
}
continue;
}
if(cmd.Equals("lls") || cmd.Equals("ldir"))
{
String path=".";
if(cmds.Count==2) path=(String)cmds[1];
try
{
//java.io.File file=new java.io.File(path);
if(!File.Exists(path))
{
outs.WriteLine(path+": No such file or directory");
continue;
}
if(Directory.Exists(path))
{
String[] list=Directory.GetDirectories(path);
for(int ii=0; ii<list.Length; ii++)
{
outs.WriteLine(list[ii]);
}
continue;
}
outs.WriteLine(path);
}
catch(Exception e)
{
Console.WriteLine(e);
}
continue;
}
if(cmd.Equals("get") ||
cmd.Equals("get-resume") || cmd.Equals("get-append") ||
cmd.Equals("put") ||
cmd.Equals("put-resume") || cmd.Equals("put-append")
)
{
if(cmds.Count!=2 && cmds.Count!=3) continue;
String p1=(String)cmds[1];
// String p2=p1;
String p2=".";
if(cmds.Count==3)p2=(String)cmds[2];
try
{
SftpProgressMonitor monitor=new MyProgressMonitor();
if(cmd.StartsWith("get"))
{
int mode=ChannelSftp.OVERWRITE;
if(cmd.Equals("get-resume")){ mode=ChannelSftp.RESUME; }
else if(cmd.Equals("get-append")){ mode=ChannelSftp.APPEND; }
c.get(p1, p2, monitor, mode);
}
else
{
int mode=ChannelSftp.OVERWRITE;
if(cmd.Equals("put-resume")){ mode=ChannelSftp.RESUME; }
else if(cmd.Equals("put-append")){ mode=ChannelSftp.APPEND; }
c.put(p1, p2, monitor, mode);
}
}
catch(SftpException e)
{
Console.WriteLine(e.message);
}
continue;
}
if(cmd.Equals("ln") || cmd.Equals("symlink") || cmd.Equals("rename"))
{
if(cmds.Count!=3) continue;
String p1=(String)cmds[1];
String p2=(String)cmds[2];
try
{
if(cmd.Equals("rename")) c.rename(p1, p2);
else c.symlink(p1, p2);
}
catch(SftpException e)
{
Console.WriteLine(e.message);
}
continue;
}
if(cmd.Equals("stat") || cmd.Equals("lstat"))
{
if(cmds.Count!=2) continue;
String p1=(String)cmds[1];
SftpATTRS attrs=null;
try
{
if(cmd.Equals("stat")) attrs=c.stat(p1);
else attrs=c.lstat(p1);
}
catch(SftpException e)
{
Console.WriteLine(e.message);
}
if(attrs!=null)
{
outs.WriteLine(attrs);
}
else
{
}
continue;
}
if(cmd.Equals("version"))
{
outs.WriteLine("SFTP protocol version "+c.version());
continue;
}
if(cmd.Equals("help") || cmd.Equals("?"))
{
outs.WriteLine(help);
continue;
}
outs.WriteLine("unimplemented command: "+cmd);
}
session.disconnect();
}
catch(Exception e)
{
Console.WriteLine(e);
}
Environment.Exit(0);
}