Java SE自定义密钥加密字符串及文本文件读写解密方案求助
Java SE Implementation for Password-Based String Encryption/Decryption with File Persistence
Got it, let's tackle this problem step by step. You want a Java SE solution to encrypt a string with a custom password, save the encrypted text to a file, then later read it back and decrypt it. I'll use standard Java crypto libraries (no external dependencies) that follow modern security best practices—no sketchy custom algorithms here.
Core Approach
I’m using these components for a secure, robust implementation:
- AES-GCM: Authenticated encryption that ensures both confidentiality and integrity (prevents tampering with the encrypted file)
- PBKDF2WithHmacSHA256: Derives a secure encryption key from your password (never use the raw password as a key directly—this makes brute-force attacks way harder)
- We’ll store all required decryption data in the file: salt, IV, ciphertext, and authentication tag (AES-GCM needs all these to decrypt safely)
Full Implementation Code
Create a utility class EncryptionUtils.java—it handles all the heavy lifting with clear comments:
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.security.SecureRandom; import java.security.spec.KeySpec; import java.util.Base64; public class EncryptionUtils { // Security configuration - adjust based on your needs private static final int AES_KEY_SIZE = 256; // 128 is also acceptable if 256 isn't allowed private static final int GCM_TAG_LENGTH = 128; // Bits, standard for GCM integrity checks private static final int PBKDF2_ITERATIONS = 65536; // Higher = slower, more secure private static final int SALT_LENGTH = 16; // Random salt for key derivation private static final int IV_LENGTH = 12; // Recommended IV length for GCM // Encrypt a string with a password and save to target file public static void encryptAndSave(String plaintext, String password, String filePath) throws Exception { // Generate random salt (unique per encryption) byte[] salt = new byte[SALT_LENGTH]; new SecureRandom().nextBytes(salt); // Generate random IV (unique per encryption) byte[] iv = new byte[IV_LENGTH]; new SecureRandom().nextBytes(iv); // Derive AES key from password using PBKDF2 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATIONS, AES_KEY_SIZE); SecretKey tmpKey = factory.generateSecret(spec); SecretKey aesKey = new SecretKeySpec(tmpKey.getEncoded(), "AES"); // Initialize AES-GCM cipher for encryption Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); cipher.init(Cipher.ENCRYPT_MODE, aesKey, gcmSpec); // Encrypt the plaintext byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)); // Encode all binary data to Base64 for safe text file storage String saltBase64 = Base64.getEncoder().encodeToString(salt); String ivBase64 = Base64.getEncoder().encodeToString(iv); String ciphertextBase64 = Base64.getEncoder().encodeToString(ciphertext); // Combine parts with a delimiter that won't appear in Base64 String combinedData = saltBase64 + "|||" + ivBase64 + "|||" + ciphertextBase64; // Write to file Files.write(Paths.get(filePath), combinedData.getBytes(StandardCharsets.UTF_8)); } // Read encrypted file and decrypt with password public static String loadAndDecrypt(String filePath, String password) throws Exception { // Read combined data from file String combinedData = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8); // Split into individual components String[] parts = combinedData.split("\\|\\|\\|"); if (parts.length != 3) { throw new IllegalArgumentException("Invalid encrypted file format—may be tampered with"); } // Decode Base64 back to binary byte[] salt = Base64.getDecoder().decode(parts[0]); byte[] iv = Base64.getDecoder().decode(parts[1]); byte[] ciphertext = Base64.getDecoder().decode(parts[2]); // Derive the same AES key using password and stored salt SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATIONS, AES_KEY_SIZE); SecretKey tmpKey = factory.generateSecret(spec); SecretKey aesKey = new SecretKeySpec(tmpKey.getEncoded(), "AES"); // Initialize AES-GCM cipher for decryption Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); cipher.init(Cipher.DECRYPT_MODE, aesKey, gcmSpec); // Decrypt and convert back to string byte[] plaintextBytes = cipher.doFinal(ciphertext); return new String(plaintextBytes, StandardCharsets.UTF_8); } // Example usage public static void main(String[] args) { String secretMessage = "This is my top-secret data that no one else should see!"; String userPassword = "MyStrongCustomPassword123!"; String encryptedFile = "secret_data.txt"; try { // Encrypt and save encryptAndSave(secretMessage, userPassword, encryptedFile); System.out.println("Successfully encrypted and saved to: " + encryptedFile); // Decrypt and verify String decryptedMessage = loadAndDecrypt(encryptedFile, userPassword); System.out.println("Decrypted message: " + decryptedMessage); } catch (Exception e) { // In production, handle specific exceptions (e.g., wrong password = BadPaddingException) e.printStackTrace(); } } }
Key Best Practices & Notes
- Never hardcode passwords: In real apps, fetch passwords from user input (console prompt, GUI, or secure vault) instead of hardcoding.
- Error handling: The example uses a generic try-catch, but in production, handle specific exceptions like
BadPaddingException(indicates wrong password or tampered file) to give meaningful feedback. - Security parameters: Adjust
PBKDF2_ITERATIONS(higher = more secure but slower) andAES_KEY_SIZEbased on your compliance needs. 65536 iterations and 256-bit AES are industry standard. - SecureRandom: Always use
SecureRandom(cryptographically secure) for generating salts/IVs—never useRandomfor crypto operations. - File storage: We use Base64 to avoid binary data corruption in text files. For binary storage, you can write raw bytes directly (just ensure you read them in the correct order with fixed lengths).
How to Test
- Compile the class:
javac EncryptionUtils.java - Run it:
java EncryptionUtils - You’ll see
secret_data.txtcreated, and the decrypted message printed to the console. - Try using the wrong password in
loadAndDecrypt—you’ll get aBadPaddingException(expected behavior for invalid credentials).
内容的提问来源于stack exchange,提问作者Samadhi Gunaratna
相关产品推荐
相关产品推荐

