Tengo una gran cantidad de datos muy pequeña (19 bytes) que necesitan ser encriptada y enviada a un servidor remoto a través de TCP en formato encriptado. Estoy utilizando el código de abajo para hacer esto.
package aesclient;
import java.io.OutputStream;
import java.net.Socket;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AESClient {
static byte[] plaintext = new byte[] {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53};
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 1337); // connecting to server on localhost
OutputStream outputStream = socket.getOutputStream();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
String s_key = "Random09" + "Random09"; // 16 Byte = 128 Bit Key
byte[] b_key = s_key.getBytes();
SecretKeySpec sKeySpec = new SecretKeySpec(b_key, "AES");
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] IV = new byte[16]; // initialization vector
int num = 10000;
long start = System.nanoTime();
for (int i = 0; i < num; ++i) {
random.nextBytes(IV);
IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec, ivSpec);
byte[] msg = new byte[16 + 32];
System.arraycopy(IV, 0, msg, 0, IV.length);
byte[] encrypted = cipher.doFinal(plaintext);
System.arraycopy(encrypted, 0, msg, IV.length, encrypted.length);
outputStream.write(msg);
outputStream.flush();
}
long end = System.nanoTime();
long duration = end - start;
double drate = ((double)plaintext.length*(double)num)/((double)duration/1000000000);
System.out.println("Verschlüsselung:\n" + num + " mal 19 Bytes in " + ((double)duration/1000000000) + " s\nData Rate = " + drate/1000.0 + " kBytes/s");
}
catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
Me pregunto por qué es extremadamente lento. Consigo una salida como esta:
Verschlüsselung:
10000 mal 19 Bytes in 2.566016627 s
Data Rate = 74.04472675694785 kBytes/s
lo que significa que tienen una tasa de datos de 74 kByte / s de los datos originales (sin cifrar). La velocidad de datos sólo aumenta insignificante si omito el envío a través de TCP (entonces se trata de 100KByte / s). He leído acerca de las tasas de datos que están alrededor 20MByte / s o incluso más. Tengo un portátil con Windows 10 e i5 procesador. Estaría agradecido por cualquier ayuda. Como ya he dicho, sólo hay que transferir una gran cantidad de pequeños paquetes de datos (19 byte) cifrados.
SecureRandom
es lento incluso en el modo de PRNG e incluso puede bloquear cuando no hay suficiente entropía está disponible.
Recomiendo abastecimiento de la IV aleatorio una vez y incrementándolo entre iteraciones similares a modo de CTR. O simplemente utilizar el modo CTR.
public class Test {
static byte[] plaintext = new byte[] { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
0x52, 0x53 };
public static void main(String[] args) {
try {
Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5PADDING");
String s_key = "Random09" + "Random09"; // 16 Byte = 128 Bit Key
byte[] b_key = s_key.getBytes();
SecretKeySpec sKeySpec = new SecretKeySpec(b_key, "AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte[] IV = new byte[16]; // initialization vector
random.nextBytes(IV);
int num = 10000;
long start = System.nanoTime();
for (int i = 0; i < num; ++i) {
IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec, ivSpec);
byte[] msg = new byte[16 + 32];
System.arraycopy(IV, 0, msg, 0, IV.length);
byte[] encrypted = cipher.doFinal(plaintext);
System.arraycopy(encrypted, 0, msg, IV.length, encrypted.length);
increment(IV);
}
long end = System.nanoTime();
long duration = end - start;
double drate = ((double) plaintext.length * (double) num) / ((double) duration / 1000000000);
System.out.println("Verschlüsselung:\n" + num + " mal 19 Bytes in " + ((double) duration / 1000000000) + " s\nData Rate = " + drate
/ 1000.0 + " kBytes/s");
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
private static void increment(byte[] iv) {
for (int i=0; i<4; ++i) {
if (++iv[i] != 0)
break;
}
}
}
Huellas dactilares:
Verschlüsselung:
10000 mal 19 Bytes in 0.0331898 s
Data Rate = 5724.650344382912 kBytes/s
Por lo menos 30 veces más rápido en mi máquina.