Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
223: Building a File Encryption Utility
I've seen this a lot in junior code reviews: a developer wants to "secure" a local config file, so they write a loop that XORs every byte of the file with a hardcoded character or shifts the bits around. They call it an "encryption utility." In their mind, they've scrambled the data, and since a human can't read it in a text editor, it's encrypted. It isn't.
Scrambling Bytes is Not Encryption
If you use a simple XOR cipher—say, XORing your file bytes with the letter 'K'—you haven't built a vault; you've built a screen door. If an attacker knows (or guesses) just one word of the original file, like the word "password" or a common XML header, they can derive your key instantly through a simple reverse XOR operation. Even worse, repetitive patterns in your original file (like long stretches of zeros in a binary file) remain visible as repetitive patterns in your "encrypted" file. This is called frequency analysis, and it's how people have been breaking amateur ciphers for centuries.
Leveraging the Java Cryptography Architecture (JCA)
To do this right, you have to stop trying to invent the math and start using the javax.crypto package. For file encryption, the industry standard is AES (Advanced Encryption Standard). I recommend using AES in GCM (Galois/Counter Mode). Why GCM? Because it provides "authenticated encryption." It doesn't just hide the data; it attaches a tag that proves the file wasn't tampered with while it was encrypted. If a single bit is flipped by a malicious actor, GCM will throw an exception during decryption rather than handing you corrupted data.
// A glimpse at the core setup
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(mySecureKey, "AES");
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv); // 128-bit authentication tag
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec);
Handling the IV Without Losing Your Mind
Here is where most people trip up: the Initialization Vector (IV). The IV is a random piece of data used to ensure that if you encrypt the same file twice with the same key, you get two completely different encrypted files. If you use a static IV, you're back to the "pattern" problem I mentioned earlier.
The common question I get is: "If the IV is random, how does the decryption utility know what it was?" The answer is simple: you store the IV in plain text at the very beginning of the encrypted file. The IV isn't a secret; the Key is. When you go to decrypt, you read the first 12 bytes (for GCM) of the file, use those to initialize your cipher, and then decrypt the rest of the stream.
When implementing this, avoid reading the entire file into a byte[] array. If you try to encrypt a 2GB video file that way, you'll hit an OutOfMemoryError faster than you can blink. Instead, wrap your FileInputStream and FileOutputStream in a CipherInputStream or use a buffer to process the file in chunks. I personally prefer the buffer approach because it gives me more control over the memory footprint.
📋 Practical Task
Build a Secure AES-GCM File Vault
Your task is to create a utility class called FileVault that can encrypt and decrypt any file on the disk. You must adhere to the following technical requirements:
- Algorithm: Use
AES/GCM/NoPadding. - Key Management: The constructor should accept a 32-byte (256-bit) key. Do not hardcode the key inside the method.
- IV Implementation: For encryption, generate a random 12-byte IV using
SecureRandom. Prepend these 12 bytes to the start of the output file. - Decryption Logic: The decryption method must read the first 12 bytes of the encrypted file to recover the IV before initializing the cipher for the remaining data.
- Memory Efficiency: Use a buffer (e.g., 4KB or 8KB) to read and write the files to ensure the utility can handle files larger than the available JVM heap space.
Test Case: Create a text file with several paragraphs of text. Encrypt it to secret.enc, then decrypt secret.enc back to restored.txt. Verify that the content of restored.txt is identical to the original.
There are no comments for now.