一、设计思路
为了避免其他人通过文件资源管理器查看自己存储的文档,我们设计出一个文档加密管理系统,通过加密算法将源文件替换成加密后的乱码,若想将乱码恢复成原文件则需输入密钥,只有密钥正确才能看到源文件。
二、项目结构
主页面如下图。查看按钮能直接打开文件看到内容,加密按钮能把文件变成加密文件放在加密文件夹中,解密按钮能把加密过的文件解密放在解密文件夹中。
三、代码
1.登陆界面
每个用户输入自己的用户名和密码以登录主界面
import javax.swing.*;
public class LoginUI extends JFrame {//登陆界面
Listener listener = new Listener();
JTextField nameField = new JTextField();
JTextField passWordField = new JTextField();
public void showUI(){//设置两个文本框和按钮,并添加监听器
setTitle("登陆界面");
setSize(300, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
JLabel nameLabel = new JLabel("用户名");
nameLabel.setBounds(10,50,50,30);
add(nameLabel);
JLabel passwordLabel = new JLabel("密码");
passwordLabel.setBounds(10,150,50,30);
add(passwordLabel);
nameField.setBounds(70,50,200,30);
add(nameField);
passWordField.setBounds(70,150,200,30);
add(passWordField);
JButton loginButton = new JButton("登录");
loginButton.setBounds(70,250,150,50);
add(loginButton);
loginButton.addActionListener(listener);
listener.loginUI = this;
setVisible(true);
}
public static void main(String[] args) {
LoginUI loginUI = new LoginUI();
loginUI.showUI();
}
}
2.文档界面
import javax.swing.*;
import java.awt.*;
import java.io.File;
public class DocUI extends JFrame {
public Listener listener;
public String name;
String path = "Data/MultiSecureDoc/UsersData/";//用户文件的根目录
public void showUI(){
setTitle(name + "的个人主页");
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// 用户的个人文件
File file = new File(path + "/" + name+"/LocalFiles");
File[] files = file.listFiles();
String[] fileNames = new String[files.length];
for (int i = 0; i < fileNames.length; i++) {
fileNames[i] = files[i].getName();
}
//用于放功能按钮的面板
JPanel buttonPanel = new JPanel();
this.add(buttonPanel, BorderLayout.SOUTH);
buttonPanel.setPreferredSize(new Dimension(0, 100));
buttonPanel.setBackground(Color.BLUE);
//用于放文件列表的面板
JPanel listPanel = new JPanel();
this.add(listPanel, BorderLayout.NORTH);
listPanel.setPreferredSize(new Dimension(0, 700));
buttonPanel.setBackground(Color.GREEN);
//把文件在面板上列出
JList<String> fileNameList = new JList<>(fileNames);
JScrollPane jScrollPane = new JScrollPane(fileNameList);
jScrollPane.setPreferredSize(new Dimension(500,500));
listPanel.add(jScrollPane);
fileNameList.addListSelectionListener(listener);
JButton lookButton = new JButton("查看");//用于打开本地文件
JButton encryptButton = new JButton("加密");//用于加密文件
JButton decryptButton = new JButton(("解密"));//用于进入解密界面
buttonPanel.add(decryptButton);
buttonPanel.add(lookButton);
buttonPanel.add(encryptButton);
lookButton.addActionListener(listener);
encryptButton.addActionListener(listener);
decryptButton.addActionListener((listener));
setVisible(true);
}
}
3.解密界面
点击解密会进入到此界面
import javax.swing.*;
import java.awt.*;
import java.io.File;
public class UnlockingUI extends JFrame {
Listener listener;
String name;
public void showUI() {//与DocUI类似,将所有加密文件列出,选择文件解密
setTitle(name + "的加密文件");
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
File file = new File("Data/MultiSecureDoc/UsersData"+ "/" + name+"/EncryptedFiles");// 用户的个人文件
File[] files = file.listFiles();
String[] fileNames = new String[files.length];
for (int i = 0; i < fileNames.length; i++) {
fileNames[i] = files[i].getName();
}
JPanel buttonPanel = new JPanel();
this.add(buttonPanel, BorderLayout.SOUTH);
buttonPanel.setPreferredSize(new Dimension(0, 100));
buttonPanel.setBackground(Color.BLUE);
JPanel listPanel = new JPanel();
this.add(listPanel, BorderLayout.NORTH);
listPanel.setPreferredSize(new Dimension(0, 700));
buttonPanel.setBackground(Color.GREEN);
JList<String> fileNameList = new JList<>(fileNames);
JScrollPane jScrollPane = new JScrollPane(fileNameList);
jScrollPane.setPreferredSize(new Dimension(500,500));
listPanel.add(jScrollPane);
fileNameList.addListSelectionListener(listener);
JButton decryptButton = new JButton(("选中文件后点此解密"));
buttonPanel.add(decryptButton);
decryptButton.addActionListener((listener));
setVisible(true);
}
}
4.密钥界面
输入密钥,解密文件
import javax.swing.*;
public class KeyUI extends JFrame {
public Listener listener;
public String key;
JTextField keyField = new JTextField();
public void showUI(){//输入密钥的界面
setTitle("登陆界面");
setSize(300, 300);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(null);
keyField.setBounds(50,50,200,50);
JButton keyButton = new JButton("确定");
keyButton.setBounds(100,200,100,50);
keyButton.addActionListener(listener);
add(keyButton);
add(keyField);
setVisible(true);
}
}
5.监听器
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.event.*;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class Listener implements ActionListener, MouseListener, ListSelectionListener {
public LoginUI loginUI;
public DocUI docUI = new DocUI();
public KeyUI keyUI = new KeyUI();
public UnlockingUI unlockingUI = new UnlockingUI();
public File encryptedFile;
public File localFile;
String secretKey = "1234567812345678";//为演示而设置的密钥,实际应用不应直接出现在程序中
public String name;
String selectedFileName;
@Override
public void actionPerformed(ActionEvent e) {
//监听器传参
unlockingUI.listener = this;
docUI.listener = this;
keyUI.listener = this;
if (e.getActionCommand().equals("登录")) {//点击登录若密码与用户名相匹配则进入文档界面
try {
FileInputStream inputStream = new FileInputStream("Data/MultiSecureDoc/UsersInfo.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
int name_start = line.indexOf("username:") + "username:".length();
int name_end = line.indexOf("password:");
int password_start = name_end + "password:".length();
String name = line.substring(name_start, name_end).trim();
String password = line.substring(password_start);
if (loginUI.nameField.getText().equals(name) && loginUI.passWordField.getText().equals(password)) {
this.name = loginUI.nameField.getText();
unlockingUI.name = this.name;
docUI.name = this.name;
docUI.showUI();
return;
}
}
JOptionPane.showMessageDialog(null, "用户名或密码错误");
} catch (IOException ex) {
throw new RuntimeException(ex);
}
} else if (e.getActionCommand().equals("解密")) {
unlockingUI.showUI();
} else if (e.getActionCommand().equals("选中文件后点此解密")) {
keyUI.showUI();
}
else if(e.getActionCommand().equals("确定")){
keyUI.key = keyUI.keyField.getText();
if (keyUI.key.equals(secretKey)) {
File decryptedFile = new File("Data/MultiSecureDoc/UsersData/"+name+"/DecryptedFiles/" + selectedFileName);
try {
decryptFile(encryptedFile.getPath(), decryptedFile.getPath(), secretKey, "AES");
JOptionPane.showMessageDialog(null,"解密成功!");
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException |
IOException | IllegalBlockSizeException | BadPaddingException runTime_e) {
runTime_e.printStackTrace();
}
}
else{
JOptionPane.showMessageDialog(null,"密码错误!");
}
}
else if (e.getActionCommand().equals("加密")) {
encryptedFile = new File("Data/MultiSecureDoc/UsersData/"+name+"/EncryptedFiles/" + selectedFileName);
localFile = new File("Data/MultiSecureDoc/UsersData/"+name+"/LocalFiles/" + selectedFileName);
try {
//加密
encryptFile(localFile.getPath(), encryptedFile.getPath(), secretKey, "AES");
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | IOException |
IllegalBlockSizeException | BadPaddingException ex) {
throw new RuntimeException(ex);
}
JOptionPane.showMessageDialog(null,"加密成功!");
} else if (e.getActionCommand().equals("查看")) {
try {
Runtime.getRuntime().exec("notepad " + "Data/MultiSecureDoc/UsersData/"+name+"/LocalFiles/"+ selectedFileName);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
private void encryptFile(String inputFile, String outputFile, String secretKey, String algorithm)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
IOException, IllegalBlockSizeException, BadPaddingException {
// 读取文件内容到inputBytes中
FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int) inputFile.length()];
inputStream.read(inputBytes);
inputStream.close();
// 创建加密器
Cipher cipher = Cipher.getInstance(algorithm);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), algorithm);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
// 对文件内容进行加密
byte[] outputBytes = cipher.doFinal(inputBytes);
// 将加密后的内容写入到输出文件
FileOutputStream outputStream = new FileOutputStream(outputFile);
outputStream.write(outputBytes);
outputStream.close();
}
private void decryptFile(String inputFile, String outputFile, String secretKey, String algorithm)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
IOException, IllegalBlockSizeException, BadPaddingException {
// 读取加密文件内容
FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int) new File(inputFile).length()];
inputStream.read(inputBytes);
inputStream.close();
// 创建AES解密器
Cipher cipher = Cipher.getInstance(algorithm);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
// 对加密文件内容进行解密
byte[] outputBytes = cipher.doFinal(inputBytes);
// 将解密后的内容写入到输出文件
FileOutputStream outputStream = new FileOutputStream(outputFile);
outputStream.write(outputBytes);
outputStream.close();
}
@Override
public void valueChanged(ListSelectionEvent e) {
JList<String> jList = (JList<String>) e.getSource();
selectedFileName = jList.getSelectedValue();
}
}
四、演示
代码中的文件夹结构如下
UserInfo.txt存放用户名和密码(用户不可见)
本地文档,加密后可删除
加密文档
解密文档