Cómo implementar el sistema de cifrado / descifrado mediante IV entre la aplicación móvil y el servicio web

3

En mi aplicación vamos a enviar datos encriptados al servicio web. Estoy utilizando el siguiente código para cifrar y descifrar los datos -

public class DecEn {
    private static final String password = "test";
    private static String salt;
    private static int pswdIterations = 65536;
    private static int keySize = 256;
    private byte[] ivBytes;

    public String encrypt(String plainText) throws Exception {

        //get salt
        salt = generateSalt();
        byte[] saltBytes = salt.getBytes("UTF-8");

        // Derive the key
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(
                password.toCharArray(),
                saltBytes,
                pswdIterations,
                keySize
        );

        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

        //encrypt the message
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        AlgorithmParameters params = cipher.getParameters();
        ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
        byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
        return new Base64().encodeAsString(encryptedTextBytes);
//      return Base64.encodeBase64String(encryptedTextBytes);
//      return Hex.encodeHexString(encryptedTextBytes);
    }

    @SuppressWarnings("static-access")
    public String decrypt(String encryptedText) throws Exception {

        byte[] saltBytes = salt.getBytes("UTF-8");
        byte[] encryptedTextBytes = new Base64().decodeBase64(encryptedText);
//      byte[] encryptedTextBytes = Base64.decodeBase64(encryptedText);
//      byte[] encryptedTextBytes = Hex.decodeHex(encryptedText.toCharArray());

        // Derive the key
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(
                password.toCharArray(),
                saltBytes,
                pswdIterations,
                keySize
        );

        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

        // Decrypt the message
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));


        byte[] decryptedTextBytes = null;
        try {
            decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }

        return new String(decryptedTextBytes);
    }

    public String generateSalt() {
        SecureRandom random = new SecureRandom();
        byte bytes[] = new byte[20];
        random.nextBytes(bytes);
        String s = new String(bytes);
        return s;
    }
}

El código anterior almacena IV y sal después de que se generan y los reutiliza para descifrar los datos. Esto no será cierto en caso de colaboración entre la aplicación y el servicio web.

Lo que realmente me confunde es que la IV y la sal se generan de nuevo cada vez que se cifran los datos, que es el procedimiento recomendado por lo que pude ver en Google, pero a medida que estos datos se envían a un servicio web, la IV y la sal tiene que estar disponible allí, lo que significa que tendré que enviarlo junto con mis datos. ¿No derrota esto al propósito del cifrado? Como hace que la información esté disponible para el atacante.

O la otra forma parece ser el uso de IV estático y sal, lo que de nuevo hace que el cifrado sea susceptible de ataques. Que el cifrado se esté utilizando con éxito en todo el mundo indica que mi comprensión del tema no se encuentra en alguna parte.

Por favor ayúdame a aclarar mis dudas.

    
pregunta Opax Web 07.07.2015 - 06:34
fuente

1 respuesta

3

Los vectores de inicialización no están destinados a ser privados. El objetivo de una IV no es fortalecer la clave, sino asegurarse de que no haya dos textos claros idénticos (o similares) que den como resultado el mismo (o similar) texto cifrado.

Funciona así: AES (junto con la mayoría, pero no todo, el algoritmo criptográfico moderno) es un cifrado de bloque . Solo opera con una cantidad fija de datos (en el caso de AES, 128 bits ). Por lo tanto, para que los bloques de datos idénticos dentro de los datos de origen (es decir, que utilicen la misma clave) sean idénticos, es habitual especificar un modo de operación que introduce alguna forma de cambio entre dos bloques de datos.

En su caso, ha seleccionado CBC que básicamente XOR el texto claro del bloque N con el texto cifrado del bloque N-1 antes de cifrarlo.

Esto funciona bien, excepto para el primer bloque: no hay un bloque anterior para mezclarlo y, por lo tanto, si no hace algo al respecto, si el texto claro comienza con los mismos 128 bits será similar si el mismo La clave se utiliza para el cifrado. Este es un problema real porque es bastante frecuente que dos mensajes tengan los mismos primeros 128 bits. Además, dependiendo de la aplicación, es posible deducir el significado del mensaje sin siquiera descifrarlo (piense en las respuestas "sí" y "no", por ejemplo).

Para eso está el IV: se asegura de que, mientras no reutilices el IV, no tengas que preocuparte por que dos mensajes produzcan un texto claro idéntico.

Otro punto que vale la pena destacar es que podrías hacer lo mismo con cambiar la clave. Aquí hay dos problemas:

  • Las claves a menudo se recogen sobre la marcha y, por lo tanto, solo son estadísticamente únicas (lo que no es un problema).
  • Las claves son caras de cambiar: en el mejor de los casos, es necesario volver a negociar una clave (por ejemplo, con DH ). Vale la pena, debe volver a crear una nueva clave e intercambiarla a través de un canal seguro.
respondido por el Stephane 07.07.2015 - 10:02
fuente

Lea otras preguntas en las etiquetas