Estoy tratando de cifrar/descifrar una cadena mediante AES de 128 bits de cifrado (BCE). Lo que quiero saber es como puedo agregar/quitar el relleno de PKCS7. Parece que la extensión Mcrypt puede tomar el cuidado de cifrado/descifrado, pero el relleno tiene que ser añadido/eliminado manualmente.

Alguna idea?

Sólo una nota: Si no se puede cambiar, el uso de otro de modo que el BCE (es inseguro).
No, no se puede cambiar, es lo que el sistema del cliente depende. Cualquier posibilidad de que usted podría guiarme con el relleno cosa?
Me refería a AES, fijo.
No utilice el modo de ECB. Si el cliente piensa que necesitan BCE, están equivocados. Usar el CTR o CBC, asegúrese de que la autenticación de su ciphertexts.

OriginalEl autor Click Upvote | 2011-09-06

3 Comentarios

  1. 51

    Vamos a ver. PKCS #7 se describe en el RFC 5652 (Sintaxis de Mensajes Criptográficos).

    El esquema de relleno sí se da en la sección 6.3. Contenido-Proceso de cifrado. Que esencialmente dice: anexar que tantos bytes como sea necesario para llenar el dado por el tamaño de bloque (al menos uno), y cada uno de ellos debe tener la longitud de relleno como valor.

    Por lo tanto, mirando a la última descifrar byte sabemos cuántos bytes a la franja. (También se podría comprobar que todos ellos tienen el mismo valor.)

    Ahora podía darle un par de funciones de PHP para hacer esto, pero mi PHP es un poco oxidado. Para hacerlo usted mismo (a continuación, siéntase libre de editar mi respuesta a agregar), o eche un vistazo a la el usuario contribuido notas a la mcrypt documentación – bastante algunos de ellos son de alrededor de relleno y proporcionar una implementación de relleno PKCS #7.


    Así que, vamos a ver en el primera nota en detalle:

    <?php
    
    function encrypt($str, $key)
     {
         $block = mcrypt_get_block_size('des', 'ecb');

    Esto hace que el tamaño de bloque del algoritmo usado. En su caso, utilizaría aes o rijndael_128 en lugar de des, supongo (yo no prueba). (En su lugar, usted podría simplemente tomar 16 aquí para AES, en lugar de invocar a la función.)

         $pad = $block - (strlen($str) % $block);

    Calcula el relleno de tamaño. strlen($str) es la longitud de su base de datos (en bytes), % $block da el resto modulo $block, es decir, el número de bytes de datos en el último bloque. $block - ... da, por tanto, el número de bytes necesarios para llenar este último bloque (este es un número entre 1 y $block, ambos inclusive).

         $str .= str_repeat(chr($pad), $pad);

    str_repeat produce una cadena que consiste en una repetición de la misma cadena, aquí una repetición de la carácter dado por $pad, $pad veces, es decir, una cadena de longitud $pad, lleno de $pad.
    $str .= ... anexa a esta cadena de relleno con los datos originales.

         return mcrypt_encrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);

    Aquí es la misma encriptación. Uso MCRYPT_RIJNDAEL_128 en lugar de MCRYPT_DES.

     }

    Ahora la otra dirección:

     function decrypt($str, $key)
     {   
         $str = mcrypt_decrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);

    El descifrado. (Usted, por supuesto, el cambio de algoritmo, como en el anterior). $str es ahora la cadena descifrada, incluyendo el relleno.

         $block = mcrypt_get_block_size('des', 'ecb');

    Esto es, nuevamente, el tamaño de bloque. (Ver más arriba).

         $pad = ord($str[($len = strlen($str)) - 1]);

    Este se ve un poco extraño. Mejor escribir en varios pasos:

        $len = strlen($str);
        $pad = ord($str[$len-1]);

    $len es ahora la longitud del collar de la cadena, y $str[$len - 1] es el último carácter de esta cadena. ord la convierte en un número. Por lo tanto $pad es el número que hemos utilizado anteriormente como el relleno de valor para el relleno, y esta es la longitud de relleno.

         return substr($str, 0, strlen($str) - $pad);

    Así que ahora tenemos que cortar los últimos $pad bytes de la cadena. (En lugar de strlen($str) también se podrían escribir $len aquí: substr($str, 0, $len - $pad).).

     }
    
    ?>

    Nota que en lugar de utilizar substr($str, $len - $pad), también se puede escribir substr($str, -$pad), como el substr función en PHP tiene un especial de manejo para los operandos y argumentos, a contar desde el final de la cadena. (No sé si esto es más o menos eficiente que la obtención de la longitud de la primera y y calcular el índice de forma manual.)

    Como se dijo antes, y señaló en el comentario por rossum, en lugar de simplemente eliminando el relleno como se hace aquí, se debe verificar que es correcta – es decir, mirar substr($str, $len - $pad), y comprobar que todos sus bytes son chr($pad). Esto sirve como un leve cheque contra la corrupción (aunque esta comprobación es más eficaz si se utiliza un modo de encadenamiento en lugar del BCE, y no es un reemplazo para un verdadero MAC).


    (Y aún así, dígale a su cliente que debería pensar en cambiar a una más segura de modo que no es el BCE.)

    Si usted podría dar algún ejemplo de código para hacer esto en pseudo-código, o java, sería estupendo. Yo todavía no entiendo muy bien cómo hacer esto, yo.e ¿cuál es el dado por el tamaño de bloque, ¿cuál es el último decodificado byte, etc
    Al retirar el relleno no debes quitarlo. Usted debe buscar de que es correcta. Si es que, a continuación, proceder, si no es correcto, a continuación, borrar el texto descifrado y lanzar un margen de error.
    WARNING: si un atacante puede probar por la incorrecta acolchados en línea, a continuación, un atacante puede crear padding oracle ataques que puede destruir por completo a la confidencialidad. Usar un MAC o HMAC sobre el IV y el texto cifrado para evitar este escenario.
    En su descifrar función usted está calculando $bloque, pero no se utiliza en la función. Por qué?
    Para ser honesto, no tengo idea. He copiado el código de usuario aportado por los comentarios de la página vinculada de PHP, doc, y acaba de agregar mis comentarios. (El vinculado comentario es desaparecido desde entonces o el Id de la página ha cambiado.)

    OriginalEl autor Paŭlo Ebermann

  2. 7

    He creado dos métodos para realizar el relleno y unpadding. Las funciones están documentadas mediante phpdoc y requiere PHP 5. Como te darás cuenta el unpad función contiene una gran cantidad de manejo de excepciones, la generación de no menos de 4 mensajes diferentes para cada posible error.

    Para obtener el tamaño de bloque para mcrypt PHP, puede utilizar mcrypt_get_block_size, que también define el tamaño de bloque en bytes en lugar de bits.

    /**
     * Right-pads the data string with 1 to n bytes according to PKCS#7,
     * where n is the block size.
     * The size of the result is x times n, where x is at least 1.
     * 
     * The version of PKCS#7 padding used is the one defined in RFC 5652 chapter 6.3.
     * This padding is identical to PKCS#5 padding for 8 byte block ciphers such as DES.
     *
     * @param string $plaintext the plaintext encoded as a string containing bytes
     * @param integer $blocksize the block size of the cipher in bytes
     * @return string the padded plaintext
     */
    function pkcs7pad($plaintext, $blocksize)
    {
        $padsize = $blocksize - (strlen($plaintext) % $blocksize);
        return $plaintext . str_repeat(chr($padsize), $padsize);
    }
    
    /**
     * Validates and unpads the padded plaintext according to PKCS#7.
     * The resulting plaintext will be 1 to n bytes smaller depending on the amount of padding,
     * where n is the block size.
     *
     * The user is required to make sure that plaintext and padding oracles do not apply,
     * for instance by providing integrity and authenticity to the IV and ciphertext using a HMAC.
     *
     * Note that errors during uppadding may occur if the integrity of the ciphertext
     * is not validated or if the key is incorrect. A wrong key, IV or ciphertext may all
     * lead to errors within this method.
     *
     * The version of PKCS#7 padding used is the one defined in RFC 5652 chapter 6.3.
     * This padding is identical to PKCS#5 padding for 8 byte block ciphers such as DES.
     *
     * @param string padded the padded plaintext encoded as a string containing bytes
     * @param integer $blocksize the block size of the cipher in bytes
     * @return string the unpadded plaintext
     * @throws Exception if the unpadding failed
     */
    function pkcs7unpad($padded, $blocksize)
    {
        $l = strlen($padded);
    
        if ($l % $blocksize != 0) 
        {
            throw new Exception("Padded plaintext cannot be divided by the block size");
        }
    
        $padsize = ord($padded[$l - 1]);
    
        if ($padsize === 0)
        {
            throw new Exception("Zero padding found instead of PKCS#7 padding");
        }    
    
        if ($padsize > $blocksize)
        {
            throw new Exception("Incorrect amount of PKCS#7 padding for blocksize");
        }
    
        //check the correctness of the padding bytes by counting the occurance
        $padding = substr($padded, -1 * $padsize);
        if (substr_count($padding, chr($padsize)) != $padsize)
        {
            throw new Exception("Invalid PKCS#7 padding encountered");
        }
    
        return substr($padded, 0, $l - $padsize);
    }

    Esto no invalida la respuesta de Paŭlo Ebermann de alguna manera, que es básicamente la misma respuesta en el código & phpdoc en lugar de como una descripción.


    Nota que devolver un margen de error de un atacante podría resultar en un relleno de oracle ataque que rompe completamente CBC (cuando CBC se utiliza en lugar del BCE o de un seguro de cifrado autenticado).

    OriginalEl autor Maarten Bodewes

  3. 0

    Basta con llamar a la siguiente función después de descifrar los datos

    function removePadding($decryptedText){
        $strPad = ord($decryptedText[strlen($decryptedText)-1]);
        $decryptedText= substr($decryptedText, 0, -$strPad);
        return $decryptedText;
    }
    El código de respuesta no funcionará con null relleno que mcrypt PHP por defecto. Para PKCS#7/PKCS#5 relleno se necesita una verificación de que el relleno es válido. Considerar el uso de la tecla equivocada, $strPad que lo más probable sería incorrecto, potencialmente, un valor mayor que la longitud de los datos. Pero no devuelven un mal relleno de error, que tiende a crear un relleno de oracle, en lugar de simplemente no hacer nada. La mayoría de las bibliotecas de soporte de relleno PKCS#7 y automáticamente agregar relleno y cifrado quitado el relleno en el descifrado–no necesita nada más por hacer.

    OriginalEl autor Hari Das

Dejar respuesta

Please enter your comment!
Please enter your name here