File Encryption Tool in Java

A comprehensive guide to building a secure file encryption and decryption tool in Java using modern cryptographic practices.

Overview

This tool provides a command-line interface for encrypting and decrypting files using strong encryption algorithms like AES with proper key management and security considerations.

Complete Implementation

1. Main Encryption Tool Class

package com.fileencryptor;
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Scanner;
/**
* Secure File Encryption Tool using AES-GCM mode
* Provides encryption and decryption functionality with password-based key derivation
*/
public class FileEncryptionTool {
// Encryption parameters
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final int AES_KEY_SIZE = 256;
private static final int GCM_TAG_LENGTH = 128;
private static final int GCM_IV_LENGTH = 12; // 96 bits for GCM
private static final int SALT_LENGTH = 16;
private static final int ITERATION_COUNT = 65536;
/**
* Encrypts a file using password-based encryption
*/
public static void encryptFile(String inputFile, String outputFile, String password) 
throws Exception {
// Generate random salt and IV
SecureRandom secureRandom = new SecureRandom();
byte[] salt = new byte[SALT_LENGTH];
byte[] iv = new byte[GCM_IV_LENGTH];
secureRandom.nextBytes(salt);
secureRandom.nextBytes(iv);
// Derive AES key from password
SecretKey secretKey = deriveKey(password, salt);
// Initialize cipher for encryption
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);
try (FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile)) {
// Write salt and IV to the beginning of the output file
fos.write(salt);
fos.write(iv);
// Encrypt the file content
try (CipherOutputStream cos = new CipherOutputStream(fos, cipher)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
cos.write(buffer, 0, bytesRead);
}
}
}
System.out.println("File encrypted successfully: " + outputFile);
}
/**
* Decrypts a file using password-based decryption
*/
public static void decryptFile(String inputFile, String outputFile, String password) 
throws Exception {
try (FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile)) {
// Read salt and IV from the beginning of the encrypted file
byte[] salt = new byte[SALT_LENGTH];
byte[] iv = new byte[GCM_IV_LENGTH];
if (fis.read(salt) != SALT_LENGTH || fis.read(iv) != GCM_IV_LENGTH) {
throw new IllegalArgumentException("Invalid encrypted file format");
}
// Derive AES key from password and salt
SecretKey secretKey = deriveKey(password, salt);
// Initialize cipher for decryption
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
// Decrypt the file content
try (CipherInputStream cis = new CipherInputStream(fis, cipher)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = cis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
}
}
System.out.println("File decrypted successfully: " + outputFile);
}
/**
* Derives a secure AES key from password using PBKDF2
*/
private static SecretKey deriveKey(String password, byte[] salt) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, AES_KEY_SIZE);
SecretKey tmp = factory.generateSecret(spec);
return new SecretKeySpec(tmp.getEncoded(), ALGORITHM);
}
/**
* Generates a secure random AES key for key file usage
*/
public static void generateKeyFile(String keyFilePath) throws Exception {
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
keyGen.init(AES_KEY_SIZE);
SecretKey secretKey = keyGen.generateKey();
try (FileOutputStream fos = new FileOutputStream(keyFilePath)) {
fos.write(secretKey.getEncoded());
}
System.out.println("Key file generated successfully: " + keyFilePath);
}
/**
* Calculates file hash for integrity verification
*/
public static String calculateFileHash(String filePath) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
try (FileInputStream fis = new FileInputStream(filePath)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
digest.update(buffer, 0, bytesRead);
}
}
byte[] hash = digest.digest();
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
hexString.append(String.format("%02x", b));
}
return hexString.toString();
}
}

2. Command Line Interface

/**
* Command Line Interface for the File Encryption Tool
*/
public class EncryptionCLI {
private static final Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("=== Secure File Encryption Tool ===");
System.out.println("Using AES-256-GCM with PBKDF2 key derivation");
while (true) {
printMenu();
String choice = scanner.nextLine();
try {
switch (choice) {
case "1":
handleEncryption();
break;
case "2":
handleDecryption();
break;
case "3":
handleKeyGeneration();
break;
case "4":
handleIntegrityCheck();
break;
case "5":
System.out.println("Exiting... Goodbye!");
return;
default:
System.out.println("Invalid choice. Please try again.");
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
}
System.out.println();
}
}
private static void printMenu() {
System.out.println("1. Encrypt a file");
System.out.println("2. Decrypt a file");
System.out.println("3. Generate key file");
System.out.println("4. Verify file integrity");
System.out.println("5. Exit");
System.out.print("Choose an option: ");
}
private static void handleEncryption() throws Exception {
System.out.print("Enter input file path: ");
String inputFile = scanner.nextLine();
System.out.print("Enter output file path: ");
String outputFile = scanner.nextLine();
System.out.print("Enter encryption password: ");
String password = scanner.nextLine();
// Verify input file exists
if (!Files.exists(Paths.get(inputFile))) {
throw new FileNotFoundException("Input file not found: " + inputFile);
}
FileEncryptionTool.encryptFile(inputFile, outputFile, password);
// Calculate and display hash for verification
String hash = FileEncryptionTool.calculateFileHash(outputFile);
System.out.println("Encrypted file SHA-256: " + hash);
}
private static void handleDecryption() throws Exception {
System.out.print("Enter encrypted file path: ");
String inputFile = scanner.nextLine();
System.out.print("Enter output file path: ");
String outputFile = scanner.nextLine();
System.out.print("Enter decryption password: ");
String password = scanner.nextLine();
FileEncryptionTool.decryptFile(inputFile, outputFile, password);
// Verify decryption was successful by checking file integrity
String hash = FileEncryptionTool.calculateFileHash(outputFile);
System.out.println("Decrypted file SHA-256: " + hash);
}
private static void handleKeyGeneration() throws Exception {
System.out.print("Enter key file path: ");
String keyFile = scanner.nextLine();
FileEncryptionTool.generateKeyFile(keyFile);
System.out.println("Keep this key file secure and secret!");
}
private static void handleIntegrityCheck() throws Exception {
System.out.print("Enter file path to verify: ");
String filePath = scanner.nextLine();
String hash = FileEncryptionTool.calculateFileHash(filePath);
System.out.println("File SHA-256 hash: " + hash);
}
}

