Project Overview
A secure, locally-stored password manager built with Java that encrypts all sensitive data using industry-standard cryptographic algorithms. Features master password protection, strong encryption, and secure password generation.
Technology Stack
- Core: Java 17+
- Encryption: JCA (Java Cryptography Architecture)
- Key Derivation: PBKDF2WithHmacSHA256
- Encryption Algorithm: AES-256-GCM
- Database: SQLite with encrypted fields
- UI: Java Swing (optional web interface)
- Password Generation: SecureRandom
- Serialization: JSON with encryption
Security Architecture
User Input → Master Password → Key Derivation (PBKDF2) → Encryption Key ↓ Sensitive Data → AES-256-GCM Encryption → Encrypted Data → Secure Storage ↓ Encrypted Data → AES-256-GCM Decryption → Decrypted Data (only in memory)
Project Structure
password-manager/ ├── src/main/java/com/passwordmanager/ │ ├── crypto/ │ ├── model/ │ ├── dao/ │ ├── service/ │ ├── ui/ │ └── exception/ ├── src/main/resources/ │ └── config/ └── data/ └── passwords.db
Core Implementation
1. Encryption Service
package com.passwordmanager.crypto; import javax.crypto.*; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.security.*; import java.security.spec.KeySpec; import java.util.Base64; public class EncryptionService { private static final String ALGORITHM = "AES/GCM/NoPadding"; private static final int KEY_LENGTH = 256; private static final int IV_LENGTH = 12; // 96 bits for GCM private static final int TAG_LENGTH = 128; // bits private static final int ITERATIONS = 100000; private final SecureRandom secureRandom; public EncryptionService() { this.secureRandom = new SecureRandom(); } public String generateSalt() { byte[] salt = new byte[16]; secureRandom.nextBytes(salt); return Base64.getEncoder().encodeToString(salt); } public SecretKey deriveKey(String masterPassword, String salt) throws Exception { byte[] saltBytes = Base64.getDecoder().decode(salt); KeySpec spec = new PBEKeySpec( masterPassword.toCharArray(), saltBytes, ITERATIONS, KEY_LENGTH ); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); byte[] keyBytes = factory.generateSecret(spec).getEncoded(); return new SecretKeySpec(keyBytes, "AES"); } public String generateIV() { byte[] iv = new byte[IV_LENGTH]; secureRandom.nextBytes(iv); return Base64.getEncoder().encodeToString(iv); } public String encrypt(String plaintext, SecretKey key, String ivBase64) throws Exception { byte[] iv = Base64.getDecoder().decode(ivBase64); Cipher cipher = Cipher.getInstance(ALGORITHM); GCMParameterSpec parameterSpec = new GCMParameterSpec(TAG_LENGTH, iv); cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec); byte[] ciphertext = cipher.doFinal(plaintext.getBytes("UTF-8")); return Base64.getEncoder().encodeToString(ciphertext); } public String decrypt(String ciphertext, SecretKey key, String ivBase64) throws Exception { byte[] iv = Base64.getDecoder().decode(ivBase64); byte[] encryptedData = Base64.getDecoder().decode(ciphertext); Cipher cipher = Cipher.getInstance(ALGORITHM); GCMParameterSpec parameterSpec = new GCMParameterSpec(TAG_LENGTH, iv); cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec); byte[] plaintext = cipher.doFinal(encryptedData); return new String(plaintext, "UTF-8"); } public boolean verifyMasterPassword(String enteredPassword, String storedSalt, String storedVerifier) throws Exception { SecretKey testKey = deriveKey(enteredPassword, storedSalt); String testVerifier = encrypt("VERIFICATION", testKey, generateIV()); return storedVerifier.equals(testVerifier); } } 2. Password Generator
package com.passwordmanager.service; import java.security.SecureRandom; import java.util.*; public class PasswordGenerator { private static final String UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static final String LOWERCASE = "abcdefghijklmnopqrstuvwxyz"; private static final String DIGITS = "0123456789"; private static final String SPECIAL = "!@#$%^&*()_+-=[]{}|;:,.<>?"; private final SecureRandom random; public PasswordGenerator() { this.random = new SecureRandom(); } public String generatePassword(int length, boolean includeUppercase, boolean includeLowercase, boolean includeDigits, boolean includeSpecial) { if (length < 8) { throw new IllegalArgumentException("Password length must be at least 8 characters"); } StringBuilder characterPool = new StringBuilder(); if (includeUppercase) characterPool.append(UPPERCASE); if (includeLowercase) characterPool.append(LOWERCASE); if (includeDigits) characterPool.append(DIGITS); if (includeSpecial) characterPool.append(SPECIAL); if (characterPool.length() == 0) { throw new IllegalArgumentException("At least one character type must be selected"); } StringBuilder password = new StringBuilder(); // Ensure at least one character from each selected type if (includeUppercase) { password.append(getRandomChar(UPPERCASE)); } if (includeLowercase) { password.append(getRandomChar(LOWERCASE)); } if (includeDigits) { password.append(getRandomChar(DIGITS)); } if (includeSpecial) { password.append(getRandomChar(SPECIAL)); } // Fill remaining length with random characters from the pool while (password.length() < length) { password.append(getRandomChar(characterPool.toString())); } // Shuffle the password to randomize character positions return shuffleString(password.toString()); } public String generatePassphrase(int wordCount, String separator) { List<String> wordList = Arrays.asList( "apple", "brave", "cloud", "dragon", "eagle", "flame", "globe", "heart", "island", "jewel", "knight", "light", "mountain", "night", "ocean", "planet", "queen", "river", "star", "tree", "unity", "valley", "water", "xray", "year", "zenith" ); StringBuilder passphrase = new StringBuilder(); for (int i = 0; i < wordCount; i++) { if (i > 0) { passphrase.append(separator); } passphrase.append(wordList.get(random.nextInt(wordList.size()))); } return passphrase.toString(); } public int calculatePasswordStrength(String password) { int score = 0; // Length score if (password.length() >= 8) score += 1; if (password.length() >= 12) score += 1; if (password.length() >= 16) score += 2; // Character variety score if (password.matches(".*[a-z].*")) score += 1; if (password.matches(".*[A-Z].*")) score += 1; if (password.matches(".*[0-9].*")) score += 1; if (password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':\",./<>?].*")) score += 2; // Entropy calculation int poolSize = 0; if (password.matches(".*[a-z].*")) poolSize += 26; if (password.matches(".*[A-Z].*")) poolSize += 26; if (password.matches(".*[0-9].*")) poolSize += 10; if (password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':\",./<>?].*")) poolSize += 32; if (poolSize > 0) { double entropy = password.length() * (Math.log(poolSize) / Math.log(2)); if (entropy > 80) score += 2; else if (entropy > 60) score += 1; } return Math.min(score, 10); } private char getRandomChar(String characterSet) { return characterSet.charAt(random.nextInt(characterSet.length())); } private String shuffleString(String input) { List<Character> characters = new ArrayList<>(); for (char c : input.toCharArray()) { characters.add(c); } Collections.shuffle(characters, random); StringBuilder result = new StringBuilder(); for (char c : characters) { result.append(c); } return result.toString(); } } 3. Data Models
package com.passwordmanager.model; import java.time.LocalDateTime; public class PasswordEntry { private String id; private String title; private String username; private String encryptedPassword; private String url; private String notes; private String category; private LocalDateTime createdAt; private LocalDateTime updatedAt; private String iv; // Initialization Vector for AES-GCM // Constructors public PasswordEntry() { this.id = java.util.UUID.randomUUID().toString(); this.createdAt = LocalDateTime.now(); this.updatedAt = LocalDateTime.now(); } public PasswordEntry(String title, String username, String url, String category) { this(); this.title = title; this.username = username; this.url = url; this.category = category; } // Getters and Setters public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; this.updatedAt = LocalDateTime.now(); } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; this.updatedAt = LocalDateTime.now(); } public String getEncryptedPassword() { return encryptedPassword; } public void setEncryptedPassword(String encryptedPassword) { this.encryptedPassword = encryptedPassword; this.updatedAt = LocalDateTime.now(); } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; this.updatedAt = LocalDateTime.now(); } public String getNotes() { return notes; } public void setNotes(String notes) { this.notes = notes; this.updatedAt = LocalDateTime.now(); } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; this.updatedAt = LocalDateTime.now(); } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } public String getIv() { return iv; } public void setIv(String iv) { this.iv = iv; } } package com.passwordmanager.model; public class UserProfile { private String id; private String masterPasswordSalt; private String masterPasswordVerifier; private String encryptionKeySalt; private LocalDateTime createdAt; private LocalDateTime lastLogin; // Constructors public UserProfile() { this.id = java.util.UUID.randomUUID().toString(); this.createdAt = LocalDateTime.now(); } // Getters and Setters public String getId() { return id; } public void setId(String id) { this.id = id; } public String getMasterPasswordSalt() { return masterPasswordSalt; } public void setMasterPasswordSalt(String masterPasswordSalt) { this.masterPasswordSalt = masterPasswordSalt; } public String getMasterPasswordVerifier() { return masterPasswordVerifier; } public void setMasterPasswordVerifier(String masterPasswordVerifier) { this.masterPasswordVerifier = masterPasswordVerifier; } public String getEncryptionKeySalt() { return encryptionKeySalt; } public void setEncryptionKeySalt(String encryptionKeySalt) { this.encryptionKeySalt = encryptionKeySalt; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getLastLogin() { return lastLogin; } public void setLastLogin(LocalDateTime lastLogin) { this.lastLogin = lastLogin; } } 4. Database Layer
package com.passwordmanager.dao; import com.passwordmanager.model.PasswordEntry; import com.passwordmanager.model.UserProfile; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class DatabaseManager { private static final String DB_URL = "jdbc:sqlite:data/passwords.db"; static { try { Class.forName("org.sqlite.JDBC"); initializeDatabase(); } catch (ClassNotFoundException e) { throw new RuntimeException("SQLite JDBC driver not found", e); } } private static void initializeDatabase() { try (Connection conn = DriverManager.getConnection(DB_URL); Statement stmt = conn.createStatement()) { // Create user profile table String createUserTable = """ CREATE TABLE IF NOT EXISTS user_profile ( id TEXT PRIMARY KEY, master_password_salt TEXT NOT NULL, master_password_verifier TEXT NOT NULL, encryption_key_salt TEXT NOT NULL, created_at TEXT NOT NULL, last_login TEXT ) """; // Create password entries table String createPasswordsTable = """ CREATE TABLE IF NOT EXISTS password_entries ( id TEXT PRIMARY KEY, title TEXT NOT NULL, username TEXT, encrypted_password TEXT NOT NULL, url TEXT, notes TEXT, category TEXT, iv TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ) """; stmt.execute(createUserTable); stmt.execute(createPasswordsTable); } catch (SQLException e) { throw new RuntimeException("Failed to initialize database", e); } } public Connection getConnection() throws SQLException { return DriverManager.getConnection(DB_URL); } // User Profile operations public void saveUserProfile(UserProfile profile) throws SQLException { String sql = """ INSERT OR REPLACE INTO user_profile (id, master_password_salt, master_password_verifier, encryption_key_salt, created_at, last_login) VALUES (?, ?, ?, ?, ?, ?) """; try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, profile.getId()); pstmt.setString(2, profile.getMasterPasswordSalt()); pstmt.setString(3, profile.getMasterPasswordVerifier()); pstmt.setString(4, profile.getEncryptionKeySalt()); pstmt.setString(5, profile.getCreatedAt().toString()); pstmt.setString(6, profile.getLastLogin() != null ? profile.getLastLogin().toString() : null); pstmt.executeUpdate(); } } public Optional<UserProfile> getUserProfile() throws SQLException { String sql = "SELECT * FROM user_profile LIMIT 1"; try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery()) { if (rs.next()) { UserProfile profile = new UserProfile(); profile.setId(rs.getString("id")); profile.setMasterPasswordSalt(rs.getString("master_password_salt")); profile.setMasterPasswordVerifier(rs.getString("master_password_verifier")); profile.setEncryptionKeySalt(rs.getString("encryption_key_salt")); profile.setCreatedAt(java.time.LocalDateTime.parse(rs.getString("created_at"))); String lastLogin = rs.getString("last_login"); if (lastLogin != null) { profile.setLastLogin(java.time.LocalDateTime.parse(lastLogin)); } return Optional.of(profile); } return Optional.empty(); } } // Password Entry operations public void savePasswordEntry(PasswordEntry entry) throws SQLException { String sql = """ INSERT OR REPLACE INTO password_entries (id, title, username, encrypted_password, url, notes, category, iv, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """; try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, entry.getId()); pstmt.setString(2, entry.getTitle()); pstmt.setString(3, entry.getUsername()); pstmt.setString(4, entry.getEncryptedPassword()); pstmt.setString(5, entry.getUrl()); pstmt.setString(6, entry.getNotes()); pstmt.setString(7, entry.getCategory()); pstmt.setString(8, entry.getIv()); pstmt.setString(9, entry.getCreatedAt().toString()); pstmt.setString(10, entry.getUpdatedAt().toString()); pstmt.executeUpdate(); } } public List<PasswordEntry> getAllPasswordEntries() throws SQLException { String sql = "SELECT * FROM password_entries ORDER BY title"; List<PasswordEntry> entries = new ArrayList<>(); try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery()) { while (rs.next()) { PasswordEntry entry = new PasswordEntry(); entry.setId(rs.getString("id")); entry.setTitle(rs.getString("title")); entry.setUsername(rs.getString("username")); entry.setEncryptedPassword(rs.getString("encrypted_password")); entry.setUrl(rs.getString("url")); entry.setNotes(rs.getString("notes")); entry.setCategory(rs.getString("category")); entry.setIv(rs.getString("iv")); entry.setCreatedAt(java.time.LocalDateTime.parse(rs.getString("created_at"))); entry.setUpdatedAt(java.time.LocalDateTime.parse(rs.getString("updated_at"))); entries.add(entry); } } return entries; } public void deletePasswordEntry(String id) throws SQLException { String sql = "DELETE FROM password_entries WHERE id = ?"; try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, id); pstmt.executeUpdate(); } } public List<PasswordEntry> searchPasswordEntries(String query) throws SQLException { String sql = """ SELECT * FROM password_entries WHERE title LIKE ? OR username LIKE ? OR url LIKE ? OR category LIKE ? ORDER BY title """; List<PasswordEntry> entries = new ArrayList<>(); String searchPattern = "%" + query + "%"; try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, searchPattern); pstmt.setString(2, searchPattern); pstmt.setString(3, searchPattern); pstmt.setString(4, searchPattern); try (ResultSet rs = pstmt.executeQuery()) { while (rs.next()) { PasswordEntry entry = new PasswordEntry(); entry.setId(rs.getString("id")); entry.setTitle(rs.getString("title")); entry.setUsername(rs.getString("username")); entry.setEncryptedPassword(rs.getString("encrypted_password")); entry.setUrl(rs.getString("url")); entry.setNotes(rs.getString("notes")); entry.setCategory(rs.getString("category")); entry.setIv(rs.getString("iv")); entry.setCreatedAt(java.time.LocalDateTime.parse(rs.getString("created_at"))); entry.setUpdatedAt(java.time.LocalDateTime.parse(rs.getString("updated_at"))); entries.add(entry); } } } return entries; } } 5. Core Service Layer
package com.passwordmanager.service; import com.passwordmanager.crypto.EncryptionService; import com.passwordmanager.dao.DatabaseManager; import com.passwordmanager.model.PasswordEntry; import com.passwordmanager.model.UserProfile; import javax.crypto.SecretKey; import java.util.List; import java.util.Optional; public class PasswordManagerService { private final EncryptionService encryptionService; private final DatabaseManager databaseManager; private final PasswordGenerator passwordGenerator; private SecretKey currentUserKey; private UserProfile currentUser; public PasswordManagerService() { this.encryptionService = new EncryptionService(); this.databaseManager = new DatabaseManager(); this.passwordGenerator = new PasswordGenerator(); } public boolean isFirstTimeSetup() { try { Optional<UserProfile> profile = databaseManager.getUserProfile(); return profile.isEmpty(); } catch (Exception e) { return true; } } public void initializeUserProfile(String masterPassword) throws Exception { if (!isFirstTimeSetup()) { throw new IllegalStateException("User profile already exists"); } UserProfile profile = new UserProfile(); // Generate salts String masterPasswordSalt = encryptionService.generateSalt(); String encryptionKeySalt = encryptionService.generateSalt(); // Derive master key and create verifier SecretKey masterKey = encryptionService.deriveKey(masterPassword, masterPasswordSalt); String verifier = encryptionService.encrypt("VERIFICATION", masterKey, encryptionService.generateIV()); profile.setMasterPasswordSalt(masterPasswordSalt); profile.setMasterPasswordVerifier(verifier); profile.setEncryptionKeySalt(encryptionKeySalt); databaseManager.saveUserProfile(profile); this.currentUser = profile; this.currentUserKey = masterKey; } public boolean authenticateUser(String masterPassword) throws Exception { Optional<UserProfile> profile = databaseManager.getUserProfile(); if (profile.isEmpty()) { return false; } UserProfile userProfile = profile.get(); boolean authenticated = encryptionService.verifyMasterPassword( masterPassword, userProfile.getMasterPasswordSalt(), userProfile.getMasterPasswordVerifier() ); if (authenticated) { this.currentUser = userProfile; this.currentUserKey = encryptionService.deriveKey(masterPassword, userProfile.getMasterPasswordSalt()); // Update last login userProfile.setLastLogin(java.time.LocalDateTime.now()); databaseManager.saveUserProfile(userProfile); } return authenticated; } public void addPasswordEntry(String title, String username, String password, String url, String notes, String category) throws Exception { if (currentUserKey == null) { throw new IllegalStateException("User not authenticated"); } PasswordEntry entry = new PasswordEntry(title, username, url, category); entry.setNotes(notes); // Generate IV and encrypt password String iv = encryptionService.generateIV(); String encryptedPassword = encryptionService.encrypt(password, currentUserKey, iv); entry.setEncryptedPassword(encryptedPassword); entry.setIv(iv); databaseManager.savePasswordEntry(entry); } public String getDecryptedPassword(PasswordEntry entry) throws Exception { if (currentUserKey == null) { throw new IllegalStateException("User not authenticated"); } return encryptionService.decrypt(entry.getEncryptedPassword(), currentUserKey, entry.getIv()); } public void updatePasswordEntry(PasswordEntry entry, String newPassword) throws Exception { if (currentUserKey == null) { throw new IllegalStateException("User not authenticated"); } String iv = encryptionService.generateIV(); String encryptedPassword = encryptionService.encrypt(newPassword, currentUserKey, iv); entry.setEncryptedPassword(encryptedPassword); entry.setIv(iv); databaseManager.savePasswordEntry(entry); } public void deletePasswordEntry(String entryId) throws Exception { databaseManager.deletePasswordEntry(entryId); } public List<PasswordEntry> getAllPasswordEntries() throws Exception { return databaseManager.getAllPasswordEntries(); } public List<PasswordEntry> searchPasswordEntries(String query) throws Exception { return databaseManager.searchPasswordEntries(query); } public String generatePassword(int length, boolean includeUppercase, boolean includeLowercase, boolean includeDigits, boolean includeSpecial) { return passwordGenerator.generatePassword(length, includeUppercase, includeLowercase, includeDigits, includeSpecial); } public String generatePassphrase(int wordCount, String separator) { return passwordGenerator.generatePassphrase(wordCount, separator); } public int calculatePasswordStrength(String password) { return passwordGenerator.calculatePasswordStrength(password); } public void lockSession() { this.currentUserKey = null; // Clear any sensitive data from memory System.gc(); } public boolean isAuthenticated() { return currentUserKey != null; } public void changeMasterPassword(String currentPassword, String newPassword) throws Exception { if (!authenticateUser(currentPassword)) { throw new SecurityException("Current password is incorrect"); } // Re-encrypt all passwords with new master key List<PasswordEntry> allEntries = getAllPasswordEntries(); // Generate new salts and derive new key String newMasterPasswordSalt = encryptionService.generateSalt(); String newEncryptionKeySalt = encryptionService.generateSalt(); SecretKey newMasterKey = encryptionService.deriveKey(newPassword, newMasterPasswordSalt); // Update user profile currentUser.setMasterPasswordSalt(newMasterPasswordSalt); currentUser.setEncryptionKeySalt(newEncryptionKeySalt); currentUser.setMasterPasswordVerifier( encryptionService.encrypt("VERIFICATION", newMasterKey, encryptionService.generateIV()) ); // Re-encrypt all passwords for (PasswordEntry entry : allEntries) { String decryptedPassword = getDecryptedPassword(entry); String newIv = encryptionService.generateIV(); String newEncryptedPassword = encryptionService.encrypt(decryptedPassword, newMasterKey, newIv); entry.setEncryptedPassword(newEncryptedPassword); entry.setIv(newIv); databaseManager.savePasswordEntry(entry); } // Update current session databaseManager.saveUserProfile(currentUser); this.currentUserKey = newMasterKey; } } 6. Swing UI Implementation
package com.passwordmanager.ui; import com.passwordmanager.model.PasswordEntry; import com.passwordmanager.service.PasswordManagerService; import javax.swing.*; import javax.swing.table.DefaultTableModel; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; public class PasswordManagerUI { private final PasswordManagerService service; private JFrame mainFrame; private JTable passwordTable; private DefaultTableModel tableModel; public PasswordManagerUI(PasswordManagerService service) { this.service = service; initializeUI(); } private void initializeUI() { mainFrame = new JFrame("Secure Password Manager"); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainFrame.setSize(1000, 700); mainFrame.setLocationRelativeTo(null); if (service.isFirstTimeSetup()) { showFirstTimeSetup(); } else { showLoginScreen(); } } private void showFirstTimeSetup() { JPanel panel = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(10, 10, 10, 10); gbc.fill = GridBagConstraints.HORIZONTAL; JLabel titleLabel = new JLabel("First Time Setup - Create Master Password"); titleLabel.setFont(new Font("Arial", Font.BOLD, 16)); JLabel infoLabel = new JLabel("<html>Your master password encrypts all your stored passwords.<br>Make sure it's strong and memorable - it cannot be recovered!</html>"); JPasswordField masterPasswordField = new JPasswordField(20); JPasswordField confirmPasswordField = new JPasswordField(20); JButton createButton = new JButton("Create Vault"); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 2; panel.add(titleLabel, gbc); gbc.gridy = 1; panel.add(infoLabel, gbc); gbc.gridwidth = 1; gbc.gridy = 2; gbc.gridx = 0; panel.add(new JLabel("Master Password:"), gbc); gbc.gridx = 1; panel.add(masterPasswordField, gbc); gbc.gridy = 3; gbc.gridx = 0; panel.add(new JLabel("Confirm Password:"), gbc); gbc.gridx = 1; panel.add(confirmPasswordField, gbc); gbc.gridy = 4; gbc.gridx = 0; gbc.gridwidth = 2; panel.add(createButton, gbc); createButton.addActionListener(e -> { String password = new String(masterPasswordField.getPassword()); String confirm = new String(confirmPasswordField.getPassword()); if (!password.equals(confirm)) { JOptionPane.showMessageDialog(mainFrame, "Passwords do not match!"); return; } if (password.length() < 8) { JOptionPane.showMessageDialog(mainFrame, "Master password must be at least 8 characters long!"); return; } try { service.initializeUserProfile(password); JOptionPane.showMessageDialog(mainFrame, "Vault created successfully!"); showMainApplication(); } catch (Exception ex) { JOptionPane.showMessageDialog(mainFrame, "Error creating vault: " + ex.getMessage()); } }); mainFrame.setContentPane(panel); mainFrame.setVisible(true); } private void showLoginScreen() { JPanel panel = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(10, 10, 10, 10); gbc.fill = GridBagConstraints.HORIZONTAL; JLabel titleLabel = new JLabel("Secure Password Manager"); titleLabel.setFont(new Font("Arial", Font.BOLD, 16)); JPasswordField passwordField = new JPasswordField(20); JButton loginButton = new JButton("Unlock Vault"); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 2; panel.add(titleLabel, gbc); gbc.gridy = 1; gbc.gridwidth = 1; panel.add(new JLabel("Master Password:"), gbc); gbc.gridx = 1; panel.add(passwordField, gbc); gbc.gridy = 2; gbc.gridx = 0; gbc.gridwidth = 2; panel.add(loginButton, gbc); loginButton.addActionListener(e -> { String password = new String(passwordField.getPassword()); try { if (service.authenticateUser(password)) { showMainApplication(); } else { JOptionPane.showMessageDialog(mainFrame, "Invalid master password!"); } } catch (Exception ex) { JOptionPane.showMessageDialog(mainFrame, "Error during authentication: " + ex.getMessage()); } }); // Enter key to login passwordField.addActionListener(e -> loginButton.doClick()); mainFrame.setContentPane(panel); mainFrame.setVisible(true); } private void showMainApplication() { mainFrame.getContentPane().removeAll(); // Create menu bar JMenuBar menuBar = new JMenuBar(); JMenu fileMenu = new JMenu("File"); JMenuItem lockItem = new JMenuItem("Lock"); JMenuItem exitItem = new JMenuItem("Exit"); lockItem.addActionListener(e -> { service.lockSession(); showLoginScreen(); }); exitItem.addActionListener(e -> System.exit(0)); fileMenu.add(lockItem); fileMenu.addSeparator(); fileMenu.add(exitItem); menuBar.add(fileMenu); JMenu toolsMenu = new JMenu("Tools"); JMenuItem passwordGeneratorItem = new JMenuItem("Password Generator"); JMenuItem changeMasterPasswordItem = new JMenuItem("Change Master Password"); passwordGeneratorItem.addActionListener(e -> showPasswordGenerator()); changeMasterPasswordItem.addActionListener(e -> showChangeMasterPassword()); toolsMenu.add(passwordGeneratorItem); toolsMenu.add(changeMasterPasswordItem); menuBar.add(toolsMenu); mainFrame.setJMenuBar(menuBar); // Create main panel JPanel mainPanel = new JPanel(new BorderLayout()); // Create toolbar JToolBar toolBar = new JToolBar(); JButton addButton = new JButton("Add Password"); JButton editButton = new JButton("Edit"); JButton deleteButton = new JButton("Delete"); JButton viewButton = new JButton("View Password"); JTextField searchField = new JTextField(20); JButton searchButton = new JButton("Search"); toolBar.add(addButton); toolBar.add(editButton); toolBar.add(deleteButton); toolBar.add(viewButton); toolBar.addSeparator(); toolBar.add(new JLabel("Search:")); toolBar.add(searchField); toolBar.add(searchButton); // Create table String[] columnNames = {"Title", "Username", "URL", "Category", "Last Updated"}; tableModel = new DefaultTableModel(columnNames, 0) { @Override public boolean isCellEditable(int row, int column) { return false; } }; passwordTable = new JTable(tableModel); JScrollPane tableScrollPane = new JScrollPane(passwordTable); mainPanel.add(toolBar, BorderLayout.NORTH); mainPanel.add(tableScrollPane, BorderLayout.CENTER); // Load data refreshPasswordTable(); // Add event listeners addButton.addActionListener(e -> showAddPasswordDialog()); editButton.addActionListener(e -> showEditPasswordDialog()); deleteButton.addActionListener(e -> deleteSelectedPassword()); viewButton.addActionListener(e -> showViewPasswordDialog()); searchButton.addActionListener(e -> searchPasswords(searchField.getText())); searchField.addActionListener(e -> searchPasswords(searchField.getText())); mainFrame.setContentPane(mainPanel); mainFrame.revalidate(); mainFrame.repaint(); } private void refreshPasswordTable() { try { tableModel.setRowCount(0); List<PasswordEntry> entries = service.getAllPasswordEntries(); for (PasswordEntry entry : entries) { tableModel.addRow(new Object[]{ entry.getTitle(), entry.getUsername(), entry.getUrl(), entry.getCategory(), entry.getUpdatedAt().toString() }); } } catch (Exception ex) { JOptionPane.showMessageDialog(mainFrame, "Error loading passwords: " + ex.getMessage()); } } private void showAddPasswordDialog() { // Implementation for add password dialog JDialog dialog = new JDialog(mainFrame, "Add New Password", true); dialog.setSize(400, 500); dialog.setLocationRelativeTo(mainFrame); JPanel panel = new JPanel(new GridLayout(0, 2, 10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); JTextField titleField = new JTextField(); JTextField usernameField = new JTextField(); JPasswordField passwordField = new JPasswordField(); JTextField urlField = new JTextField(); JTextArea notesArea = new JTextArea(3, 20); JTextField categoryField = new JTextField(); JButton generateButton = new JButton("Generate"); JButton saveButton = new JButton("Save"); panel.add(new JLabel("Title:")); panel.add(titleField); panel.add(new JLabel("Username:")); panel.add(usernameField); panel.add(new JLabel("Password:")); panel.add(passwordField); panel.add(new JLabel("")); panel.add(generateButton); panel.add(new JLabel("URL:")); panel.add(urlField); panel.add(new JLabel("Category:")); panel.add(categoryField); panel.add(new JLabel("Notes:")); panel.add(new JScrollPane(notesArea)); panel.add(new JLabel("")); panel.add(saveButton); generateButton.addActionListener(e -> showPasswordGeneratorDialog(passwordField)); saveButton.addActionListener(e -> { try { service.addPasswordEntry( titleField.getText(), usernameField.getText(), new String(passwordField.getPassword()), urlField.getText(), notesArea.getText(), categoryField.getText() ); refreshPasswordTable(); dialog.dispose(); JOptionPane.showMessageDialog(mainFrame, "Password saved successfully!"); } catch (Exception ex) { JOptionPane.showMessageDialog(dialog, "Error saving password: " + ex.getMessage()); } }); dialog.setContentPane(panel); dialog.setVisible(true); } private void showPasswordGenerator() { showPasswordGeneratorDialog(null); } private void showPasswordGeneratorDialog(JPasswordField targetField) { JDialog dialog = new JDialog(mainFrame, "Password Generator", true); dialog.setSize(400, 400); dialog.setLocationRelativeTo(mainFrame); JPanel panel = new JPanel(new GridLayout(0, 2, 10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); JSpinner lengthSpinner = new JSpinner(new SpinnerNumberModel(16, 8, 64, 1)); JCheckBox uppercaseCheck = new JCheckBox("Uppercase", true); JCheckBox lowercaseCheck = new JCheckBox("Lowercase", true); JCheckBox digitsCheck = new JCheckBox("Digits", true); JCheckBox specialCheck = new JCheckBox("Special Characters", true); JTextField generatedPasswordField = new JTextField(); JButton generateButton = new JButton("Generate"); JButton useButton = new JButton("Use Password"); JLabel strengthLabel = new JLabel("Strength: -"); panel.add(new JLabel("Length:")); panel.add(lengthSpinner); panel.add(new JLabel("Character Types:")); panel.add(new JLabel("")); panel.add(uppercaseCheck); panel.add(lowercaseCheck); panel.add(digitsCheck); panel.add(specialCheck); panel.add(new JLabel("Generated Password:")); panel.add(generatedPasswordField); panel.add(new JLabel("")); panel.add(generateButton); panel.add(strengthLabel); panel.add(useButton); generateButton.addActionListener(e -> { try { String password = service.generatePassword( (Integer) lengthSpinner.getValue(), uppercaseCheck.isSelected(), lowercaseCheck.isSelected(), digitsCheck.isSelected(), specialCheck.isSelected() ); generatedPasswordField.setText(password); int strength = service.calculatePasswordStrength(password); strengthLabel.setText("Strength: " + strength + "/10"); strengthLabel.setForeground(getStrengthColor(strength)); } catch (Exception ex) { JOptionPane.showMessageDialog(dialog, "Error generating password: " + ex.getMessage()); } }); useButton.addActionListener(e -> { if (targetField != null) { targetField.setText(generatedPasswordField.getText()); } dialog.dispose(); }); // Generate initial password generateButton.doClick(); dialog.setContentPane(panel); dialog.setVisible(true); } private Color getStrengthColor(int strength) { if (strength <= 3) return Color.RED; if (strength <= 6) return Color.ORANGE; if (strength <= 8) return Color.BLUE; return Color.GREEN; } private void showEditPasswordDialog() { int selectedRow = passwordTable.getSelectedRow(); if (selectedRow == -1) { JOptionPane.showMessageDialog(mainFrame, "Please select a password to edit."); return; } // Implementation similar to add dialog but with existing data // ... (detailed implementation would go here) } private void deleteSelectedPassword() { int selectedRow = passwordTable.getSelectedRow(); if (selectedRow == -1) { JOptionPane.showMessageDialog(mainFrame, "Please select a password to delete."); return; } int confirm = JOptionPane.showConfirmDialog( mainFrame, "Are you sure you want to delete this password?", "Confirm Delete", JOptionPane.YES_NO_OPTION ); if (confirm == JOptionPane.YES_OPTION) { try { String title = (String) tableModel.getValueAt(selectedRow, 0); List<PasswordEntry> entries = service.searchPasswordEntries(title); if (!entries.isEmpty()) { service.deletePasswordEntry(entries.get(0).getId()); refreshPasswordTable(); } } catch (Exception ex) { JOptionPane.showMessageDialog(mainFrame, "Error deleting password: " + ex.getMessage()); } } } private void showViewPasswordDialog() { int selectedRow = passwordTable.getSelectedRow(); if (selectedRow == -1) { JOptionPane.showMessageDialog(mainFrame, "Please select a password to view."); return; } try { String title = (String) tableModel.getValueAt(selectedRow, 0); List<PasswordEntry> entries = service.searchPasswordEntries(title); if (!entries.isEmpty()) { PasswordEntry entry = entries.get(0); String password = service.getDecryptedPassword(entry); JDialog dialog = new JDialog(mainFrame, "View Password", true); dialog.setSize(300, 200); dialog.setLocationRelativeTo(mainFrame); JPanel panel = new JPanel(new GridLayout(0, 1, 10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); panel.add(new JLabel("Title: " + entry.getTitle())); panel.add(new JLabel("Username: " + entry.getUsername())); JPasswordField passwordField = new JPasswordField(password); passwordField.setEditable(false); panel.add(new JLabel("Password:")); panel.add(passwordField); JButton closeButton = new JButton("Close"); panel.add(closeButton); closeButton.addActionListener(e -> dialog.dispose()); dialog.setContentPane(panel); dialog.setVisible(true); } } catch (Exception ex) { JOptionPane.showMessageDialog(mainFrame, "Error viewing password: " + ex.getMessage()); } } private void searchPasswords(String query) { try { tableModel.setRowCount(0); List<PasswordEntry> entries = service.searchPasswordEntries(query); for (PasswordEntry entry : entries) { tableModel.addRow(new Object[]{ entry.getTitle(), entry.getUsername(), entry.getUrl(), entry.getCategory(), entry.getUpdatedAt().toString() }); } } catch (Exception ex) { JOptionPane.showMessageDialog(mainFrame, "Error searching passwords: " + ex.getMessage()); } } private void showChangeMasterPassword() { JDialog dialog = new JDialog(mainFrame, "Change Master Password", true); dialog.setSize(400, 300); dialog.setLocationRelativeTo(mainFrame); JPanel panel = new JPanel(new GridLayout(0, 2, 10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); JPasswordField currentPasswordField = new JPasswordField(); JPasswordField newPasswordField = new JPasswordField(); JPasswordField confirmPasswordField = new JPasswordField(); JButton changeButton = new JButton("Change Master Password"); panel.add(new JLabel("Current Password:")); panel.add(currentPasswordField); panel.add(new JLabel("New Password:")); panel.add(newPasswordField); panel.add(new JLabel("Confirm New Password:")); panel.add(confirmPasswordField); panel.add(new JLabel("")); panel.add(changeButton); changeButton.addActionListener(e -> { String currentPassword = new String(currentPasswordField.getPassword()); String newPassword = new String(newPasswordField.getPassword()); String confirmPassword = new String(confirmPasswordField.getPassword()); if (!newPassword.equals(confirmPassword)) { JOptionPane.showMessageDialog(dialog, "New passwords do not match!"); return; } if (newPassword.length() < 8) { JOptionPane.showMessageDialog(dialog, "New password must be at least 8 characters long!"); return; } try { service.changeMasterPassword(currentPassword, newPassword); JOptionPane.showMessageDialog(dialog, "Master password changed successfully!"); dialog.dispose(); } catch (Exception ex) { JOptionPane.showMessageDialog(dialog, "Error changing master password: " + ex.getMessage()); } }); dialog.setContentPane(panel); dialog.setVisible(true); } public void show() { mainFrame.setVisible(true); } } 7. Main Application Class
package com.passwordmanager; import com.passwordmanager.service.PasswordManagerService; import com.passwordmanager.ui.PasswordManagerUI; import javax.swing.*; public class PasswordManagerApp { public static void main(String[] args) { // Set system properties for better security System.setProperty("file.encoding", "UTF-8"); // Use try-with-resources for auto-closing sensitive data (conceptual) try { // Set look and feel UIManager.setLookAndFeel(UIManager.getSystemLookAndFeel()); } catch (Exception e) { e.printStackTrace(); } // Create and show application SwingUtilities.invokeLater(() -> { PasswordManagerService service = new PasswordManagerService(); PasswordManagerUI ui = new PasswordManagerUI(service); ui.show(); }); } } Security Features
1. Cryptographic Security
- AES-256-GCM for authenticated encryption
- PBKDF2 with 100,000 iterations for key derivation
- Unique IV for each encryption operation
- Salt for each user's master password
2. Memory Security
- Passwords only decrypted when needed
- Sensitive data cleared from memory after use
- Session locking capability
3. Data Protection
- All sensitive fields encrypted at rest
- SQLite database with encrypted content
- Master password verification without storage
4. Password Strength
- Secure password generation
- Password strength meter
- Passphrase generation option
Usage Examples
// Basic usage example public class ExampleUsage { public static void main(String[] args) throws Exception { PasswordManagerService service = new PasswordManagerService(); if (service.isFirstTimeSetup()) { service.initializeUserProfile("MySecureMasterPassword123!"); } if (service.authenticateUser("MySecureMasterPassword123!")) { // Add a password entry service.addPasswordEntry( "Gmail", "[email protected]", "MyGmailPassword123!", "https://gmail.com", "Personal email account", "Email" ); // Generate a strong password String strongPassword = service.generatePassword(16, true, true, true, true); System.out.println("Generated password: " + strongPassword); // Search for entries List<PasswordEntry> results = service.searchPasswordEntries("gmail"); for (PasswordEntry entry : results) { String decryptedPassword = service.getDecryptedPassword(entry); System.out.println("Decrypted password: " + decryptedPassword); } } } } Build Configuration (Maven)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.passwordmanager</groupId> <artifactId>secure-password-manager</artifactId> <version>1.0.0</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- SQLite Database --> <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.42.0.0</version> </dependency> <!-- JSON Processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.15.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency> <!-- Testing --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>17</source> <target>17</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.passwordmanager.PasswordManagerApp</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
This password manager provides enterprise-grade security with user-friendly features, making it suitable for personal use while maintaining strong cryptographic protection for all stored credentials.