PHP AES加密PKCS5Padding

时间:2011-08-04 09:43:07

标签: php encryption aes padding

我不是PHP编码器,所以我需要一点PHP AES加密帮助。

我正在编写代码,我在PHP中加密图像文件,然后在Java(Android)中解密它们。当我加密/解密PNG文件时,一切正常,但当我尝试对JPG执行相同操作时,Java解密会引发异常:

WARN/System.err(345): java.io.IOException: data not block size aligned

基于在线搜索,似乎这是因为我没有正确填充。

我该如何正确地做到这一点?

以下是加密的PHP代码:

<?php
    $secret_key   = "01234567890abcde";
    $iv           = "fedcba9876543210";
    $infile       = "5.png";
    $outfile      = "5_encrypted.png";

    $crypttext = file_get_contents($infile);
    $plaintext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $secret_key, $crypttext, MCRYPT_MODE_CBC, $iv);

    header('Content-Type: application/octet-stream');
    header('Content-Length: ' . strlen($plaintext));
    header('Content-Disposition: attachment; filename=' . ($outfile));

    echo $plaintext;


    //file_put_contents($outfile,$plaintext);   
    //save the file in the folder of server

2 个答案:

答案 0 :(得分:7)

以下PKCS5Padding示例来自对mcrypt docs的评论。

<?php 

function encrypt_something($input) 
{ 
    $size = mcrypt_get_block_size('des', 'ecb'); 
    $input = pkcs5_pad($input, $size); 

    $key = 'YOUR SECRET KEY HERE'; 
    $td = mcrypt_module_open('des', '', 'ecb', ''); 
    $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND); 
    mcrypt_generic_init($td, $key, $iv); 
    $data = mcrypt_generic($td, $input); 
    mcrypt_generic_deinit($td); 
    mcrypt_module_close($td); 
    $data = base64_encode($data); 
    return $data; 
} 

function pkcs5_pad ($text, $blocksize) 
{ 
    $pad = $blocksize - (strlen($text) % $blocksize); 
    return $text . str_repeat(chr($pad), $pad); 
} 

function pkcs5_unpad($text) 
{ 
    $pad = ord($text{strlen($text)-1}); 
    if ($pad > strlen($text)) return false; 
    if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false; 
    return substr($text, 0, -1 * $pad); 
}

答案 1 :(得分:0)

这里是使用openssl而不是mcrypt的PHP实现。

mcrypt在PHP中已删除。 openssl仅支持PKSC7。但是,PKSC7和PKSC5之间的区别仅在于PKSC7具有可变的块大小,而PKSC5始终以8的块大小工作。

您可以在PHP> 7.0上使用它,也可以通过删除PHP 5.3上的“类型提示”来进行修改。这是openssl的用法:https://www.php.net/manual/de/book.openssl.php

在类代码中可以找到更多链接,帮助和资源。

class AESCryptoStreamFactory
{
    /**
     * default: 8 fpr PKSC5! 
     * - The block size is a property of the used cipher algorithm. 
     * 
     * For AES it is always 16 bytes. So strictly speaking, 
     * PKCS5Padding cannot be used with AES since it is defined only for a block size of 8 bytes.
     * 
     * The only difference between these padding schemes is that PKCS7Padding has the block size as a parameter,
     * while for PKCS5Padding it is fixed at 8 bytes. When the Block size is 8 bytes they do exactly the same.
     * 
     * - https://crypto.stackexchange.com/questions/43489/how-does-aes-ctr-pkcs5padding-works-when-the-bits-to-encrypt-is-more-than-8-bits
     * - https://stackoverflow.com/questions/20770072/aes-cbc-pkcs5padding-vs-aes-cbc-pkcs7padding-with-256-key-size-performance-java/20770158
     */
    public const BLOCK_SIZE = 8;

    /**
     * default: 16
     * @var int IV_LENGTH
     * - IV Length
     */
    public const IV_LENGTH = 16;

    /**
     * default: AES256
     * @var string CIPHER
     */
    public const CIPHER = 'AES256';

    /**
     * 
     * @param string $plainText
     *  - plain text
     * @return string $plainText 
     *  - padded text
     */
    protected static function getPaddedText(string $plainText): string
    {
        $stringLength = strlen($plainText);
        if ($stringLength % static::BLOCK_SIZE) {
            $plainText = str_pad($plainText, $stringLength + static::BLOCK_SIZE - $stringLength % static::BLOCK_SIZE, "\0");
        }
        return $plainText;
    }

    /**
     * Get encrypted string
     * @param string $plainText [required]
     * - decrypted string
     * @param string $key [required]
     * - Key
     * @param string $iv [required]
     * - IV Key
     * @return string 
     * - encrypted string
     */
    public static function encrypt(string $plainText, string $key, string $iv): string
    {
        $plainText = static::getPaddedText($plainText);
        return openssl_encrypt($plainText, static::CIPHER, $key, OPENSSL_RAW_DATA, $iv);
    }

    /**
     * Get decrypted string
     * @param string $encryptedText
     * - verschlüsselter Text
     * @param string $key 
     * - key to decrypt
     * @param string $iv 
     * - IV key
     * @return string 
     * - decrypted string
     */
    public static function decrypt(string $encryptedText, string $key, string $iv): string
    {
        return openssl_decrypt($encryptedText, static::CIPHER, $key, OPENSSL_RAW_DATA, $iv);
    }
}

用法:

$encrypted = AESCryptoStreamFactory::encrypt($plainText, $key, $iv);
$decrypted = AESCryptoStreamFactory::decrypt($encryptedText, $key, $iv);

要生成cipherIV,请将此函数添加到类中:

   public static function generateIv(bool $allowLessSecure = false): string
    {
        $success = false;
        $random = openssl_random_pseudo_bytes(openssl_cipher_iv_length(static::CIPHER));
        if (!$success) {
            if (function_exists('sodium_randombytes_random16')) {
                $random = sodium_randombytes_random16();
            } else {
                try {
                    $random = random_bytes(static::IV_LENGTH);
                } catch (\Exception $e) {
                    if ($allowLessSecure) {
                        $permitted_chars = implode(
                            '',
                            array_merge(
                                range('A', 'z'),
                                range(0, 9),
                                str_split('~!@#$%&*()-=+{};:"<>,.?/\'')
                            )
                        );
                        $random = '';
                        for ($i = 0; $i < static::IV_LENGTH; $i++) {
                            $random .= $permitted_chars[mt_rand(0, (static::IV_LENGTH) - 1)];
                        }
                    } else {
                        throw new \RuntimeException('cannot generate an initialization vector (IV)');
                    }
                }
            }
        }
        return $random;
    }