Java Cryptography: A Developer's Guide (2026)


Java Cryptography

Cryptography is essential for securing data in Java applications. This comprehensive guide explores cryptographic techniques, patterns, and best practices for Java developers.

Pro Tip: Understanding cryptography fundamentals is crucial for implementing secure applications.

Symmetric Encryption

Note: Symmetric encryption uses the same key for both encryption and decryption.

Symmetric Encryption Implementation


public class SymmetricEncryption {
    private static final String ALGORITHM = "AES/GCM/NoPadding";
    private static final int GCM_IV_LENGTH = 12;
    private static final int GCM_TAG_LENGTH = 16;
    
    private final SecretKey key;
    
    public SymmetricEncryption(byte[] keyBytes) {
        this.key = new SecretKeySpec(keyBytes, "AES");
    }
    
    public String encrypt(String plaintext) throws Exception {
        byte[] iv = generateIV();
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);
        
        byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        byte[] combined = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, combined, 0, iv.length);
        System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);
        
        return Base64.getEncoder().encodeToString(combined);
    }
    
    public String decrypt(String ciphertext) throws Exception {
        byte[] combined = Base64.getDecoder().decode(ciphertext);
        byte[] iv = new byte[GCM_IV_LENGTH];
        byte[] encrypted = new byte[combined.length - GCM_IV_LENGTH];
        System.arraycopy(combined, 0, iv, 0, GCM_IV_LENGTH);
        System.arraycopy(combined, GCM_IV_LENGTH, encrypted, 0, encrypted.length);
        
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
        cipher.init(Cipher.DECRYPT_MODE, key, spec);
        
        byte[] decrypted = cipher.doFinal(encrypted);
        return new String(decrypted, StandardCharsets.UTF_8);
    }
    
    private byte[] generateIV() {
        byte[] iv = new byte[GCM_IV_LENGTH];
        new SecureRandom().nextBytes(iv);
        return iv;
    }
}

Asymmetric Encryption

Pro Tip: Asymmetric encryption uses different keys for encryption and decryption.

Asymmetric Encryption Implementation


public class AsymmetricEncryption {
    private static final String ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
    
    private final PrivateKey privateKey;
    private final PublicKey publicKey;
    
    public AsymmetricEncryption(KeyPair keyPair) {
        this.privateKey = keyPair.getPrivate();
        this.publicKey = keyPair.getPublic();
    }
    
    public String encrypt(String plaintext) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        
        byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    public String decrypt(String ciphertext) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
        return new String(decrypted, StandardCharsets.UTF_8);
    }
    
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(4096);
        return generator.generateKeyPair();
    }
}

Hashing

Note: Hashing is used for data integrity verification and password storage.

Hashing Implementation


public class SecureHashing {
    private static final String HASH_ALGORITHM = "SHA-256";
    private static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA256";
    private static final int ITERATIONS = 65536;
    private static final int KEY_LENGTH = 256;
    
    public String hash(String input) throws Exception {
        MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
        byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(hash);
    }
    
    public String hashPassword(String password, byte[] salt) throws Exception {
        KeySpec spec = new PBEKeySpec(
            password.toCharArray(),
            salt,
            ITERATIONS,
            KEY_LENGTH
        );
        
        SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
        byte[] hash = factory.generateSecret(spec).getEncoded();
        
        byte[] combined = new byte[salt.length + hash.length];
        System.arraycopy(salt, 0, combined, 0, salt.length);
        System.arraycopy(hash, 0, combined, salt.length, hash.length);
        
        return Base64.getEncoder().encodeToString(combined);
    }
    
    public boolean verifyPassword(String password, String storedHash) throws Exception {
        byte[] combined = Base64.getDecoder().decode(storedHash);
        byte[] salt = new byte[16];
        byte[] hash = new byte[combined.length - 16];
        System.arraycopy(combined, 0, salt, 0, 16);
        System.arraycopy(combined, 16, hash, 0, hash.length);
        
        String computedHash = hashPassword(password, salt);
        return computedHash.equals(storedHash);
    }
}

Digital Signatures

Pro Tip: Digital signatures ensure data authenticity and integrity.

Digital Signature Implementation


public class DigitalSignature {
    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
    
    private final PrivateKey privateKey;
    private final PublicKey publicKey;
    
    public DigitalSignature(KeyPair keyPair) {
        this.privateKey = keyPair.getPrivate();
        this.publicKey = keyPair.getPublic();
    }
    
    public String sign(String data) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        
        return Base64.getEncoder().encodeToString(signature.sign());
    }
    
    public boolean verify(String data, String signature) throws Exception {
        Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
        sig.initVerify(publicKey);
        sig.update(data.getBytes(StandardCharsets.UTF_8));
        
        return sig.verify(Base64.getDecoder().decode(signature));
    }
}

Key Management

Note: Proper key management is crucial for cryptographic security.

Key Management Implementation


public class KeyManager {
    private static final String KEYSTORE_TYPE = "PKCS12";
    private static final String KEYSTORE_PATH = "keystore.p12";
    private static final String KEYSTORE_PASSWORD = "changeit";
    
    private final KeyStore keyStore;
    
    public KeyManager() throws Exception {
        this.keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
        loadKeyStore();
    }
    
    private void loadKeyStore() throws Exception {
        File keystoreFile = new File(KEYSTORE_PATH);
        if (keystoreFile.exists()) {
            try (FileInputStream fis = new FileInputStream(keystoreFile)) {
                keyStore.load(fis, KEYSTORE_PASSWORD.toCharArray());
            }
        } else {
            keyStore.load(null, KEYSTORE_PASSWORD.toCharArray());
        }
    }
    
    public void saveKeyStore() throws Exception {
        try (FileOutputStream fos = new FileOutputStream(KEYSTORE_PATH)) {
            keyStore.store(fos, KEYSTORE_PASSWORD.toCharArray());
        }
    }
    
    public void storeKey(String alias, Key key, String password) throws Exception {
        keyStore.setKeyEntry(alias, key, password.toCharArray(), null);
        saveKeyStore();
    }
    
    public Key getKey(String alias, String password) throws Exception {
        return keyStore.getKey(alias, password.toCharArray());
    }
    
    public void deleteKey(String alias) throws Exception {
        keyStore.deleteEntry(alias);
        saveKeyStore();
    }
}

Best Practices

Pro Tip: Following cryptographic best practices ensures application security.

Cryptographic Best Practices

  • Use strong encryption algorithms
  • Implement proper key management
  • Use secure random number generation
  • Implement proper key rotation
  • Use appropriate key sizes
  • Implement proper error handling
  • Use secure key storage
  • Implement proper access controls
  • Use secure communication protocols
  • Implement proper logging
  • Use secure configuration management
  • Implement proper key backup
  • Use secure key exchange
  • Implement proper key recovery
  • Follow cryptographic standards

Conclusion

Cryptography is essential for securing data in Java applications. By implementing these cryptographic techniques and following best practices, developers can create more secure applications.