24

尝试编写几个将加密或解密文件的函数,并使用此处找到的类来尝试完成此操作:

http://www.itnewb.com/v/PHP-Encryption-Decryption-Using-the-MCrypt-Library-libmcrypt

下面的加密功能似乎有效,因为它似乎加密了文件并将其放置在预期的目录中。我现在正在尝试解密文件,它只是因为消息“无法完成解密”而死掉(其中编码...)php错误日志中没有任何内容,所以我不确定它为什么会失败,但由于 mcrypt 对我来说是全新的,我更倾向于相信我在这里做错了什么......

以下是功能:

//ENCRYPT FILE
    function encryptFile() {
        global $cryptastic;
        $pass = PGPPASS;
        $salt = PGPSALT;
        $key = $cryptastic->pbkdf2($pass, $salt, 1000, 32) or die("Failed to generate secret key.");

        if ($handle = opendir(PATH.'/ftpd')) {
            while (false !== ($file = readdir($handle))) {
                if ($file != "." && $file != "..") {
                    $newfile = PATH.'/encrypted/'.$file.'.txt';
                    $msg = file_get_contents(PATH.'/ftpd/'.$file);
                    $encrypted = $cryptastic->encrypt($msg, $key) or die("Failed to complete encryption.");
                    $nfile = fopen($newfile, 'w');
                    fwrite($nfile, $encrypted);
                    fclose($nfile);
                    unlink(PATH.'/ftpd/'.$file);

                }
            }
            closedir($handle);
        }       


//DECRYPT FILE
    function inFTP() {
        global $cryptastic;
        $pass = PGPPASS;
        $salt = PGPSALT;
        $key = $cryptastic->pbkdf2($pass, $salt, 1000, 32) or die("Failed to generate secret key.");

        if ($handle = opendir(PATH.'/encrypted')) {
            while (false !== ($file = readdir($handle))) {
                if ($file != "." && $file != "..") {
                    $newfile = PATH.'/decrypted/'.$file;
                    $msg = PATH.'/encrypted/'.$file;
                    $decrypted = $cryptastic->decrypt($msg, $key) or die("Failed to complete decryption.");
                    $nfile = fopen($newfile, 'w');
                    fwrite($nfile, $decrypted);
                    fclose($nfile);
                    //unlink(PATH.'/encrypted/'.$file);

                }
            }
            closedir($handle);
        }       
        //$crypt->decrypt($file);
    }
4

4 回答 4

57

由于mcrypt 是废弃软件,不再推荐使用,这里有一个使用 openssl 的示例。

class AES256Encryption
{
    public const BLOCK_SIZE = 8;
    public const IV_LENGTH = 16;
    public const CIPHER = 'AES256';

    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('Unable to generate initialization vector (IV)');
                    }
                }
            }
        }
        return $random;
    }

    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;
    }

    public static function encrypt(string $plainText, string $key, string $iv): string
    {
        $plainText = static::getPaddedText($plainText);
        return base64_encode(openssl_encrypt($plainText, static::CIPHER, $key, OPENSSL_RAW_DATA, $iv));
    }

    public static function decrypt(string $encryptedText, string $key, string $iv): string
    {
        return openssl_decrypt(base64_decode($encryptedText), static::CIPHER, $key, OPENSSL_RAW_DATA, $iv);
    }
}

$text = '8SViI0Gz4r-p7A15YxkwjOBFuW*@NTtbm{U]D&E=~6yLM+adX'P;h3$,KJ%/eo>}<Rs:2#gZ.9fqn"Cv_^[(H\c!)?`Ql';
$key = 'secretkey';
$iv = AES256Encryption::generateIv();
$encryptedText = AES256Encryption::encrypt($text, $key, $iv);
$decryptedText = AES256Encryption::decrypt($encryptedText, $key, $iv);

printf('Original Text: %s%s', $text, PHP_EOL);
printf('Encrypted: %s%s', $encryptedText, PHP_EOL);
printf('Decrypted: %s%s', $decryptedText, PHP_EOL);

输出:

