Of course. Comparing AES implementation in Java and Delphi is a great topic, as it highlights different approaches to cryptography in modern programming languages. Here’s a detailed breakdown covering the concepts, code examples, and key differences.

The Core Concept: AES is an Algorithm, Not a Class
First, a crucial point: AES (Advanced Encryption Standard) is a symmetric block cipher algorithm. It's a set of mathematical rules for encrypting and decrypting data.
When you use a library like Java's javax.crypto or Delphi's System.TIdEncryption, you are not using the "AES class" directly. Instead, you are using a class that implements the AES algorithm. This class is usually part of a higher-level construct, like a Cipher (Java) or a Stream (Delphi).
The process always involves:
- Key: A secret key used for both encryption and decryption.
- Mode of Operation: How the blocks of data are chained together (e.g., CBC, GCM, CTR). This is critical for security.
- Padding: How data that isn't a multiple of the block size (128 bits) is handled (e.g., PKCS#7, NoPadding).
- Initialization Vector (IV): A random value used in certain modes (like CBC) to ensure encrypting the same plaintext multiple times produces different ciphertexts. The IV is not secret and must be transmitted with the ciphertext.
Java Implementation (javax.crypto)
Java has a robust, built-in cryptography API. The main classes you'll interact with are:

javax.crypto.SecretKey: Represents the secret key.javax.crypto.Cipher: The workhorse class that performs the actual encryption and decryption.javax.crypto.KeyGenerator: Used to generate a new random key.javax.crypto.spec.SecretKeySpec: Allows you to create a key from a raw byte array.javax.crypto.spec.IvParameterSpec: Specifies the Initialization Vector.
Example: AES-256 in CBC Mode with PKCS#5 Padding
This is a common and secure mode for encrypting data that is not a stream.
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
public class AesExample {
public static void main(String[] args) throws Exception {
String plainText = "This is a secret message.";
String keyString = "ThisIsASecretKey123456"; // Must be 16, 24, or 32 bytes for AES-128, 192, 256
// 1. Generate a random IV (16 bytes for AES)
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// 2. Create the key from a string
byte[] keyBytes = keyString.getBytes(StandardCharsets.UTF_8);
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
// 3. Setup the Cipher for encryption
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
// 4. Encrypt the data
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
// 5. Combine IV and ciphertext for storage/transmission
// The IV is not secret, so it's stored with the ciphertext.
byte[] combined = new byte[iv.length + encryptedBytes.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encryptedBytes, 0, combined, iv.length, encryptedBytes.length);
String encryptedBase64 = Base64.getEncoder().encodeToString(combined);
System.out.println("Encrypted (Base64): " + encryptedBase64);
// --- Decryption ---
// 1. Decode the combined data
byte[] combinedDecoded = Base64.getDecoder().decode(encryptedBase64);
// 2. Extract the IV and ciphertext
byte[] extractedIv = new byte[16];
byte[] cipherText = new byte[combinedDecoded.length - 16];
System.arraycopy(combinedDecoded, 0, extractedIv, 0, extractedIv.length);
System.arraycopy(combinedDecoded, extractedIv.length, cipherText, 0, cipherText.length);
// 3. Setup the Cipher for decryption
IvParameterSpec extractedIvSpec = new IvParameterSpec(extractedIv);
Cipher decipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, secretKey, extractedIvSpec);
// 4. Decrypt the data
byte[] decryptedBytes = decipher.doFinal(cipherText);
String decryptedText = new String(decryptedBytes, StandardCharsets.UTF_8);
System.out.println("Decrypted: " + decryptedText);
}
}
Delphi Implementation
Delphi's standard library does not have a built-in, high-level cryptography API like Java's javax.crypto. The most common and robust solution is to use a third-party library. Indy (TId... components) is very popular, but it's considered legacy. A more modern and recommended library is OpenSSL4Pascal.
Using OpenSSL4Pascal (Recommended)
This library provides a clean, object-oriented interface to the OpenSSL library, which is the industry standard.
-
Install: Use the GetIt package manager in Delphi to install
OpenSSL4Pascal.
(图片来源网络,侵删) -
Code Example: AES-256 in CBC Mode
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, OpenSSL4Pascal, System.StrUtils;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
PlainText: string;
KeyString: string;
Cipher: TIdEVP_CIPHER;
Encryptor: TIdEVP_CIPHER_CTX;
Key, IV: TBytes;
EncryptedBytes, FinalBytes: TBytes;
Base64Str: string;
begin
PlainText := 'This is a secret message.';
KeyString := 'ThisIsASecretKey123456'; // 32 bytes for AES-256
// 1. Setup the Cipher (AES-256 in CBC mode with PKCS#7 padding)
Cipher := TIdEVP_CIPHER.Create(EVP_aes_256_cbc);
try
// 2. Create the key and IV
// Key must be 256 bits (32 bytes)
Key := TEncoding.UTF8.GetBytes(KeyString);
// IV must be 128 bits (16 bytes)
SetLength(IV, 16);
RandomBytes(IV); // Helper function to generate random bytes
// 3. Initialize the encryption context
Encryptor := TIdEVP_CIPHER_CTX.Create;
try
Encryptor.InitEncrypt(Key, IV);
// 4. Encrypt the data
SetLength(EncryptedBytes, Encryptor.BlockSize);
FinalBytes := nil;
Encryptor.Update(TEncoding.UTF8.GetBytes(PlainText), EncryptedBytes, FinalBytes);
Encryptor.Final(EncryptedBytes, FinalBytes);
// Combine IV and ciphertext for storage/transmission
FinalBytes := IV + FinalBytes;
// 5. Encode to Base64 for easy transport
Base64Str := TNetEncoding.Base64.EncodeBytes(FinalBytes);
ShowMessage('Encrypted (Base64): ' + Base64Str);
// --- Decryption ---
// 1. Decode from Base64
FinalBytes := TNetEncoding.Base64.DecodeString(Base64Str);
// 2. Extract IV and ciphertext
SetLength(IV, 16);
Move(FinalBytes[0], IV[0], 16);
SetLength(FinalBytes, Length(FinalBytes) - 16);
// 3. Initialize the decryption context
Encryptor.InitDecrypt(Key, IV);
// 4. Decrypt the data
SetLength(EncryptedBytes, Encryptor.BlockSize);
var DecryptedBytes: TBytes;
Encryptor.Update(FinalBytes, EncryptedBytes, DecryptedBytes);
Encryptor.Final(EncryptedBytes, DecryptedBytes);
// 5. Convert back to string
var DecryptedText := TEncoding.UTF8.GetString(DecryptedBytes);
ShowMessage('Decrypted: ' + DecryptedText);
finally
Encryptor.Free;
end;
finally
Cipher.Free;
end;
end;
// Helper function to generate random bytes
procedure RandomBytes(var Bytes: TBytes);
var
HCryptProv: Cardinal;
Buffer: PByte;
I: Integer;
begin
if CryptAcquireContext(@HCryptProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_SILENT) then
try
SetLength(Bytes, Length(Bytes));
Buffer := PByte(Bytes);
CryptGenRandom(HCryptProv, Length(Bytes), Buffer);
finally
CryptReleaseContext(HCryptProv, 0);
end;
end;
end.
Key Differences and Summary
| Feature | Java (javax.crypto) |
Delphi (OpenSSL4Pascal) |
|---|---|---|
| Availability | Built-in. No external libraries needed. | Requires a third-party library. OpenSSL4Pascal is the modern standard. |
| API Style | Procedural/OOP. Cipher.getInstance("AES/CBC/PKCS5Padding") is a factory method. |
Object-Oriented. TIdEVP.Create(EVP_aes_256_cbc) is a constructor. |
| Key/IV Handling | Uses specific classes: SecretKeySpec, IvParameterSpec. |
Passes raw TBytes for Key and IV to the cipher context. |
| Mode/Padding | Specified as a single string in Cipher.getInstance(). |
Specified by passing a constant (e.g., EVP_aes_256_cbc) which implies the mode. |
| Data Handling | doFinal() on a byte array. Returns the final encrypted bytes. |
Update() and Final() methods. You manage byte arrays yourself. |
| Modern Modes (AEAD) | Excellent support. AES/GCM/NoPadding is straightforward. |
Excellent support. TIdEVP_AES_GCM is available for authenticated encryption. |
| Ease of Use | Generally considered easier and more consistent for standard operations. | More manual memory management of byte arrays, but very powerful once you learn the pattern. |
Critical Best Practices (For Both Languages)
- NEVER Roll Your Own Crypto: Always use a well-vetted, standard library like the ones shown above.
- Use Strong Modes: Avoid ECB mode. Use modes like GCM (Galois/Counter Mode) or CBC with a strong padding scheme. GCM is preferred for new applications as it provides both confidentiality and authentication.
- IV Must Be Unique: For a given key, the IV must never be reused for two different messages. A random IV is the standard and safest approach.
- IV is Not Secret: Store the IV alongside the ciphertext. It does not need to be protected.
- Key Management is Hard: Storing keys securely is one of the hardest parts of cryptography. For simple applications, a key derived from a password using a Key Derivation Function (KDF) like PBKDF2 or Argon2 is better than a raw string.
- Handle Exceptions: Cryptographic operations can fail (e.g., bad padding, wrong key length). Always wrap your code in
try...catch(Java) ortry...finally(Delphi).
