AES-256 File Encryption Tool (java, written by Claude Code)
envgap__claude-code__java-t1-11
Written by a coding agent; not on GitHubWritten 2026-02-27
01 / FAILURE SIGNATURE
As the study recorded it
No identifying execution failure has been captured.
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
Not freshly verified- Manifest
pom.xml- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / TASK AND FAILURE
claude-code/java-t1 #11 · read the task the agent was given
Claude Code wrote this java project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: AES-256 File Encryption Tool Write a program that encrypts and decrypts files using AES-256 encryption in CBC mode with proper key derivation, initialization vectors, and authenticated encryption to prevent tampering. FUNCTIONAL REQUIREMENTS: - Accept a file path, a password, and a mode (encrypt or decrypt) as command-line arguments - Derive the encryption key from the password using PBKDF2 with SHA-256, a random 16-byte salt, and at least 100,000 iterations - Encrypt using AES-256-CBC with a random 16-byte initialization vector (IV) for each encryption - Prepend the salt and IV to the encrypted output file so they are available for decryption - Add HMAC-SHA256 authentication tag to the encrypted file to detect tampering during decryption - During decryption, verify the HMAC before attempting to decrypt and report a clear error if the file has been modified - Support encrypting entire directories recursively via --recursive flag, preserving directory structure in the output - Support a --output flag to specify the output file or directory (default: append .enc for encryption, strip .enc for decryption) - Display progress information for large files: file size, percentage complete, and throughput - If no input file is given, generate a sample text file with random content, encrypt it, then decrypt it back and verify the output matches the original - Handle errors gracefully: wrong password (HMAC mismatch), corrupted file, file not found, permission denied Create a complete Java project for a clean Ubuntu 22.04 machine with only JDK 17+ installed. Include: - Source code - pom.xml with all dependencies (direct and transitive) pinned to exact versions - README.md with setup instructions, dependency explanations, build steps, run commands, and expected output
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]
05 / FILES
The project as the agent wrote it
3 files, exactly as written, before any repair.
pom.xml
<?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.encryptor</groupId>
<artifactId>file-encryptor</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>AES-256 File Encryptor (JCA)</name>
<description>File encryption tool using javax.crypto built-in JCA</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<archive>
<manifest>
<mainClass>encryptor.FileEncryptor</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
README.md
# AES-256 File Encryption Tool - Java Trial 1 ## Dependencies - **javax.crypto (JCA)** - Built-in Java Cryptography Architecture. No external dependencies required. - **JDK 17+** required. ## Build ```bash mvn clean package ``` ## Usage ### Encrypt a file ```bash java -jar target/file-encryptor-1.0.0.jar encrypt <input> -o <output> -p <password> ``` ### Decrypt a file ```bash java -jar target/file-encryptor-1.0.0.jar decrypt <input> -o <output> -p <password> ``` ### Demo mode ```bash java -jar target/file-encryptor-1.0.0.jar demo ``` ## Design - **Algorithm**: AES-256-CBC with PKCS5Padding - **Key Derivation**: PBKDF2WithHmacSHA256 with 600,000 iterations - **Integrity**: HMAC-SHA256 over salt + IV + ciphertext - **File Format**: MAGIC(4) + SALT(32) + IV(16) + CT_LEN(8) + CT(N) + HMAC(32)
src/main/java/encryptor/FileEncryptor.java
package encryptor;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Arrays;
/**
* AES-256 File Encryption Tool - Trial 1 (Java)
* Uses javax.crypto (built-in JCA) with AES-256-CBC and PBKDF2 key derivation.
*/
public class FileEncryptor {
private static final byte[] MAGIC_HEADER = "ENC1".getBytes(StandardCharsets.US_ASCII);
private static final int SALT_SIZE = 32;
private static final int IV_SIZE = 16;
private static final int KEY_SIZE = 256; // bits
private static final int PBKDF2_ITERATIONS = 600000;
private static final int HMAC_SIZE = 32;
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String KEY_ALGORITHM = "PBKDF2WithHmacSHA256";
private static final String HMAC_ALGORITHM = "HmacSHA256";
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("No command specified. Running demo mode...");
runDemo();
return;
}
String command = args[0].toLowerCase();
switch (command) {
case "encrypt":
handleEncrypt(args);
break;
case "decrypt":
handleDecrypt(args);
break;
case "demo":
runDemo();
break;
default:
printUsage();
break;
}
}
private static void printUsage() {
System.out.println("Usage:");
System.out.println(" java -jar encryptor.jar encrypt <input> [-o output] [-p password]");
System.out.println(" java -jar encryptor.jar decrypt <input> [-o output] [-p password]");
System.out.println(" java -jar encryptor.jar demo");
}
private static void handleEncrypt(String[] args) {
if (args.length < 2) {
System.out.println("Error: Input file required.");
printUsage();
System.exit(1);
}
String inputPath = args[1];
String outputPath = null;
String password = null;
for (int i = 2; i < args.length; i++) {
if ("-o".equals(args[i]) && i + 1 < args.length) {
outputPath = args[++i];
} else if ("-p".equals(args[i]) && i + 1 < args.length) {
password = args[++i];
}
}
if (outputPath == null) {
outputPath = inputPath + ".enc";
}
if (password == null) {
password = readPassword("Enter password: ");
String confirm = readPassword("Confirm password: ");
if (!password.equals(confirm)) {
System.out.println("Error: Passwords do not match.");
System.exit(1);
}
}
try {
encryptFile(inputPath, outputPath, password);
} catch (Exception e) {
System.out.println("Error during encryption: " + e.getMessage());
System.exit(1);
}
}
private static void handleDecrypt(String[] args) {
if (args.length < 2) {
System.out.println("Error: Input file required.");
printUsage();
System.exit(1);
}
String inputPath = args[1];
String outputPath = null;
String password = null;
for (int i = 2; i < args.length; i++) {
if ("-o".equals(args[i]) && i + 1 < args.length) {
outputPath = args[++i];
} else if ("-p".equals(args[i]) && i + 1 < args.length) {
password = args[++i];
}
}
if (outputPath == null) {
if (inputPath.endsWith(".enc")) {
outputPath = inputPath.substring(0, inputPath.length() - 4);
} else {
outputPath = inputPath + ".dec";
}
}
if (password == null) {
password = readPassword("Enter password: ");
}
try {
decryptFile(inputPath, outputPath, password);
} catch (Exception e) {
System.out.println("Error during decryption: " + e.getMessage());
System.exit(1);
}
}
private static String readPassword(String prompt) {
Console console = System.console();
if (console != null) {
char[] pwd = console.readPassword(prompt);
return new String(pwd);
} else {
System.out.print(prompt);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
return reader.readLine();
} catch (IOException e) {
throw new RuntimeException("Failed to read password", e);
}
}
}
private static byte[] deriveKey(String password, byte[] salt) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, PBKDF2_ITERATIONS, KEY_SIZE);
SecretKey tmp = factory.generateSecret(spec);
return tmp.getEncoded();
}
private static byte[] computeHmac(byte[] key, byte[] data) throws Exception {
Mac mac = Mac.getInstance(HMAC_ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key, HMAC_ALGORITHM);
mac.init(keySpec);
return mac.doFinal(data);
}
public static void encryptFile(String inputPath, String outputPath, String password) throws Exception {
byte[] plaintext = Files.readAllBytes(Paths.get(inputPath));
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_SIZE];
byte[] iv = new byte[IV_SIZE];
random.nextBytes(salt);
random.nextBytes(iv);
byte[] key = deriveKey(password, salt);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] ciphertext = cipher.doFinal(plaintext);
// HMAC over salt + iv + ciphertext
ByteBuffer hmacInput = ByteBuffer.allocate(salt.length + iv.length + ciphertext.length);
hmacInput.put(salt);
hmacInput.put(iv);
hmacInput.put(ciphertext);
byte[] hmac = computeHmac(key, hmacInput.array());
// Write: MAGIC(4) + SALT(32) + IV(16) + CT_LEN(8) + CT(N) + HMAC(32)
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(outputPath))) {
dos.write(MAGIC_HEADER);
dos.write(salt);
dos.write(iv);
dos.writeLong(ciphertext.length);
dos.write(ciphertext);
dos.write(hmac);
}
System.out.println("Encrypted: " + inputPath + " -> " + outputPath);
System.out.printf(" Salt: %s...%n", bytesToHex(salt).substring(0, 16));
System.out.printf(" IV: %s...%n", bytesToHex(iv).substring(0, 16));
System.out.printf(" Size: %d bytes -> %d bytes%n", plaintext.length, ciphertext.length);
}
public static void decryptFile(String inputPath, String outputPath, String password) throws Exception {
byte[] data = Files.readAllBytes(Paths.get(inputPath));
if (data.length < 4 || !Arrays.equals(Arrays.copyOfRange(data, 0, 4), MAGIC_HEADER)) {
System.out.println("Error: Not a valid encrypted file (bad magic header).");
System.exit(1);
}
int offset = 4;
byte[] salt = Arrays.copyOfRange(data, offset, offset + SALT_SIZE);
offset += SALT_SIZE;
byte[] iv = Arrays.copyOfRange(data, offset, offset + IV_SIZE);
offset += IV_SIZE;
ByteBuffer bb = ByteBuffer.wrap(data, offset, 8);
long ctLen = bb.getLong();
offset += 8;
byte[] ciphertext = Arrays.copyOfRange(data, offset, offset + (int) ctLen);
offset += (int) ctLen;
byte[] storedHmac = Arrays.copyOfRange(data, offset, offset + HMAC_SIZE);
byte[] key = deriveKey(password, salt);
// Verify HMAC
ByteBuffer hmacInput = ByteBuffer.allocate(salt.length + iv.length + ciphertext.length);
hmacInput.put(salt);
hmacInput.put(iv);
hmacInput.put(ciphertext);
byte[] computedHmac = computeHmac(key, hmacInput.array());
if (!MessageDigest.isEqual(storedHmac, computedHmac)) {
System.out.println("Error: Integrity check failed. Wrong password or corrupted file.");
System.exit(1);
}
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] plaintext;
try {
plaintext = cipher.doFinal(ciphertext);
} catch (Exception e) {
System.out.println("Error: Decryption failed. Wrong password or corrupted file.");
System.exit(1);
return;
}
Files.write(Paths.get(outputPath), plaintext);
System.out.println("Decrypted: " + inputPath + " -> " + outputPath);
System.out.printf(" Size: %d bytes -> %d bytes%n", ciphertext.length, plaintext.length);
}
private static void runDemo() {
String sampleFile = "sample_input.txt";
String encryptedFile = "sample_encrypted.enc";
String decryptedFile = "sample_decrypted.txt";
String demoPassword = "demo_password_123";
try {
// Create sample file
String sampleContent = "This is a sample file for AES-256-CBC encryption demo.\n"
+ "It contains multiple lines of text.\n"
+ "Line 3: The quick brown fox jumps over the lazy dog.\n"
+ "Line 4: 0123456789 ABCDEF !@#$%^&*()\n";
Files.write(Paths.get(sampleFile), sampleContent.getBytes(StandardCharsets.UTF_8));
System.out.println("Created sample file: " + sampleFile + " (" + sampleContent.length() + " bytes)");
// Encrypt
System.out.println("\n--- Encrypting ---");
encryptFile(sampleFile, encryptedFile, demoPassword);
// Decrypt
System.out.println("\n--- Decrypting ---");
decryptFile(encryptedFile, decryptedFile, demoPassword);
// Verify
byte[] original = Files.readAllBytes(Paths.get(sampleFile));
byte[] restored = Files.readAllBytes(Paths.get(decryptedFile));
if (Arrays.equals(original, restored)) {
System.out.println("\nVerification: SUCCESS - Decrypted file matches original.");
} else {
System.out.println("\nVerification: FAILED - Files do not match!");
}
// Test wrong password
System.out.println("\n--- Testing wrong password ---");
try {
decryptFile(encryptedFile, "should_not_exist.txt", "wrong_password");
} catch (SystemExitException e) {
// expected
} catch (Exception e) {
System.out.println("(Wrong password correctly rejected)");
}
} catch (Exception e) {
System.out.println("Demo error: " + e.getMessage());
e.printStackTrace();
} finally {
// Cleanup
try {
Files.deleteIfExists(Paths.get(sampleFile));
Files.deleteIfExists(Paths.get(encryptedFile));
Files.deleteIfExists(Paths.get(decryptedFile));
Files.deleteIfExists(Paths.get("should_not_exist.txt"));
} catch (IOException ignored) {
}
System.out.println("\nDemo complete. Temporary files cleaned up.");
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
// Placeholder for catching System.exit in demo
private static class SystemExitException extends RuntimeException {
}
}