3. Advanced Encryption Manager

/**
* Advanced encryption manager with additional features
*/
public class AdvancedEncryptionManager {
private static final String ENCRYPTED_EXTENSION = ".encrypted";
private static final String DECRYPTED_EXTENSION = ".decrypted";
/**
* Encrypts all files in a directory
*/
public static void encryptDirectory(String directoryPath, String password) throws Exception {
File directory = new File(directoryPath);
if (!directory.isDirectory()) {
throw new IllegalArgumentException("Path is not a directory: " + directoryPath);
}
File[] files = directory.listFiles((dir, name) -> !name.endsWith(ENCRYPTED_EXTENSION));
if (files != null) {
for (File file : files) {
if (file.isFile()) {
String outputFile = file.getAbsolutePath() + ENCRYPTED_EXTENSION;
FileEncryptionTool.encryptFile(file.getAbsolutePath(), outputFile, password);
}
}
}
System.out.println("Directory encryption completed.");
}
/**
* Decrypts all encrypted files in a directory
*/
public static void decryptDirectory(String directoryPath, String password) throws Exception {
File directory = new File(directoryPath);
if (!directory.isDirectory()) {
throw new IllegalArgumentException("Path is not a directory: " + directoryPath);
}
File[] files = directory.listFiles((dir, name) -> name.endsWith(ENCRYPTED_EXTENSION));
if (files != null) {
for (File file : files) {
if (file.isFile()) {
String outputFile = file.getAbsolutePath()
.replace(ENCRYPTED_EXTENSION, DECRYPTED_EXTENSION);
FileEncryptionTool.decryptFile(file.getAbsolutePath(), outputFile, password);
}
}
}
System.out.println("Directory decryption completed.");
}
/**
* Securely deletes a file by overwriting it multiple times
*/
public static void secureDelete(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException("File not found: " + filePath);
}
long length = file.length();
try (RandomAccessFile raf = new RandomAccessFile(file, "rws")) {
// Overwrite with random data 3 times (DoD 5220.22-M standard)
for (int pass = 0; pass < 3; pass++) {
raf.seek(0);
byte[] randomData = new byte[8192];
SecureRandom secureRandom = new SecureRandom();
long bytesWritten = 0;
while (bytesWritten < length) {
secureRandom.nextBytes(randomData);
int toWrite = (int) Math.min(randomData.length, length - bytesWritten);
raf.write(randomData, 0, toWrite);
bytesWritten += toWrite;
}
raf.getFD().sync();
}
}
// Finally delete the file
if (!file.delete()) {
throw new IOException("Failed to delete file: " + filePath);
}
System.out.println("File securely deleted: " + filePath);
}
}

4. 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.fileencryptor</groupId>
<artifactId>file-encryption-tool</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- JUnit for testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.fileencryptor.EncryptionCLI</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Security Features

1. Strong Cryptographic Algorithms

  • AES-256-GCM: Provides both confidentiality and integrity
  • PBKDF2WithHmacSHA256: Secure password-based key derivation
  • SHA-256: File integrity verification

2. Security Best Practices

  • Unique IV per encryption: Prevents pattern analysis
  • Salt for key derivation: Prevents rainbow table attacks
  • Authentication with GCM: Detects tampering
  • Secure random generation: Cryptographically strong randomness

3. Key Management

  • Password-based key derivation with high iteration count
  • Option to generate and use key files
  • Secure memory practices

Usage Examples

Command Line Usage

# Compile and run
javac -cp . com/fileencryptor/*.java
java com.fileencryptor.EncryptionCLI
# Or package with Maven
mvn clean package
java -jar target/file-encryption-tool-1.0.0-jar-with-dependencies.jar

Programmatic Usage

// Encrypt a file
FileEncryptionTool.encryptFile("document.pdf", "document.pdf.encrypted", "securepassword");
// Decrypt a file
FileEncryptionTool.decryptFile("document.pdf.encrypted", "document_decrypted.pdf", "securepassword");
// Generate key file
FileEncryptionTool.generateKeyFile("secret.key");
// Verify file integrity
String hash = FileEncryptionTool.calculateFileHash("important_file.txt");

Security Considerations

  1. Password Strength: Use strong, complex passwords
  2. Key Storage: Never store keys with encrypted data
  3. Secure Deletion: Use the secure delete feature for sensitive files
  4. Backup: Always maintain backups of important files before encryption
  5. Testing: Test encryption/decryption on non-critical files first

This File Encryption Tool provides enterprise-grade security while maintaining ease of use for both command-line and programmatic usage scenarios.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper