How to add/remove PKCS7 padding from an AES encrypted string?

前端 未结 3 542
慢半拍i
慢半拍i 2020-11-22 16:47

I\'m trying to encrypt/decrypt a string using 128 bit AES encryption (ECB). What I want to know is how I can add/remove the PKCS7 padding to it. It seems that the Mcrypt ext

3条回答
  •  日久生厌
    2020-11-22 16:59

    I've created two methods to perform the padding and unpadding. The functions are documented using phpdoc and require PHP 5. As you will notice the unpad function contains a lot of exception handling, generating not less than 4 different messages for each possible error.

    To get to the block size for PHP mcrypt, you can use mcrypt_get_block_size, which also defines the block size to be in bytes instead of 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);
    }
    

    This does not invalidate the answer of Paŭlo Ebermann in any way, it's basically the same answer in code & phpdoc instead of as description.


    Note that returning a padding error to an attacker might result in a padding oracle attack which completely breaks CBC (when CBC is used instead of ECB or a secure authenticated cipher).

提交回复
热议问题