This document covers security best practices for using APACK encryption.
APACK encryption protects against:
| Threat | Protection |
|---|---|
| Unauthorized access | 256-bit encryption |
| Data tampering | AEAD authentication |
| Password brute-force | Memory-hard KDF |
| Side-channel attacks | ChaCha20 constant-time |
APACK does not protect against:
| Threat | Mitigation |
|---|---|
| Key compromise | Proper key management |
| Weak passwords | Password policies |
| Malware on system | System security |
| Physical access | Full-disk encryption |
Always use cryptographically secure random generation:
// GOOD: Cryptographic random
SecretKey key = aes.generateKey();
// GOOD: Secure random for raw bytes
byte[] keyBytes = new byte[32];
SecureRandom.getInstanceStrong().nextBytes(keyBytes);Never use:
- Predictable values
- Timestamps
- User-supplied strings directly
- Weak random generators
| Storage | Recommendation |
|---|---|
| In memory | Clear when done |
| On disk | Never store plaintext |
| In config | Use password + KDF |
| Production | Use HSM or key vault |
// Clear keys when done
try {
byte[] ciphertext = aes.encryptBlock(data, key);
} finally {
// Clear key bytes
byte[] encoded = key.getEncoded();
if (encoded != null) {
Arrays.fill(encoded, (byte) 0);
}
}| Requirement | Minimum | Recommended |
|---|---|---|
| Length | 12 chars | 16+ chars |
| Entropy | 60 bits | 80+ bits |
| Character classes | 3 | 4 (upper, lower, digit, symbol) |
// Secure password reading
Console console = System.console();
if (console != null) {
char[] password = console.readPassword("Password: ");
try {
// Use password
} finally {
Arrays.fill(password, '\0');
}
}char[] password = readPassword("Enter password: ");
char[] confirm = readPassword("Confirm password: ");
try {
if (!Arrays.equals(password, confirm)) {
throw new SecurityException("Passwords do not match");
}
// Proceed with password
} finally {
Arrays.fill(password, '\0');
Arrays.fill(confirm, '\0');
}// BAD: Password as String (can't clear, may be interned)
String password = scanner.nextLine();
// BAD: Logging passwords
log.debug("Password: " + password);
// BAD: Password in command line
// Visible in process list, shell history
apack create -p "secret" archive.apackNonces must be unique per key:
- APACK generates random 96-bit nonces automatically
- Safe for approximately 2^48 encryptions per key
If a nonce is reused with the same key:
- XOR of plaintexts is revealed
- Authentication key may be recovered
- Complete security break
APACK prevents this by using SecureRandom for each encryption.
For long-lived keys, consider rotation:
// Track encryption count
long encryptionCount = counter.incrementAndGet();
// Rotate key before 2^40 uses (safety margin)
if (encryptionCount > (1L << 40)) {
key = aes.generateKey();
counter.set(0);
}OWASP 2024 recommendations:
| Parameter | Value | Rationale |
|---|---|---|
| Memory | 64 MiB | GPU cost |
| Iterations | 3 | Time cost |
| Parallelism | 4 | CPU utilization |
Target: 100-500ms derivation time on target hardware.
// Measure derivation time
long start = System.nanoTime();
kdf.deriveKey(testPassword, salt, 32);
long elapsed = System.nanoTime() - start;
// Adjust if too fast (< 100ms) or too slow (> 500ms)If using PBKDF2:
- Minimum 600,000 iterations (OWASP 2024)
- Consider higher for sensitive data
- Be aware of GPU vulnerability
try {
byte[] plaintext = aes.decryptBlock(ciphertext, key);
} catch (AEADBadTagException e) {
// Authentication failed
// Could be: wrong key, data tampering, corruption
// DO NOT:
// - Reveal which error occurred
// - Return partial data
// - Retry with variations
throw new SecurityException("Decryption failed");
}Don't reveal information through timing:
// BAD: Early exit on error
if (!checkHeader(data)) {
throw new Exception("Invalid header");
}
if (!checkMac(data)) {
throw new Exception("Invalid MAC");
}
// BETTER: Constant-time comparison
boolean valid = constantTimeEquals(computedMac, expectedMac);| Scenario | Protection |
|---|---|
| Archive on disk | APACK encryption |
| Extracted files | Not protected |
| Temporary files | May leak data |
// After extraction, consider secure deletion
try {
// Use archive
} finally {
// Secure delete extracted files if sensitive
secureDelete(extractedPath);
}- SSD wear leveling may retain deleted data
- Consider full-disk encryption for sensitive systems
- Swap files may contain decrypted data
APACK encryption protects data confidentiality, but consider:
- Use TLS for transmission (defense in depth)
- Verify archive integrity after transfer
- Consider signature for authenticity
// After receiving archive
if (!apackVerify(archive)) {
throw new SecurityException("Archive verification failed");
}
// Then decrypt- Keep dependencies updated
- Monitor for CVEs in BouncyCastle, zstd-jni, lz4-java
- Use dependency scanning tools
// Clear sensitive data
Arrays.fill(keyBytes, (byte) 0);
Arrays.fill(password, '\0');
// Note: Java GC may copy objects, clearing is best-effort// BAD: Detailed error reveals information
throw new Exception("Decryption failed: key mismatch for entry 'secret.txt'");
// GOOD: Generic error
throw new SecurityException("Decryption failed");| Event | Log Level |
|---|---|
| Archive created (encrypted) | INFO |
| Archive opened | INFO |
| Decryption failure | WARN |
| Multiple failures | ERROR |
- Passwords
- Decryption keys
- Plaintext data
- Salt values
- Specific entry names (in sensitive contexts)
// GOOD logging
log.info("Created encrypted archive: {}", archivePath);
log.warn("Decryption failed for archive: {}", archivePath);
// BAD logging
log.debug("Password used: {}", password);
log.info("Decrypting entry: {}", entryName);| Standard | AES-256-GCM | ChaCha20-Poly1305 | Argon2id |
|---|---|---|---|
| NIST | Approved | Not approved | Not approved |
| FIPS 140-2/3 | Approved | Not approved | Not approved |
| Common Criteria | Varies | Varies | Varies |
- Government/regulated: Use AES-256-GCM
- Commercial: Either algorithm acceptable
- Open source: ChaCha20 often preferred
Before deploying encrypted APACK archives:
- Using AES-256-GCM or ChaCha20-Poly1305
- Using Argon2id for password-based encryption
- KDF parameters tuned for target hardware
- Passwords meet minimum requirements
- Keys cleared from memory after use
- Authentication failures handled securely
- Logging doesn't expose sensitive data
- Dependencies are up to date
- Tested with wrong passwords (fails gracefully)
- Tested with corrupted data (fails gracefully)
Previous: Key Derivation | Back to: Encryption Overview