【问题标题】:How to encrypt big files with php and decrypt over commandline?如何使用 php 加密大文件并通过命令行解密?
【发布时间】:2014-04-15 03:56:59
【问题描述】:

我正在用 PHP 编写一个小脚本来备份我的文件。在从服务器传输文件之前,我想对它们进行加密。

我在以前版本的脚本中通过在我的 Linux 服务器上使用 exec() 和 OpenSSL 来做到这一点。现在我正在寻找一个原生 PHP-Function 来完成这项工作,主要是为了更好地处理错误。

问题是我的文件可能会变大(比如 20GB)。此外,我必须在我的 shell 上使用命令再次解密文件。

有谁知道如何在 PHP 中加密大文件,然后在命令行上解密?

我现在使用 PHP 的 mcrypt 函数来加密:

// IV:
$iv = mcrypt_create_iv($ivSize, MCRYPT_RAND);

// Create new random Key:
$key = openssl_random_pseudo_bytes(32);

// Encrypt:
$fileStream = fopen($file, "r");
$encFileStream = fopen($file . ".enc.data", "w");

$opts = [
    'iv'   => $iv,
    'key'  => $key,
    'mode' => 'cbc'
];
stream_filter_append($encFileStream, 'mcrypt.rijndael-256', STREAM_FILTER_WRITE, $opts);
stream_copy_to_stream($fileStream, $encFileStream);

fclose($fileStream);
fclose($encFileStream);

// Encrypt random generated key and save it:
$encryptedKey = null;
openssl_public_encrypt($key, $encryptedKey, $publickey);
file_put_contents($file . ".enc.key", $encryptedKey);

// Save Initial Vetor:
file_put_contents($file . ".enc.iv", $iv);

// Delete unencrypted file:
unlink($file);

现在要在 linux 命令行上解密,我也尝试使用 mcrypt。但我遇到的最大问题是我不知道如何将 IV 添加到mdecrypt。到目前为止,我的命令是:

mdecrypt --decrypt -m CBC -f key.key archive_hallo.tar.gz.enc.data

这当然行不通,因为 IV 丢失了。那么,有谁知道如何将 IV 添加到我的 mdecrypt 命令中

【问题讨论】:

    标签: php linux encryption cryptography mcrypt


    【解决方案1】:

    mdecrypt 来自 mcrypt_2.6.8 debian 包 expects the specific file format with header 的 CLI 工具。搜索write_file_head函数,显示mcrypt/mdecrypt工具格式的前3个字节:

    buf[0] = '\0';
    buf[1] = 'm';
    buf[2] = '\3';
    

    标头应设置特殊位,并将 IV 嵌入文件中。会读到here, in decrypt_general function:

    if (_mcrypt_iv_is_needed(td, mode, noiv) != 0) {
       IV = read_iv(FROMF, mcrypt_enc_get_iv_size(td));
    } else {
       IV = _mcrypt_calloc(1, mcrypt_enc_get_iv_size(td));
    }
    

    read_ivextra.c 中定义为:

    void *read_iv(FILE * fstream, int ivsize)
    {
    char *IV;
         ... // malloc 
    fread(IV, 1, ivsize, fstream);
        return IV;
    }
    

    所以,只需检查加密文件的前 N ​​个字节(您可以在 hexdump -C 之后将它们发布在这里)并检查 mcrypt 标头(0x00 'm' 0x03)和您的 IV。如果是 - 那么mdecrypt 工具应该从文件中获取 IV。如果不是 - 不支持在 mdecrypt 中通过命令行设置 IV,但您可以侵入源代码,为 iv 添加新选项,然后修改 decrypt_general 以从选项中读取 iv。

    【讨论】:

    • 您好,谢谢您的回答。如果我做 hexdump,第一行是:00000000 76 80 ee 78 05 07 03 36 72 a7 62 46 78 95 11 91 |v.îx...6r§bFx...|。如何确定第二个字节是否为“m”?
    • 'm' 是 0x6d - 使用 www.asciitable.com。因此,PHP mcrypt 的输出不是mdecrypt 实用程序的格式。您应该添加正确的标题并在其中填写 IV;或者,您可以侵入 mdecrypt 实用程序并添加 IV 命令行选项。或者你可以编写一个小的 php 脚本来使用 php 函数解密文件,然后从 bash 中以php script.php 或类似的方式运行这个 php 脚本。
    • 好的,非常感谢。将尝试将标题和 IV 添加到文件中。是否有关于标题必须如何的文档?还是我必须通过阅读代码来弄清楚?再次感谢您!
    • 我不明白。你能帮助我吗?这是我的尝试方法(见第 13、14 行):gist.github.com/DeDu/3804940cffc19db4aedf
    • Matthias,您可以尝试使用命令行mcrypt 加密已知文件并将结果与​​您的脚本进行比较(--noiv 选项可将 IV 设置为全零)。不知道确切的格式(在这里阅读资料可能会有所帮助)。
    【解决方案2】:

    如果您的 PHP 版本可以从命令行执行单个文件,您始终可以创建一个 PHP 命令行程序来执行解密。根据您的安全设置,您可能需要通过 shell 程序(shell 文件中的php -q decrypt.php)而不是直接(#!/usr/bin/php/cli/php 或类似的)执行 PHP。

    【讨论】:

    • 这就是我目前使用的解决方案。但我希望能够在不需要我的脚本的情况下解密我的备份文件。还是谢谢你!
    • 那么您认为一些命令行程序是如何实现的:)?例如,看看 Puppet——它是用 Ruby 编写的。前面有正确的魔法咒语(例如#!/usr/bin/perl),你永远不需要考虑这个命令实际上是用什么语言实现的。
    • 是的,我知道 shebang 是如何工作的。目标是不依赖我的脚本来解密我的备份。我想使用 PHP-Encryption 方法进行加密,然后当我需要备份时,我希望能够使用 mdecrypt(因为我更有可能在那个时候使用它)。感谢您的帮助,但我的问题与 shebang 无关 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 2016-04-22
    • 2012-07-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多