cifrado AES ¿necesito usar un Modo?

3

Actualmente estoy trabajando en un programa de cifrado de archivos usando Java Cryptography Architecture.

Mi plan es tener una serie de archivos cifrados donde cada archivo tenga una clave AES diferente. Para realizar un seguimiento de los archivos cifrados también incluyo un archivo de metadatos que almacena una entrada para cada archivo cifrado con los siguientes valores: nombre de archivo de texto sin formato, nombre de archivo cifrado y clave AES.

El archivo de metadatos se encripta utilizando una clave AES que se deriva de la contraseña del usuario.

Mi pregunta es ¿Debo implementar un modo? y ¿cree que mantener todas las contraseñas en los metadatos cifrados es una práctica aceptable?

Aquí está el código al que me he referido:

public class PasswordBasedEncryption {

PBEKeySpec pbeKeySpec;
PBEParameterSpec pbeParamSpec;
SecretKeyFactory keyFac;

// Salt
byte[] salt = {
        (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
        (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};
// Iteration count
int count = 65536;
int keySize = 128;

Cipher pbeCipher;
SecretKey pbeKey;
FileInputStream fis;
FileOutputStream fos;

/**
 * constructor given a master password
 * Use password based derivation function II to make AES key.
 * used only for the metadata file encryption
 * @param password
 */
public PasswordBasedEncryption(char[] password){
    try{
        keyFac = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        pbeKeySpec = new PBEKeySpec(password, salt, count, keySize);
        SecretKey tempKey = keyFac.generateSecret(pbeKeySpec);
        pbeKey = new SecretKeySpec(tempKey.getEncoded(), "AES");
        pbeCipher = Cipher.getInstance("AES");
    }
    catch (Exception e){e.printStackTrace();}
}
/**
 * constructor given a generated AES key
 * each file has its own AES key to avoid known text attacks
 * @param key
 */
public PasswordBasedEncryption(SecretKey key){
    try{
        pbeKey = key;
    }
    catch (Exception e){e.printStackTrace();}
}

public void encrypt(String filePath, String cipherName){
    try{
        File clearFile = new File(filePath);
        fis = new FileInputStream(clearFile);

        pbeCipher = Cipher.getInstance("AES");
        pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey);

        CipherInputStream cis = new CipherInputStream(fis, pbeCipher);          
        File cipherFile = new File(Path.TEMP + cipherName);
        fos = new FileOutputStream(cipherFile);
        int read;
        while((read = cis.read())!=-1)
        {
            fos.write((char)read);
            fos.flush();
        } 
        cis.close();
        fos.close();
        fis.close();
    }
    catch(Exception e ){e.printStackTrace();}
}

public void decrypt(String cipherName, String filePath){
    try{

        fis = new FileInputStream(Path.TEMP + cipherName);          
        File clearFile = new File(filePath);
        fos = new FileOutputStream(clearFile);

        pbeCipher = Cipher.getInstance("AES");
        pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey);
        CipherOutputStream cos = new CipherOutputStream(fos, pbeCipher);            
        int read;
        while((read = fis.read())!=-1)
        {
            cos.write(read);
            cos.flush();
        } 
        cos.close();
        fis.close();
        fos.close();
    }
    catch(Exception e ){e.printStackTrace();}
}


/**
 * Generate secret password used each time a new file needs encrypting
 * @return
 */
public static SecretKey genPass(){
    KeyGenerator keyGen;
    try {
        keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(128);
        return keyGen.generateKey();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}
}
    
pregunta John 01.05.2014 - 15:52
fuente

3 respuestas

9

AES es un cifrado de bloque : toma como entrada una clave y un bloque de exactamente 16 bytes , y genera otro bloque de 16 bytes. Ese es el alcance de lo que hace AES en sí.

Entonces, si desea cifrar una secuencia de bytes que no es un solo bloque de 16 bytes, debe usar un " modo de funcionamiento ". Y eso es lo que ya estás haciendo en tu código. Simplemente no lo especificaste en tu código y dejaste que Java seleccionara uno por ti. Desafortunadamente, el valor predeterminado puede ser el BCE, que es atroz y débil; consulte este documento que incluye lo siguiente:

  

Por ejemplo, el proveedor SunJCE usa ECB como modo predeterminado y PKCS5Padding como esquema de relleno predeterminado para cifrados DES, DES-EDE y Blowfish.

(No hay información sobre AES aquí.)

Entonces, en cualquier caso:

  • DEBES entender lo que estás haciendo. La seguridad no se puede probar, por lo que la única forma de crear código seguro, especialmente con criptografía, es tener un conocimiento profundo y profundo de lo que sucede internamente.

  • DEBES especificar exactamente lo que estás haciendo. No permita que su idioma seleccione valores predeterminados mal definidos.

  • NO DEBES hacerlo tú mismo. Escribir un código criptográfico seguro es una de las tareas más difíciles en el desarrollo, precisamente porque no hay forma de saber si lo hizo correctamente (aunque la experiencia muestra que la respuesta "no, se hizo mal, es débil" casi siempre encaja).

respondido por el Tom Leek 01.05.2014 - 16:14
fuente
3

Veo algunos problemas con tu código en general; no es completamente seguro y descarta las excepciones, por lo que no es adecuado para ninguna aplicación relevante para la seguridad.

Supongo que no es para algún tipo de proyecto comercial, sino un proyecto privado que haces para (y solo para) aprender algo. Eso está totalmente bien. Sin embargo, recomendaría no enviar esto a ningún cliente (esto incluye a amigos), hasta que esté más familiarizado con la escritura de código de seguridad.

Debería especificar el relleno y el modo de su cifrado, como "AES/CBC/PKCS5Padding" . No especificar un modo y el relleno puede dar lugar a problemas dependientes de la implementación (como una JVM diferente que usa otro modo y, por lo tanto, no puede descifrar su archivo). También tenga en cuenta que los modos como ECB no protegen contra algunos ataques, consulte esta imagen encriptada:

ImagenCopyright:todoslosusosestánpermitidossiemprequeLarryEwing,elpropietariodelaimagenoriginal,querequierequeustedlomencione,sudireccióndecorreoelectrónico,[email protected],yTheGIMP,deacuerdocon enlace .

Para obtener más detalles al respecto, consulte Artículo de Wikipedia sobre los modos de cifrado de bloque . Por lo tanto, me gustaría ir CBC para tu aplicación.

    
respondido por el dst 01.05.2014 - 16:14
fuente
0

Bueno, no, supongo que no, pero entonces no habría forma de cifrar nada más allá del primer bloque con una clave dada. Esto es un poco como preguntarle si puede cifrar algo sin entrada o sin un algoritmo de cifrado. El modo es cómo se deriva la clave para cada bloque y cómo se produce realmente el cifrado. Es una parte crítica del cifrado, no puede "no tener un modo" y tener un algoritmo de trabajo.

En cuanto al almacenamiento de las claves de archivos AES en los metadatos cifrados. No le dará mucha seguridad adicional al usar la misma clave para todo, pero no está mal. Su archivo de metadatos es básicamente un conjunto de claves, por lo tanto, si un archivo se pierde y se agrieta, el resto no se verá comprometido, aunque de manera realista, si ha hecho las cosas correctamente, no se espera que un archivo AES se craque antes de Calor muerte del universo, por lo que realmente no gana mucho ...

    
respondido por el AJ Henderson 01.05.2014 - 16:14
fuente

Lea otras preguntas en las etiquetas