php 使用 Mcrypt 加密/解密文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2448256/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 06:31:45  来源:igfitidea点击:

Encrypting / Decrypting file with Mcrypt

phpfilemcrypt

提问by whitman6732

Trying to write a couple of functions that will encrypt or decrypt a file and am using the class found here to try and accomplish this:

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

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

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

The encryption function below seems to work, in that it appears to encrypt the file and place it in the intended directory. I'm trying to decrypt the file now, and it just dies with the message "Failed to complete decryption" (which is coded in there...) There's nothing in the php error logs, so I'm not sure why it's failing, but as mcrypt is entirely new to me, I'm more than inclined to believe I'm doing something wrong here...

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

Here are the functions:

以下是功能:

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

回答by John Conde

Since mcrypt is abandonware and no longer recommended to be used, here's an example using openssl.

由于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, "
// 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 
"); } 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);

Output:

输出:

<?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, "
$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
"); } }

Old Answer

旧答案

Try this PHP5 class for encryption using mcrypt. In this case it's using AES encryption. You'll want to change the key for each site you use it on. If you don't use it at least it may guide you on writing your own version of it.

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

##代码##

Usage:

用法:

##代码##

Notes:

笔记:

  • This class is not safe for use with binary data (which may end in NUL bytes)
  • This class does not provide authenticated encryption.
  • 此类不能安全用于二进制数据(可能以 NUL 字节结尾)
  • 此类不提供经过身份验证的加密。

回答by Phil

While Johns answer is good, using base64 encoding just to fix the binary safety issue is overkill and will make your encrypted files 33% larger than the original. Here is my PHP Implementation of the AES Crypt file format which solves all the above issues transparently.

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

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

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

It is binary safe and includes authenticated encryption. Since it uses the open source aes crypt file format (.aes) it is fully compatible with other .aes software.

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

https://www.aescrypt.com/

https://www.aescrypt.com/

The interface is pretty simple whether you are encrypting or decrypting. You just give it a source file and password.

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

回答by Aaron Toponce

You should not be using Mcrypt to encrypt/decrypt data. As shown in your question, and in the accepted answer, the data is not authenticated, which means it will fall victim to chosen ciphertext attacks.

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

Further, a great deal of effort has been done to make sure that developers put together cryptographic primitives correctly. As such, instead of Mcrypt, you should be using libsodium for your PHP projects. libsodium is a fork of NaCl. NaCl/libsodium is written to remove a lot of the cryptographic pitfalls that developers find themselves in, such as timing attacks with verification of MAC tags.

此外,还做了大量工作以确保开发人员正确地组合加密原语。因此,您应该在 PHP 项目中使用 libsodium,而不是 Mcrypt。libsodium 是 NaCl 的叉子。编写 NaCl/libsodium 是为了消除开发人员发现的许多密码陷阱,例如带有 MAC 标签验证的定时攻击。

Mcrypt is deprecated in PHP 7.1, and libsodim is the preferred way to handle cryptography in PHP.

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

Using libsodium in your PHP project is easy, and secure. Scott Arciszewski has written an extensive ebook on using libsodium with PHP at https://paragonie.com/book/pecl-libsodium. It's worth the read for anyone doing PHP cryptography.

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

回答by rynop

CakePHPhas a pretty good implementationof rijndael. I'm not posting code directly here because not sure the legal ramifications.

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

Here are the api docsfor the Security::rijndael()method.

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

If encoding a file, you will want to base64_encode()before calling this method with 'encrypt', and base64_decode()after calling this method with 'decrypt'

如果编码文件,你将要base64_encode()调用这个方法用“前encrypt”,并base64_decode()调用此方法与后“ decrypt