電子公文系統
個人貢獻值
本人對於此專案的貢獻是檔案傳輸和使用者口令的保護,及負責整個系統密碼安全
實踐過程
首先建立資料庫連線使用者名稱密碼
進入mysql本地
建立自己使用者名稱(20201325xjr)
為“20201325xjr”授全部許可權
檢視資料庫使用者是否新增成功
我們發現已經建立成功啦!
修改idea專案通過20201325xjr連線資料庫
就成功啦!!!
專案中資訊保護方法
此電子公文系統採用的是呼叫openssl演算法庫中的指令對資料進行加解密。首先我們來看一下專案crypto層的openssl類
crypto.Openssl
該專案的檔案傳輸使用SM4對稱加密,金鑰分配通過使用rand生成16位元組的隨機數,使用者密碼使用SM3演算法計算摘要值。部分程式碼如下:
SM3
public static String SM3(String data) throws IOException { List<String> commandArr = new ArrayList<>(); commandArr.add("/bin/sh"); commandArr.add("-c"); String cmd = "echo "+data+" | openssl sm3"; commandArr.add(cmd); String result = RunCmd.run(commandArr.toArray(new String[commandArr.size()])); return result.substring(9); }
SM4
public static void SM4encrypt(String filePath,String key) throws IOException { String cmd = "openssl sm4 -in " + filePath + " -out " + filePath + ".en -K " + key + " -iv " + key; RunCmd.run(cmd); } public static void SM4decrypt(String filePath,String key) throws IOException { String cmd = "openssl sm4 -d -in " + filePath + ".en -out " + filePath + " -K " + key + " -iv " + key; RunCmd.run(cmd); }
rand16
public static String rand16() throws IOException {
//生成16位元組的隨機數
String cmd = "openssl rand -hex 16";
String result = RunCmd.run(cmd);
return result;
}
由程式碼我們可以看出使用的是openssl命令列指令對資料進行加密解密。通過建立cmd變數儲存待加密的檔案路徑和金鑰,然後傳入RunCmd類中的run方法進行執行。
dao.UserDao
我們通過看專案dao層的程式碼來看使用者的口令保護程式
註冊使用者
可以看到使用者在頁面進行互動後傳入的密碼要先通過Openssl中的SM3方法之後再被放入sql字串中進行insert。
然後通過PreparedStatement類的setString方法進行傳入引數,其中每個使用者自己的對稱金鑰通過Openssl中的rand16方法進行生成
引數值與資料庫對應關係如下:
使用者登入
可以看到使用者在登入的時候會首先通過select語句進行尋找使用者名稱,找到使用者名稱之後通過使用者名稱尋找其id、name、password、level,隨後通過if判斷密碼摘要值來決定使用者身份。
上傳公文controller.UploadServlet
我們在controller層的UploadServlet類中新增加密傳輸程式碼
加密核心程式碼
//使用使用者的對稱金鑰對檔案加密
Openssl.SM4encrypt(path+filePath, u.getEncrykey());
//刪除明文
Openssl.deletePlain(path+filePath);
上傳公文 UploadServlet(xjr發給tsx)
定義儲存路徑
path為伺服器儲存的公文地址
獲取上傳檔名
- 首先通過req.getPart方法獲取檔案存入part物件中
Part part = req.getPart("file");
- 隨後定義disposition變數獲取檔案的路徑及名字
String disposition = part.getHeader("Content-Disposition");
- 使用substring方法獲取路徑中最後的那個檔名,如:*.txt
String realFileName = disposition.substring(disposition.lastIndexOf("=\"") + 2, disposition.length()-1);
- 隨後使用InputStream類定義一個物件is並用getInputStream方法獲取part中檔案的資料流
InputStream is = part.getInputStream();
- 動態獲取伺服器路徑
此處使用了UUID.randomUUID().toString方法。
String filePath = String.format("/%s/%s", UUID.randomUUID().toString(), realFileName);
我們嘗試用System.out.println輸出filePath看看如下:
此處我上傳了一個1.txt,前面路徑是伺服器當前的路徑
- 獲取檔案
使用Path類定義一個file變數,並使用get方法獲取檔案
Path file = Paths.get(path, filePath);
- 輸出檔案流
使用FileOutputStream類建立物件fos進行輸出檔案流
FileOutputStream fos = new FileOutputStream(file.toFile());
byte[] bty = new byte[1024];
int length =0;
while((length=is.read(bty))!=-1){
fos.write(bty,0,length);
}
- 檔案加密
此處使用了Openssl.SM4encrypt方法對檔案進行加密,注意:此處加密檔案路徑為path+filePath,即/home/xjr/桌面/Project2/file/伺服器動態路徑/filename
Openssl.SM4encrypt(path+filePath, u.getEncrykey());
對照剛剛的System.out.println輸出的filePath結果我們看看是否生成對應檔案目錄
可以發現已經成功!
下載公文controller.DownServlet
解密核心程式碼
Openssl.SM4decrypt(path,key);
下載公文過程
- 獲取客戶端需要下載的檔名
此處建立了一個file字串存取資料庫動態地址+檔名
String file = request.getParameter("file");
我們可以使用System.out.println(file);
對其驗證:
- 獲取檔案絕對地址
定義一個path字串,儲存專案路徑+伺服器動態路徑+檔名
String path = UploadServlet.path+"/"+file; //預設認為檔案在當前專案的根目錄
- 獲取傳送者資訊
定義字串sender儲存傳送者名字,並使用documentService類中的findDocumentByPath和getSendUser方法進行查詢傳送者名字。
String sender = documentService.findDocumentByPath(file).getSendUser();
- 獲取解密金鑰
由於使用的是SM4演算法,此演算法為一個對稱密碼演算法,故需要將獲取傳送方的金鑰。
這裡使用了userService類中的getEncrykey方法;
key = userService.findUserByName(sender).getEncrykey();
這裡我們用xjr使用者給tsx使用者傳送公文,隨後tsx下載公文為例,用System.out.println(key);
檢視key值
- 解密
此處使用了Openssl.SM4decrypt方法進行解密
Openssl.SM4decrypt(path,key);
將目標檔案解密後得到: