8

これは、データの暗号化/復号化に使用するコードです。

// Set the method
$method = 'AES-128-CBC';

// Set the encryption key
$encryption_key = 'myencryptionkey';

// Generet a random initialisation vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));

// Define the date to be encrypted
$data = "Encrypt me, please!";

var_dump("Before encryption: $data");

// Encrypt the data
$encrypted = openssl_encrypt($data, $method, $encryption_key, 0, $iv);

var_dump("Encrypted: ${encrypted}");

// Append the vector at the end of the encrypted string
$encrypted = $encrypted . ':' . $iv;

// Explode the string using the `:` separator.
$parts = explode(':', $encrypted);

// Decrypt the data
$decrypted = openssl_decrypt($parts[0], $method, $encryption_key, 0, $parts[1]);

var_dump("Decrypted: ${decrypted}");

通常は正常に動作しますが、時々 (10 分の 1 またはそれ以下) 失敗します。テキストが部分的にのみ暗号化されているよりも失敗した場合:

これは、発生したときのエラー メッセージです。

Warning: openssl_decrypt(): IV passed is only 10 bytes long, cipher expects an IV of precisely 16 bytes, padding with \0

そして、暗号化されたテキストは次のようになります。

Encrypt me���L�se!

PHP のバグが原因ではないかと考えましたが、別のホストでテストしました: PHP 7.0.6 と PHP 5.6。また、phpfidle.org や 3v4l.org などの複数のオンライン PHP パーサーも試しました。

常に適切な長さの文字列が返されるとは限らないようですopenssl_random_pseudo_bytesが、その理由はわかりません。

サンプルは次のとおりです: https://3v4l.org/RZV8d

ページを更新し続けると、ある時点でエラーが発生します。

4

3 に答える 3

16

ランダムな IV を生成すると、生のバイナリが得られます。IV を暗号文から分離するために使用している文字:または文字がバイナリ文字列に含まれる可能性はゼロではありません。\0そうするexplode()ことで、より短い文字列が得られます。デモ: https://3v4l.org/3ObfJ

簡単な解決策は、base64 エンコード/デコードをこのプロセスに追加することです。


とは言っても、自分の暗号を転がさないでください。特に、認証されていない暗号化は危険あり、この問題を解決する安全なライブラリが既に存在します

独自に作成する代わりに、defuse/php-encryptionを使用することを検討してください。これは安全な選択です。

于 2016-05-25T14:36:06.433 に答える
1

これが解決策です

最初の投稿のコードを更新し、クラスにラップしました。これは、 Scott Arciszewskiによって提供されたソリューションに基づいて修正されたコードです。

class Encryptor
{

    /**
     * Holds the Encryptor instance
     * @var Encryptor
     */
    private static $instance;

    /**
     * @var string
     */
    private $method;

    /**
     * @var string
     */
    private $key;

    /**
     * @var string
     */
    private $separator;

    /**
     * Encryptor constructor.
     */
    private function __construct()
    {
        $app = App::getInstance();
        $this->method = $app->getConfig('encryption_method');
        $this->key = $app->getConfig('encryption_key');
        $this->separator = ':';
    }

    private function __clone()
    {
    }

    /**
     * Returns an instance of the Encryptor class or creates the new instance if the instance is not created yet.
     * @return Encryptor
     */
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new Encryptor();
        }
        return self::$instance;
    }

    /**
     * Generates the initialization vector
     * @return string
     */
    private function getIv()
    {
        return openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->method));
    }

    /**
     * @param string $data
     * @return string
     */
    public function encrypt($data)
    {
        $iv = $this->getIv();
        return base64_encode(openssl_encrypt($data, $this->method, $this->key, 0, $iv) . $this->separator . base64_encode($iv));
    }

    /**
     * @param string $dataAndVector
     * @return string
     */
    public function decrypt($dataAndVector)
    {
        $parts = explode($this->separator, base64_decode($dataAndVector));
        // $parts[0] = encrypted data
        // $parts[1] = initialization vector
        return openssl_decrypt($parts[0], $this->method, $this->key, 0, base64_decode($parts[1]));
    }

}

使用法

$encryptor = Encryptor::getInstance();

$encryptedData = $encryptor->encrypt('Encrypt me please!');
var_dump($encryptedData);

$decryptedData = $encryptor->decrypt($encryptedData);
var_dump($decryptedData);
于 2016-05-25T18:19:44.893 に答える
0

これは私にも起こりました。次のようなエラーが発生しました

openssl_decrypt(): IV passed is only 14 bytes long, cipher expects an IV of precisely 16 bytes, padding with \0

次のような小文字の方法を使用していましたopenssl_cipher_iv_length('aes-128-cbc')

小文字の aes- -メソッドは、12 から 16 の間で変化する長さの結果を返します。参照: https://www.php.net/manual/en/function.openssl-cipher-iv-length.php

メソッドを大文字openssl_cipher_iv_length('AES-128-CBC')にすると、一貫した値である 16 が得られます。

そのため、暗号化と復号化の間、IV の長さは 16 のままです。

于 2020-11-26T09:26:04.737 に答える