使用Java开发简易密码管理器,核心目标是安全存储用户的各类账号密码,避免明文存储带来的泄露风险,同时提供简单的操作入口让用户可以管理自己的密码数据。整个实现过程会围绕加密、存储、交互三个核心模块展开,最终得到一个可以本地运行的命令行版本密码管理工具。

功能设计与核心依赖
简易密码管理器的核心功能包含四个部分:添加密码记录、查询密码记录、删除密码记录、退出程序。为了实现安全存储,需要使用AES对称加密算法对密码原文进行加密,加密密钥由用户自定义的主管密码生成。整个项目不需要额外引入第三方依赖,使用Java标准库即可完成所有功能。
核心依赖的Java类包含以下几个:
javax.crypto.Cipher:用于AES算法的加密解密操作javax.crypto.spec.SecretKeySpec:生成AES加密所需的密钥对象java.io.FileReader和java.io.FileWriter:用于本地文件的读写操作java.util.Scanner:用于处理用户的命令行输入java.util.ArrayList:用于存储内存中的密码记录列表
AES加密工具类实现
首先封装一个加密工具类,负责将用户的主密码转换为AES密钥,同时提供加密和解密的方法。这里使用AES算法的ECB模式,填充方式为PKCS5Padding,密钥长度固定为128位。
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class AESUtil {
// 加密算法名称
private static final String ALGORITHM = "AES";
// 将用户主密码转换为128位AES密钥
private static SecretKeySpec getSecretKey(String masterPassword) {
// 将主密码转为字节数组,截取前16字节作为密钥,不足则补0
byte[] passwordBytes = masterPassword.getBytes(StandardCharsets.UTF_8);
byte[] keyBytes = new byte[16];
for (int i = 0; i < passwordBytes.length && i < 16; i++) {
keyBytes[i] = passwordBytes[i];
}
return new SecretKeySpec(keyBytes, ALGORITHM);
}
// 加密方法,传入明文和主密码,返回Base64编码的密文
public static String encrypt(String plaintext, String masterPassword) throws Exception {
SecretKeySpec key = getSecretKey(masterPassword);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
// 解密方法,传入密文和主密码,返回明文
public static String decrypt(String ciphertext, String masterPassword) throws Exception {
SecretKeySpec key = getSecretKey(masterPassword);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decodedBytes = Base64.getDecoder().decode(ciphertext);
byte[] decryptedBytes = cipher.doFinal(decodedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
}密码记录实体类
定义一个密码记录的实体类,用来存储单条密码的相关信息,包含平台名称、账号、加密后的密码三个属性,同时提供序列化和反序列化的方法,方便将对象转换为字符串存储到文件,或者从文件字符串恢复对象。
public class PasswordRecord {
// 平台名称,比如微信、淘宝
private String platform;
// 对应账号
private String account;
// 加密后的密码
private String encryptedPassword;
public PasswordRecord(String platform, String account, String encryptedPassword) {
this.platform = platform;
this.account = account;
this.encryptedPassword = encryptedPassword;
}
// 将记录转为存储格式的字符串,用|分隔各个字段
public String toStorageString() {
return platform + "|" + account + "|" + encryptedPassword;
}
// 从存储字符串恢复记录对象
public static PasswordRecord fromStorageString(String storageStr) {
String[] parts = storageStr.split("\\|");
if (parts.length != 3) {
return null;
}
return new PasswordRecord(parts[0], parts[1], parts[2]);
}
// getter方法
public String getPlatform() {
return platform;
}
public String getAccount() {
return account;
}
public String getEncryptedPassword() {
return encryptedPassword;
}
}数据存储管理类
数据存储管理类负责将内存中的密码记录列表持久化到本地文件,以及从本地文件加载数据到内存。这里使用固定的本地文件路径password_data.txt,存储的是每条记录的序列化字符串,每行对应一条记录。
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class DataStorageManager {
// 存储文件的路径
private static final String FILE_PATH = "password_data.txt";
// 将密码记录列表保存到文件
public static void saveRecords(List<PasswordRecord> records) throws IOException {
try (FileWriter writer = new FileWriter(FILE_PATH, StandardCharsets.UTF_8)) {
for (PasswordRecord record : records) {
writer.write(record.toStorageString());
writer.write("\n");
}
}
}
// 从文件加载密码记录列表
public static List<PasswordRecord> loadRecords() throws IOException {
List<PasswordRecord> records = new ArrayList<>();
File file = new File(FILE_PATH);
if (!file.exists()) {
return records;
}
try (BufferedReader reader = new BufferedReader(new FileReader(file, StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
if (!line.trim().isEmpty()) {
PasswordRecord record = PasswordRecord.fromStorageString(line);
if (record != null) {
records.add(record);
}
}
}
}
return records;
}
}主程序交互逻辑
主程序负责处理用户的命令行输入,实现菜单展示、功能分发、用户交互的完整流程。用户启动程序后首先要输入主管密码,之后会展示功能菜单,用户选择对应功能后执行对应的操作。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class PasswordManagerMain {
private static List<PasswordRecord> records = new ArrayList<>();
private static String masterPassword = null;
private static final Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("欢迎使用简易Java密码管理器");
// 输入主管密码
System.out.print("请输入主管密码:");
masterPassword = scanner.nextLine();
// 加载本地存储的密码记录
try {
records = DataStorageManager.loadRecords();
System.out.println("成功加载" + records.size() + "条密码记录");
} catch (Exception e) {
System.out.println("加载本地数据失败,将创建新的数据文件");
}
// 展示功能菜单
while (true) {
showMenu();
System.out.print("请输入操作编号:");
String choice = scanner.nextLine();
switch (choice) {
case "1":
addPasswordRecord();
break;
case "2":
queryPasswordRecord();
break;
case "3":
deletePasswordRecord();
break;
case "4":
saveAndExit();
return;
default:
System.out.println("无效的操作编号,请重新输入");
}
}
}
// 展示功能菜单
private static void showMenu() {
System.out.println("\n====== 密码管理器功能菜单 ======");
System.out.println("1. 添加密码记录");
System.out.println("2. 查询密码记录");
System.out.println("3. 删除密码记录");
System.out.println("4. 保存并退出");
System.out.println("==============================");
}
// 添加密码记录
private static void addPasswordRecord() {
try {
System.out.print("请输入平台名称:");
String platform = scanner.nextLine();
System.out.print("请输入账号:");
String account = scanner.nextLine();
System.out.print("请输入密码:");
String password = scanner.nextLine();
// 加密密码
String encryptedPassword = AESUtil.encrypt(password, masterPassword);
PasswordRecord record = new PasswordRecord(platform, account, encryptedPassword);
records.add(record);
System.out.println("密码记录添加成功");
} catch (Exception e) {
System.out.println("添加密码记录失败:" + e.getMessage());
}
}
// 查询密码记录
private static void queryPasswordRecord() {
if (records.isEmpty()) {
System.out.println("当前没有存储任何密码记录");
return;
}
System.out.println("\n====== 所有密码记录 ======");
for (int i = 0; i < records.size(); i++) {
PasswordRecord record = records.get(i);
System.out.println("序号:" + (i + 1));
System.out.println("平台:" + record.getPlatform());
System.out.println("账号:" + record.getAccount());
try {
String decryptedPassword = AESUtil.decrypt(record.getEncryptedPassword(), masterPassword);
System.out.println("密码:" + decryptedPassword);
} catch (Exception e) {
System.out.println("密码解密失败,主管密码可能错误");
}
System.out.println("--------------------------");
}
}
// 删除密码记录
private static void deletePasswordRecord() {
if (records.isEmpty()) {
System.out.println("当前没有存储任何密码记录,无法删除");
return;
}
queryPasswordRecord();
System.out.print("请输入要删除的记录序号:");
try {
int index = Integer.parseInt(scanner.nextLine()) - 1;
if (index >= 0 && index < records.size()) {
records.remove(index);
System.out.println("密码记录删除成功");
} else {
System.out.println("无效的序号");
}
} catch (NumberFormatException e) {
System.out.println("请输入有效的数字序号");
}
}
// 保存数据并退出
private static void saveAndExit() {
try {
DataStorageManager.saveRecords(records);
System.out.println("数据保存成功,程序退出");
} catch (Exception e) {
System.out.println("数据保存失败:" + e.getMessage());
}
}
}运行与测试说明
将以上四个类的代码放到同一个Java项目下,编译后运行PasswordManagerMain类即可启动程序。首次运行时本地没有数据文件,会提示加载0条记录,用户可以选择添加密码记录,输入对应的平台、账号、密码后,数据会被加密存储到本地文件。之后再次启动程序,输入相同的主管密码就可以查询到之前保存的密码记录。
需要注意主管密码的重要性,一旦主管密码遗忘,所有加密存储的密码都无法解密恢复,因此要妥善保管主管密码。这个简易版本没有做主管密码的校验逻辑,实际使用中可以根据需求增加主管密码二次确认或者密码强度校验的功能。