No hay comprobaciones de integridad, para estas razones particulares
- la necesidad no es evidente a partir del caso de uso.
"AES/GCM/NoPadding"
modo solo está disponible desde Java 7 en adelante
- Depende del usuario si desea implementar, p. HMAC y/o AESCMAC (recomendado).
- Necesitará una clave adicional como mínimo y dos pases completos.
Si tiene una implementación del modo GCM en ambos lados, p. Ej. usando Bouncy Castle en Java 6 - por favor, porque es mucho más seguro (siempre que el "IV" sea realmente único). Debería ser realmente fácil cambiar la implementación.
notas de aplicación en materia de cifrado
- Esta aplicación no es segura cuando se utilizan en un papel de cliente/servidor sin restricciones debido a los ataques del oráculo de relleno (se requieren 128 intentos por byte o menor, en promedio, independientemente de algoritmo o tamaño de clave). Tendrá que usar un MAC, HMAC o Signature sobre los datos cifrados, y verificarlo antes de descifrarlo para implementarlo en modo cliente/servidor.
- El descifrado devolverá nulo si falla el descifrado. Esto solo puede indicar una excepción de relleno, que debe manejarse adecuadamente (¿advertí sobre los ataques oracle de relleno?)
- Las claves inválidas se devolverán como
InvalidArgumentException
.
- Todas las demás excepciones relacionadas con la seguridad están "barridas debajo de la tabla", ya que significa que el entorno de ejecución de Java no es válido. Por ejemplo, admitir
"UTF-8"
y "AES/CBC/PKCS5Padding"
es requiere para cada implementación de Java SE.
Algunas otras notas
- favor, no intente lo contrario e insertar bytes directamente en la cadena de entrada del método de cifrar (utilizando
new String(byte[])
por ejemplo). ¡El método puede fallar silenciosamente!
- Optimizado para facilitar la lectura. Vaya a las implementaciones de transmisión Base64 y
CipherStream
si prefiere la velocidad y una mejor huella de memoria.
- Necesita al menos Java 6 SE o compatible para ejecutar este código.
- cifrado/descifrado puede fallar por tamaños de clave AES de 128 bits más a medida que puede necesitar los archivos de política para el cifrado sin restricciones (disponibles en Oracle)
- Cuidado con las regulaciones gubernamentales al exportar cifrado.
- Esta implementación utiliza llaves hexadecimales en lugar de las teclas base64 ya que son lo suficientemente pequeñas, y el hexadecimal es simplemente más fácil de editar/verificar manualmente.
- Codificación/decodificación hexadecimal y base64 utilizadas recuperadas del JDK, no se necesitan bibliotecas externas de ningún tipo.
- Uber simple de usar, pero, por supuesto, no muy orientado a objetos, no hay almacenamiento en caché de las instancias de objeto utilizadas en el cifrado/descifrado. Refactor a voluntad.
bien, aquí viene algo de código ...
public static String encrypt(final String plainMessage,
final String symKeyHex) {
final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);
final byte[] encodedMessage = plainMessage.getBytes(Charset
.forName("UTF-8"));
try {
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final int blockSize = cipher.getBlockSize();
// create the key
final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");
// generate random IV using block size (possibly create a method for
// this)
final byte[] ivData = new byte[blockSize];
final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
rnd.nextBytes(ivData);
final IvParameterSpec iv = new IvParameterSpec(ivData);
cipher.init(Cipher.ENCRYPT_MODE, symKey, iv);
final byte[] encryptedMessage = cipher.doFinal(encodedMessage);
// concatenate IV and encrypted message
final byte[] ivAndEncryptedMessage = new byte[ivData.length
+ encryptedMessage.length];
System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage,
blockSize, encryptedMessage.length);
final String ivAndEncryptedMessageBase64 = DatatypeConverter
.printBase64Binary(ivAndEncryptedMessage);
return ivAndEncryptedMessageBase64;
} catch (InvalidKeyException e) {
throw new IllegalArgumentException(
"key argument does not contain a valid AES key");
} catch (GeneralSecurityException e) {
throw new IllegalStateException(
"Unexpected exception during encryption", e);
}
}
public static String decrypt(final String ivAndEncryptedMessageBase64,
final String symKeyHex) {
final byte[] symKeyData = DatatypeConverter.parseHexBinary(symKeyHex);
final byte[] ivAndEncryptedMessage = DatatypeConverter
.parseBase64Binary(ivAndEncryptedMessageBase64);
try {
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final int blockSize = cipher.getBlockSize();
// create the key
final SecretKeySpec symKey = new SecretKeySpec(symKeyData, "AES");
// retrieve random IV from start of the received message
final byte[] ivData = new byte[blockSize];
System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
final IvParameterSpec iv = new IvParameterSpec(ivData);
// retrieve the encrypted message itself
final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length
- blockSize];
System.arraycopy(ivAndEncryptedMessage, blockSize,
encryptedMessage, 0, encryptedMessage.length);
cipher.init(Cipher.DECRYPT_MODE, symKey, iv);
final byte[] encodedMessage = cipher.doFinal(encryptedMessage);
// concatenate IV and encrypted message
final String message = new String(encodedMessage,
Charset.forName("UTF-8"));
return message;
} catch (InvalidKeyException e) {
throw new IllegalArgumentException(
"key argument does not contain a valid AES key");
} catch (BadPaddingException e) {
// you'd better know about padding oracle attacks
return null;
} catch (GeneralSecurityException e) {
throw new IllegalStateException(
"Unexpected exception during decryption", e);
}
}
Uso:
String plain = "Zaphod's just zis guy, ya knöw?";
String encrypted = encrypt(plain, "000102030405060708090A0B0C0D0E0F");
System.out.println(encrypted);
String decrypted = decrypt(encrypted, "000102030405060708090A0B0C0D0E0F");
if (decrypted != null && decrypted.equals(plain)) {
System.out.println("Hey! " + decrypted);
} else {
System.out.println("Bummer!");
}
El 'KeyGenerator kgen' no se usa nunca. ¿Qué está haciendo eso allí? Un 'KeyGenerator' se utiliza para elegir una nueva clave aleatoria. Pero parece que desea reutilizar una clave existente que de alguna manera está almacenada en un 'String' (¿Base-64 codificada, quizás?) – erickson