Sto tentando di crittografare e decodificare i dati utilizzando AES/GCM/NoPadding. Ho installato JCE Unlimited Strength Policy Files e ho seguito il benchmark (semplice) di seguito. Ho fatto lo stesso utilizzando OpenSSL ed è stato in grado di ottenere oltre il 1 GB/s crittografia e decrittografia sul mio PC.Lenta crittografia e decrittografia AES GCM con Java 8u20
Con il benchmark di seguito sono in grado di ottenere solo la crittografia e la decrittografia di 3 MB/s utilizzando Java 8 sullo stesso PC. Qualche idea su cosa sto facendo male?
public static void main(String[] args) throws Exception {
final byte[] data = new byte[64 * 1024];
final byte[] encrypted = new byte[64 * 1024];
final byte[] key = new byte[32];
final byte[] iv = new byte[12];
final Random random = new Random(1);
random.nextBytes(data);
random.nextBytes(key);
random.nextBytes(iv);
System.out.println("Benchmarking AES-256 GCM encryption for 10 seconds");
long javaEncryptInputBytes = 0;
long javaEncryptStartTime = System.currentTimeMillis();
final Cipher javaAES256 = Cipher.getInstance("AES/GCM/NoPadding");
byte[] tag = new byte[16];
long encryptInitTime = 0L;
long encryptUpdate1Time = 0L;
long encryptDoFinalTime = 0L;
while (System.currentTimeMillis() - javaEncryptStartTime < 10000) {
random.nextBytes(iv);
long n1 = System.nanoTime();
javaAES256.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(16 * Byte.SIZE, iv));
long n2 = System.nanoTime();
javaAES256.update(data, 0, data.length, encrypted, 0);
long n3 = System.nanoTime();
javaAES256.doFinal(tag, 0);
long n4 = System.nanoTime();
javaEncryptInputBytes += data.length;
encryptInitTime = n2 - n1;
encryptUpdate1Time = n3 - n2;
encryptDoFinalTime = n4 - n3;
}
long javaEncryptEndTime = System.currentTimeMillis();
System.out.println("Time init (ns): " + encryptInitTime);
System.out.println("Time update (ns): " + encryptUpdate1Time);
System.out.println("Time do final (ns): " + encryptDoFinalTime);
System.out.println("Java calculated at " + (javaEncryptInputBytes/1024/1024/((javaEncryptEndTime - javaEncryptStartTime)/1000)) + " MB/s");
System.out.println("Benchmarking AES-256 GCM decryption for 10 seconds");
long javaDecryptInputBytes = 0;
long javaDecryptStartTime = System.currentTimeMillis();
final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * Byte.SIZE, iv);
final SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
long decryptInitTime = 0L;
long decryptUpdate1Time = 0L;
long decryptUpdate2Time = 0L;
long decryptDoFinalTime = 0L;
while (System.currentTimeMillis() - javaDecryptStartTime < 10000) {
long n1 = System.nanoTime();
javaAES256.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
long n2 = System.nanoTime();
int offset = javaAES256.update(encrypted, 0, encrypted.length, data, 0);
long n3 = System.nanoTime();
javaAES256.update(tag, 0, tag.length, data, offset);
long n4 = System.nanoTime();
javaAES256.doFinal(data, offset);
long n5 = System.nanoTime();
javaDecryptInputBytes += data.length;
decryptInitTime += n2 - n1;
decryptUpdate1Time += n3 - n2;
decryptUpdate2Time += n4 - n3;
decryptDoFinalTime += n5 - n4;
}
long javaDecryptEndTime = System.currentTimeMillis();
System.out.println("Time init (ns): " + decryptInitTime);
System.out.println("Time update 1 (ns): " + decryptUpdate1Time);
System.out.println("Time update 2 (ns): " + decryptUpdate2Time);
System.out.println("Time do final (ns): " + decryptDoFinalTime);
System.out.println("Total bytes processed: " + javaDecryptInputBytes);
System.out.println("Java calculated at " + (javaDecryptInputBytes/1024/1024/((javaDecryptEndTime - javaDecryptStartTime)/1000)) + " MB/s");
}
EDIT: lascio come un esercizio divertente per migliorare questo semplice punto di riferimento mentalità.
Ho provato un po 'di più utilizzando ServerVM, rimosso le chiamate nanoTime e introdotto il riscaldamento, ma, come mi aspettavo, nessuna di queste ha avuto alcun miglioramento sui risultati del benchmark. È piatta a 3 megabyte al secondo.
In primo luogo, il benchmarking è sbagliato: nessun riscaldamento, singola iterazione, chiamate nanoTime eccessive. Le proprietà intrinseche di Hotspot per AES-NI sono utilizzate solo con un compilatore JIT ottimizzato, devi raggiungerlo prima di valutare le prestazioni. Secondo, prova AES/CBC. Misurate effettivamente aes-gcm con OpenSSL e vi ha dato 1 GB/s? –
Si noti inoltre che per utilizzare intrinseche AES-NI è necessario utilizzare la Server VM, una moderna CPU Intel con supporto, * e * per avere una sequenza di riscaldamento. Notare che OpenSSL è una delle librerie più veloci là fuori, il codice byte potrebbe essere relativamente veloce per la logica di business, ma per la crittografia si * vedranno differenze con librerie C/C++ ben implementate. –
Sì, lo so che questo non è il benchmark più robusto, ma 3 MB/s contro 1 GB/s è ancora molto significativo e ritengo che questo benchmark semplice sia abbastanza buono da portare il punto. Ho provato AES/CBC e sono in grado di ottenere più di 400 MB/s per la crittografia e più di 1 GB/s per la decrittografia utilizzando il codice Java. – Christo