电子公文系统

个人贡献值

本人对于此项目的贡献是文件传输和用户口令的保护,及负责整个系统密码安全

实践过程

首先创建数据库连接用户名密码

进入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);

将目标文件解密后得到:

posted @ 2022-12-11 17:44  20201325my  阅读(209)  评论(0编辑  收藏  举报