2009-12-17 11 views
14

Para el cifrado utilizo algo como esto:manera fácil de almacenar/restaurar la clave de cifrado para descifrar la cadena en Java

SecretKey aesKey = KeyGenerator.getInstance("AES").generateKey(); 
StringEncrypter aesEncrypt = new StringEncrypter(aesKey, aesKey.getAlgorithm()); 
String aesEncrypted= aesEncrypt.encrypt(StringContent); 

Si imprimo aesKey me sale: "[email protected]" .

Así que para el cifrado me gustaría pedirle al usuario la clave, pero no sé cómo y qué formato debería ser. Mi plan era algo como esto:

SecretKey aesKey = [email protected]; 
StringEncrypter aesEncrypt = new StringEncrypter(aesKey, aesKey.getAlgorithm()); 
String aesDecrypt = aesEncrypt.decrypt(aesEncrypted); 

Pero parece no su trabajo. ¿Hay alguna manera fácil de imprimir la clave después del cifrado en la consola para que el usuario pueda guardarla (o recordarla) y luego usar para descifrar?

Todo el código está aquí: Cannot decrypt cyphertext from text file, symmetric key implement. in java Así que lo siento por publicar de nuevo, pero no estoy seguro si el código es incluso legible (soy novato).

+0

favor ver mi respuesta actualizada. – erickson

Respuesta

0

Sólo como referencia, la salida que se está viendo es el resultado del método predeterminado toString y el número divertida en la final es un código hash. Ver here. Los códigos Hash son, por diseño, no reversibles, y no se garantiza necesariamente que toString le proporcione suficiente información para reconstruir el objeto original (aunque sí lo hace para ciertas clases).

12

La mayoría de las instancias de Java Key se representan como una cadena de bytes resultante de su método getEncoded(). Esto es lo que necesita ser almacenado para reconstruir la clave más tarde.

Sin embargo, para almacenar una clave de forma segura en forma electrónica, debe ser encriptada. Por supuesto, encriptar la clave requeriría otra clave (o contraseña) & hellip; y entonces tienes una regresión infinita. Un Java KeyStore se puede usar para almacenar objetos SecretKey de esta manera, y eso es útil cuando tiene muchas claves secretas que están todas protegidas por una sola contraseña "maestra". Pero para proteger una sola clave, no tiene mucho sentido.

Una alternativa es presentar la clave al usuario en una forma que se pueda almacenar de una manera segura (en muchas aplicaciones, que podría estar en un trozo de papel en su billetera). Esto podría ser tan simple como mostrar los bytes de la clave codificada en hexadecimal, Base-64 u otra codificación de texto, y pedirle al usuario que la escriba.

Otro enfoque es permitir al usuario elegir una contraseña memorable y generar una clave con eso, utilizando un algoritmo como PBKDF2. Sin embargo, la sal (y quizás el recuento de iteraciones) utilizada para la derivación de claves debería registrarse en algún lugar. Otro inconveniente es que las personas tienden a elegir entre un número relativamente limitado de contraseñas del total disponible. Por lo tanto, las claves derivadas de las contraseñas pueden ser más fáciles de adivinar de lo que sugiere el tamaño de la clave.


Aquí hay una ilustración de la técnica básica para conservar y reconstituir una clave secreta.

byte[] encoded = aesKey.getEncoded(); 
/* Now store "encoded" somewhere. For example, display the key and 
    ask the user to write it down. */ 
String output = Base64.getEncoder().withoutPadding().encodeToString(encoded); 
System.out.println("Keep it secret, keep it safe! " + output); 

... 

/* At some point, you need to reconstitute the key. Let's say the user 
    enters it as a base-64 number that you convert to bytes. */ 
String input = ... ; 
byte[] encoded = Base64.getDecoder().decode(input); 
SecretKey aesKey = new SecretKeySpec(encoded, "AES"); 
+0

Gracias por la explicación. Pero ¿cómo puedo llamar a la clave en lugar de generarla? (KeyGenerator.getInstance ("AES"). GenerateKey();)? Ahora puedo imprimir la clave con getEncoded(), el usuario la escribirá. Pero, ¿cómo devuelvo la llamada? – dave91

+0

Veo lecturas incoherentes con la nueva porción BigInteger (entrada, 16) .toByteArray() de este código. La mayoría de las veces está leyendo en 17bytes y me da un error de "longitud de clave de aes inválida: 17 bytes" cuando intento usarlo. ¿Qué podría causar esto? – sapatos

+2

@sapatos si se establece el bit alto de la clave, 'BigInteger' agregará un byte cero al comienzo de la matriz de bytes para evitar que se interprete como un número negativo. Tal vez en lugar de 'nuevo BigInteger (1, codificado)', debe permitir que la cadena sea un número negativo: 'nuevo BigInteger (codificado)' – erickson

20

He tenido que hacer esto recientemente. Y mientras que las otras respuestas aquí me llevaron en la dirección correcta, podría haber sido más fácil. Así que aquí está mi "compartir" por el día, un par de métodos de ayuda para la manipulación simple de claves AES.(Tenga en cuenta la dependencia de Apache Commons y Codec.)

Esto es todo en un repositorio git ahora: github.com/stuinzuri/SimpleJavaKeyStore

import static org.apache.commons.codec.binary.Hex.*; 
import static org.apache.commons.io.FileUtils.*; 
import java.io.*; 
import java.security.NoSuchAlgorithmException; 
import javax.crypto.*; 
import org.apache.commons.codec.DecoderException; 

public static SecretKey generateKey() throws NoSuchAlgorithmException 
{ 
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); 
    keyGenerator.init(256); // 128 default; 192 and 256 also possible 
    return keyGenerator.generateKey(); 
} 

public static void saveKey(SecretKey key, File file) throws IOException 
{ 
    char[] hex = encodeHex(key.getEncoded()); 
    writeStringToFile(file, String.valueOf(hex)); 
} 

public static SecretKey loadKey(File file) throws IOException 
{ 
    String data = new String(readFileToByteArray(file)); 
    byte[] encoded; 
    try { 
     encoded = decodeHex(data.toCharArray()); 
    } catch (DecoderException e) { 
     e.printStackTrace(); 
     return null; 
    } 
    return new SecretKeySpec(encoded, "AES"); 
} 
+2

¿No fallará si la matriz devuelta por 'getEncoded()' tiene bytes nulos iniciales o si el primer byte tiene el bit más alto establecido? –

+0

@NiklasB. Corregido, gracias por señalarlo. –

+1

_I soy un fanático de las funciones de utilidad estáticas y las importaciones estáticas_ :) –

Cuestiones relacionadas