// Long string with lots of different characters
Original Text: 8SViI0Gz4r-p7A15YxkwjOBFuW*@NTtbm{U]D&E=~6yLM+adX'P;h3$,KJ%/eo>}<Rs:2#gZ.9fqn"Cv_^[(H\c!)?`Ql
Encrypted    : rsiF4PMCMyvAp+CTuJrxJYGoV4BSy8Fy+q+FL8m64+Mt5V3o0HS0elRkWXsy+//hPjzNhjmVktxVvMY55Negt4DyLcf2QpH05wUX+adJDe634J/9fWd+nlEFoDutXuhY+/Kep9zUZFDmLmszJaBHWQ==
Decrypted    : 8SViI0Gz4r-p7A15YxkwjOBFuW*@NTtbm{U]D&E=~6yLM+adX'P;h3$,KJ%/eo>}<Rs:2#gZ.9fqn"Cv_^[(H\c!)?`Ql 

旧答案

试试这个 PHP5 类使用 mcrypt 进行加密。在这种情况下,它使用 AES 加密。您需要为使用它的每个站点更改密钥。如果您至少不使用它,它可能会指导您编写自己的版本。

<?php

class Encryption
{
    const CIPHER = MCRYPT_RIJNDAEL_128; // Rijndael-128 is AES
    const MODE   = MCRYPT_MODE_CBC;

    /* Cryptographic key of length 16, 24 or 32. NOT a password! */
    private $key;
    public function __construct($key) {
        $this->key = $key;
    }

    public function encrypt($plaintext) {
        $ivSize = mcrypt_get_iv_size(self::CIPHER, self::MODE);
        $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
        $ciphertext = mcrypt_encrypt(self::CIPHER, $this->key, $plaintext, self::MODE, $iv);
        return base64_encode($iv.$ciphertext);
    }

    public function decrypt($ciphertext) {
        $ciphertext = base64_decode($ciphertext);
        $ivSize = mcrypt_get_iv_size(self::CIPHER, self::MODE);
        if (strlen($ciphertext) < $ivSize) {
            throw new Exception('Missing initialization vector');
        }

        $iv = substr($ciphertext, 0, $ivSize);
        $ciphertext = substr($ciphertext, $ivSize);
        $plaintext = mcrypt_decrypt(self::CIPHER, $this->key, $ciphertext, self::MODE, $iv);
        return rtrim($plaintext, "\0");
    }
}

用法:

$key = /* CRYPTOGRAPHIC!!! key */;
$crypt = new Encryption($key);
$encrypted_string = $crypt->encrypt('this is a test');
$decrypted_string = $crypt->decrypt($encrypted_string); // this is a test

笔记:

  • 此类与二进制数据(可能以 NUL 字节结尾)一起使用是不安全的
  • 此类不提供经过身份验证的加密。
于 2010-03-15T15:49:06.663 回答
2

虽然 Johns 的回答很好,但仅使用 base64 编码来解决二进制安全问题是多余的,并且会使您的加密文件比原始文件大 33%。这是我的 AES Crypt 文件格式的 PHP 实现,它透明地解决了上述所有问题。

https://github.com/philios33/PHP-AES-File-Encryption

它是二进制安全的,包括经过身份验证的加密。由于它使用开源 aes crypt 文件格式 (.aes),因此它与其他 .aes 软件完全兼容。

https://www.aescrypt.com/

无论您是加密还是解密,界面都非常简单。你只需给它一个源文件和密码。

于 2014-12-05T00:53:41.607 回答
2

您不应该使用 Mcrypt 来加密/解密数据。如您的问题和接受的答案所示,数据未经过身份验证,这意味着它将成为选择密文攻击的受害者。

此外,为了确保开发人员正确地将密码原语放在一起,已经做了很多努力。因此,您应该在 PHP 项目中使用 libsodium 而不是 Mcrypt。libsodium 是 NaCl 的一个分支。编写 NaCl/libsodium 是为了消除开发人员发现的许多加密陷阱,例如带有 MAC 标签验证的定时攻击。

Mcrypt 在 PHP 7.1 中已弃用,而 libsodim 是在 PHP 中处理密码学的首选方式。

在您的 PHP 项目中使用 libsodium 既简单又安全。Scott Arciszewski 在https://paragonie.com/book/pecl-libsodium上写了一本关于将 libsodium 与 PHP 结合使用的内容丰富的电子书。任何从事 PHP 加密的人都值得一读。

于 2016-12-09T18:00:00.030 回答
1

CakePHP有一个很好的 rijndael实现。我没有直接在这里发布代码,因为不确定法律后果。

这是该方法的 api 文档Security::rijndael()

如果对文件进行编码,您将需要base64_encode()在调用此方法之前使用 ' encrypt',并base64_decode()在调用此方法之后使用 ' decrypt'

于 2013-09-20T20:53:50.133 回答