library - java aes cbc encryption
Java AES/GCM/NoPadding-¿Qué es cipher.getIV() dándome? (1)
Estoy utilizando encriptación AES/GCM/NoPadding
en Java 8 y me pregunto si mi código tiene un defecto de seguridad. Mi código parece funcionar , ya que encripta y descifra el texto, pero algunos detalles no están claros.
Mi pregunta principal es esta:
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????
¿Cumple ese IV el requisito de "Para una clave dada, el IV NO DEBE repetirse"? de RFC 4106 ?
También agradecería cualquier respuesta / idea para mis preguntas relacionadas (ver a continuación), pero esa primera pregunta me está molestando más. No sé dónde encontrar el código fuente o la documentación que responde esto.
Aquí está el código completo, aproximadamente. Me disculpo en caso de que haya introducido errores al escribir esta publicación:
class Encryptor {
Key key;
Encryptor(byte[] key) {
if (key.length != 32) throw new IllegalArgumentException();
this.key = new SecretKeySpec(key, "AES");
}
// the output is sent to users
byte[] encrypt(byte[] src) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // See question #1
assert iv.length == 12; // See question #2
byte[] cipherText = cipher.doFinal(src);
assert cipherText.length == src.length + 16; // See question #3
byte[] message = new byte[12 + src.length + 16]; // See question #4
System.arraycopy(iv, 0, message, 0, 12);
System.arraycopy(cipherText, 0, message, 12, cipherText.length);
return message;
}
// the input comes from users
byte[] decrypt(byte[] message) throws Exception {
if (message.length < 12 + 16) throw new IllegalArgumentException();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, key, params);
return cipher.doFinal(message, 12, message.length - 12);
}
}
Supongamos que los usuarios descifran mi clave secreta = juego terminado.
Preguntas más detalladas / preguntas relacionadas:
¿Es seguro que pueda usar la IV devuelta por cipher.getIV () de esta manera?
- ¿Evita la catástrofe de reutilizar la combinación de teclas IV en el modo Galois / Counter?
- ¿Todavía es seguro cuando tengo varias aplicaciones ejecutando este código a la vez, todas mostrando mensajes encriptados a usuarios de los mismos datos src (posiblemente en el mismo milisegundo)?
- ¿De qué está hecha la IV? ¿Es un contador atómico más algún ruido aleatorio?
- ¿Debo evitar
cipher.getIV()
y construir una IV, con mi propio contador? - ¿Está el código fuente implementando
cipher.getIV()
disponible en línea en alguna parte, suponiendo que estoy usando la extensión Oracle JDK 8 + JCE Unlimited Strength?
¿Ese IV siempre tiene 12 bytes de largo?
¿La etiqueta de autenticación siempre tiene 16 bytes (128 bits) de largo?
Con # 2 y # 3, y la falta de relleno, ¿eso significa que mis mensajes cifrados siempre son
12 + src.length + 16
bytes de largo? (¿Y entonces puedo aplastarlos de forma segura en una matriz de bytes, para lo cual sé la longitud correcta?)¿Es seguro para mí mostrar un número ilimitado de encriptación de datos src a los usuarios, dados los datos src constantes que los usuarios conocen?
¿Es seguro para mí mostrar un número ilimitado de cifrados de datos src a los usuarios, si los datos src son diferentes cada vez (por ejemplo, incluyendo
System.currentTimeMillis()
o números aleatorios)?¿Me ayudaría si rellenara los datos src con números aleatorios antes del cifrado? Diga 8 bytes al azar en frente y atrás, o solo en un extremo? ¿O eso no ayudaría para nada / empeoraría mi encriptación?
(Debido a que estas preguntas tienen que ver con el mismo bloque de mi propio código, y están fuertemente relacionadas entre sí, y otros podrían / deberían tener el mismo conjunto de preguntas al implementar la misma funcionalidad, se sintió mal dividir las preguntas en múltiples mensajes. Puedo volver a publicarlos por separado si es más apropiado para el formato de StackOverflow. ¡Avísame!)
Q1: ¿Es seguro para mí usar el IV devuelto por cipher.getIV () de esta manera?
Sí, es al menos para la implementación provista por Oracle. Se genera por separado utilizando la implementación predeterminada de SecureRandom
. Como tiene 12 bytes de tamaño (el valor predeterminado para GCM), entonces tiene 96 bits de aleatoriedad. La probabilidad de que el contador se repita es abismalmente pequeña. Puede buscar el origen en OpenJDK (GPL''ed) en el que se basa Oracle JDK.
Sin embargo, todavía te recomiendo que generes tus propios 12 bytes aleatorios ya que otros proveedores pueden comportarse de manera diferente.
Q2: ¿Es IV siempre 12 bytes de largo?
Es muy probable ya que es el valor predeterminado de GCM, pero otras longitudes son válidas para GCM. Sin embargo, el algoritmo tendrá que hacer cálculos adicionales para cualquier tamaño distinto de 12 bytes. Debido a las deficiencias, se recomienda encarecidamente mantenerlo en 12 bytes / 96 bits y las API pueden restringirlo a esa opción de tamaño IV .
Q3: ¿La etiqueta de autenticación siempre tiene 16 bytes (128 bits) de largo?
No, puede tener cualquier tamaño en bytes que van desde 64 bits a 128 bits con incrementos de 8 bits. Si es más pequeño, simplemente consiste en los bytes más a la izquierda de la etiqueta de autenticación. Puede especificar otro tamaño de etiqueta usando GCMParameterSpec
como tercer parámetro para su llamada de init
.
Tenga en cuenta que la fuerza de GCM depende en gran medida del tamaño de la etiqueta. Yo recomendaría mantenerlo en 128 bits. 96 bits debe ser el mínimo, especialmente si desea generar una gran cantidad de texto cifrado.
Q4: con # 2 y # 3, y la falta de relleno, ¿significa eso que mis mensajes cifrados siempre son 12 + src.length + 16 bytes de largo? (¿Y entonces puedo aplastarlos de forma segura en una matriz de bytes, para lo cual sé la longitud correcta?)
Véase más arriba. Para el proveedor de Oracle este es el caso. Use GCMParameterSpec
para estar seguro de ello.
P5: ¿Es seguro para mí mostrar un número ilimitado de encriptación de datos src a los usuarios, dados los datos src constantes que los usuarios conocen?
Virtualmente desatado, sí. Comenzaría a preocuparme por aproximadamente 2 ^ 48 encriptaciones. En general, sin embargo, debe diseñar para el cambio clave.
P6: ¿Es seguro para mí mostrar un número ilimitado de cifrados de datos src a los usuarios, si los datos src son diferentes todas las veces (por ejemplo, incluyendo System.currentTimeMillis () o números aleatorios)?
Ver respuesta a Q5
P7: ¿Sería útil si rellenara los datos src con números aleatorios antes del cifrado? Diga 8 bytes al azar en frente y atrás, o solo en un extremo? ¿O eso no ayudaría para nada / empeoraría mi encriptación?
No, no ayudaría en absoluto. GCM usa el modo CTR debajo, por lo que solo se cifraría con la transmisión de la clave. No actuaría como un IV. Si necesita una cantidad prácticamente ilimitada de textos cifrados (¡más de 2 ^ 48!), Le sugiero que use ese número aleatorio y su clave para una función de derivación de tecla o KDF. HKDF es actualmente la mejor de su clase, pero es posible que necesite usar Bouncy Castle o implementarlo usted mismo.