Lent AES GCM chiffrement et le déchiffrement de Java 8u20

Je suis en train de chiffrer et déchiffrer les données en utilisant AES/GCM/NoPadding. J'ai installé la JCE Force Illimitée de la Politique de Fichiers et a couru la (les simples d'esprit) de référence ci-dessous. J'ai fait la même à l'aide d'OpenSSL et a été en mesure d'atteindre plus de 1 GB/s de chiffrement et de déchiffrement sur mon PC.

Avec la référence ci-dessous, je suis seulement en mesure d'obtenir 3 MO/s de chiffrement et de déchiffrement à l'aide de Java 8 sur le même PC. Toute idée de ce que je fais de mal?

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:
Je laisse comme un exercice amusant pour améliorer ce simple d'esprit indice de référence.

J'en ai testé quelques uns de plus à l'aide de la ServerVM, retiré nanoTime appels et introduit de chauffe, mais comme je m'y attendais rien de cela n'a eu aucune amélioration sur les résultats de la référence. Il est plafonné à 3 mégaoctets par seconde.

  • Tout d'abord, l'analyse comparative est faux: pas de warm-up, seule itération, excessive nanoTime appels. Zone intrinsèques de l'AES-NI sont utilisés uniquement avec une optimisation de compilateur JIT, vous devez y arriver avant l'évaluation de la performance. Ensuite, essayez de AES/CBC. Pensez-vous réellement mesurer aes-gcm avec OpenSSL, et il vous a donné 1 GB/s?
  • Notez aussi que pour utiliser AES-NI intrinsèques, il est nécessaire d'utiliser le Serveur de VM, un moderne type de PROCESSEUR Intel, avec le soutien, et d'avoir un échauffement de la séquence. Notez que OpenSSL est l'un des plus rapides libs y, byte code peut être relativement rapide pour la logique métier, mais pour la cryptographie, vous verrez les différences avec bien mis en œuvre bibliothèques C/C++.
  • Oui je sais que ce n'est pas le plus solide de référence, mais à 3 MO/s vs 1 GB/s est encore très important et je sens que cette simpleminded de référence est assez bon pour donner le point à travers. J'ai essayé AES/CBC et je suis en mesure d'obtenir plus de 400 MO/s pour le chiffrement et plus de 1 GO/s pour le décryptage à l'aide de Java de l'algorithme de chiffrement.
  • Je suis en train d'écrire mon propre JavaFX/Java EE de l'application de test avec un impressionnant GUI qui vont à travers l'ensemble du processus d'authentification d'un utilisateur à l'aide de PRS et ensuite envoyer des fichiers cryptés sur WebSocket en utilisant AES/GCM. Je vais revenir avec un lien lorsque l'application est faite. Mais pour l'instant, tout ce que je voulais dire, c'est que, par rapport chiffré de transfert de fichier, en utilisant AES/GCM est environ 10 fois plus lent pour moi (96 bits d'authentification balise de 128 bits, la clé & IV).
  • vous n'avez pas le Illimité de la Force de la Compétence de la Politique de Fichiers installé.
InformationsquelleAutor Christo | 2014-09-23