前言

這學期上老師的PCS課程時,最後的Final Project要我們用SMS系統下指令來實現一些創意。和組員商量了下後決定用手機SMS下指令達成秘鑰對生成與自動分發,我們以SSH密鑰對連線為例。我負責收到指令後自動產生密鑰對,將公鑰自動寫入目標連線機器,將私鑰以SM回傳。在查閱了資料後,我決定用Jsch完成這一自動化過程。


Jsch介紹

JSch is a pure Java implementation of SSH2.JSch allows you to connect to an sshd server and use port forwarding, X11 forwarding, file transfer, etc., and you can integrate its functionality into your own Java programs.


安裝

可以直接從官網上下載jar包後導入即可使用:


實踐

這邊主要有兩部分的工作,一部分是jsch內置的函數完成key pair的生成,還有一部分是使用jsch連接上遠程的伺服器並執行命令將Public key放入指定位置。

生成KeyPair

這邊就是調用KeyPair.genKeyPair()這一函數產生密鑰對,然後寫出秘鑰文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public static String genkey(String Uid_h) {
String filename = "id_rsa";
String comment = "";
String privatekeystring = "";

JSch jsch = new JSch();

byte[] passphrase = Uid_h.getBytes(StandardCharsets.UTF_8);

try {
//Genkey
KeyPair kpair = KeyPair.genKeyPair(jsch, KeyPair.RSA);

ByteArrayOutputStream S1 = new ByteArrayOutputStream();
kpair.writePrivateKey(S1, passphrase);
//kpair.writePrivateKey("id_rsa",passphrase);
privatekeystring = S1.toString();
//System.out.println(privatekeystring);
File file = new File("./id_rsa");
PrintStream ps = new PrintStream(new FileOutputStream(file));
ps.println(privatekeystring);

kpair.writePublicKey(filename + ".pub", comment);
System.out.println("Finger print: " + kpair.getFingerPrint());
kpair.dispose();
File pvtKey = new File("keypair");
pvtKey.setWritable(false);

} catch (Exception e) {
System.out.println(e);
} finally {
return privatekeystring;
}

連接遠端機器執行寫入命令

這邊大致的流程就是:設置連接參數與要執行的命令->建立session連接->記錄可能出現的錯誤並返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public static void uploadkey() throws JSchException, InterruptedException, IOException {
ChannelExec channelExec = null;
BufferedReader inputStreamReader = null;
BufferedReader errInputStreamReader = null;
StringBuilder runLog = new StringBuilder("");
StringBuilder errLog = new StringBuilder("");
JSch jsch = new JSch();
Session session = null;


try {

//設定連接的賬號密碼port
String USER = "";
String PASSWORD = "";
String HOST = "";
int DEFAULT_SSH_PORT =;
String cmd = ""; //命令

//建構命令
cmd = getcmd();

cmd = "echo " + cmd + " >> /ssd/labguest/.ssh/authorized_keys";

session = jsch.getSession(USER, HOST, DEFAULT_SSH_PORT);
session.setPassword(PASSWORD);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();


channelExec = (ChannelExec) session.openChannel("exec");

//channelExec.setCommand("ifconfig;");
channelExec.setCommand(cmd);
channelExec.connect();

//獲取標準輸入流
inputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getInputStream()));
//獲取標準錯誤輸入流
errInputStreamReader = new BufferedReader(new InputStreamReader(channelExec.getErrStream()));

//記錄命令執行 log
String line = null;
while ((line = inputStreamReader.readLine()) != null) {
runLog.append(line).append("\n");
}

//記錄命令執行錯誤 log
String errLine = null;
while ((errLine = errInputStreamReader.readLine()) != null) {
errLog.append(errLine).append("\n");
}

//輸出 shell 命令執行紀錄檔
System.out.println("exitStatus=" + channelExec.getExitStatus() + ", openChannel.isClosed="
+ channelExec.isClosed());
System.out.println("Run log:");
System.out.println(runLog.toString());
System.out.println("Error log:");
System.out.println(errLog.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (errInputStreamReader != null) {
errInputStreamReader.close();
}

if (channelExec != null) {
channelExec.disconnect();
}
if (session != null) {
session.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}


}


遇到的問題

  • 記得要處理key的訪問權限,要不然連線時會報錯。

參考

  • Jsch Official Web
  • https://segmentfault.com/a/1190000019967309?utm_source=tag-newest