首页 > 解决方案 > PHP 相当于一个 Node 加密函数

问题描述

我正在尝试获取此节点函数的 php 等效项,以便能够在 php 中加密某些数据,然后在节点中对其进行解密

/**
    * Encrypts an object with aes-256-cbc to use as a token
    * @param {any} data An object to encrypt
    * @param {string} secret The secret to encrypt the data with
    * @returns {string}
    */
static encrypt(data, secret) {
    const iv = randomBytes(16);
    const cipher = createCipheriv('aes-256-cbc', secret, iv);
    return `${cipher.update(JSON.stringify(data), 'utf8', 'base64') + cipher.final('base64')}.${iv.toString('base64')}`;
}

这是我想出的 php 函数,以及必要的辅助函数

/**
 * Encrypts an object with aes-256-cbc to use as a token
 * @param $data An object to encrypt
 * @param $secret The secret to encrypt data with
 * @return \Illuminate\Http\Response
 */
public function encrypt($data, $secret)
{
    $method = 'AES-256-CBC';

    $data = static::getPaddedText($data);
    $iv             = static::generateIv();

    $ciphertext     = openssl_encrypt(json_encode($data), $method, $secret, OPENSSL_RAW_DATA, $iv);
    $ciphertext_64  = base64_encode(utf8_encode($ciphertext));
    $iv_64          = base64_encode($iv);
    return "$ciphertext_64.$iv_64";
}

private static function getPaddedText(string $plainText): string
{
    $blocksize = 8;

    $textLength = strlen($plainText);
    if ($textLength % $blocksize) {
        $plainText = str_pad($plainText, $textLength + $blocksize - $textLength % $blocksize, "\0");
    }
    return $plainText;
}

public static function generateIv(): string
{
    $ivLength = 16;
    $success = false;
    $random = openssl_random_pseudo_bytes($ivLength, $success);
    if (!$success) {
        $random = random_bytes($ivLength);
    }
    return $random;
}

但我认为它与使用此功能解密时不完全相同

/**
    * Decrypts an object with aes-256-cbc to use as a token
    * @param {string} token An data to decrypt
    * @param {string} secret The secret to decrypt the data with
    * @returns {any}
    */
static decrypt(token, secret) {
    const [data, iv] = token.split('.');
    const decipher = createDecipheriv('aes-256-cbc', secret, Buffer.from(iv, 'base64'));
    return JSON.parse(decipher.update(data, 'base64', 'utf8') + decipher.final('utf8'));
}

我收到这个错误EVP_DecryptFinal_ex:wrong final block length

标签: phpnode.jsencryptionopenssl

解决方案


看起来您没有用空值填充文本以确保您的块大小正好是八个字符长。换句话说,您的字符串长度必须是 8 的倍数。用空值填充您的字符串将为您完成此操作,而无需更改其值。

class AES256Encryption
{
    public const BLOCK_SIZE = 8;
    public const IV_LENGTH = 16;
    public const CIPHER = 'AES-256-CBC';

    public static function generateIv(): string
    {
            $success = false;
            $random = openssl_random_pseudo_bytes(static::IV_LENGTH, $success);
            if (!$success) {
                $random = random_bytes(static::IV_LENGTH);
            }
            return $random;
    }

    private static function getPaddedText(string $plainText): string
    {
        $textLength = strlen($plainText);
        if ($textLength % static::BLOCK_SIZE) {
            $plainText = str_pad($plainText, $textLength + static::BLOCK_SIZE - $textLength % 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);
    }
}

用法:

$key = 'secretkey';
$iv = AES256Encryption::generateIv();
$text = 'The quick brown fox jumps over the lazy dog';
$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);

输出:

Original Text: The quick brown fox jumps over the lazy dog
Encrypted    : 1J+0tGHzn67WA7kJGjp9malmv0w+tcl0t8YnC+F9Y9IZWMDeBH4+k9TyuznF77cWe1SGUWa6Pb6r/i0xmH+ajg==
Decrypted    : The quick brown fox jumps over the lazy dog   

你的用法:

// Your encoding usage:
$key = 'secret';
$iv = AES256Encryption::generateIv();
$text = 'The quick brown fox jumps over the lazy dog';
$encryptedText = AES256Encryption::encrypt($text, $key, $iv);
$finalString = $encryptedText . bin2hex($iv);

// Your decoding usage:
$iv = hex2bin(substr($finalString, -32, 32));
$decryptedText = AES256Encryption::decrypt($encryptedText, $key, $iv);

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

输出:

Original Text : The quick brown fox jumps over the lazy dog
Encrypted     : +JsjXFPdyTycYrc2fOb1edLKNksEUHzEGxwRewBlA8yxBWZZV2y/EVIwk0g9g17dtxAaTGZvYaf2y9+oTCvLWg==
Encrypted w/Iv: +JsjXFPdyTycYrc2fOb1edLKNksEUHzEGxwRewBlA8yxBWZZV2y/EVIwk0g9g17dtxAaTGZvYaf2y9+oTCvLWg==54993615360ff641a952a553e1500568
Decrypted     : The quick brown fox jumps over the lazy dog  

生成 IV 可以更健壮,因为random_bytes()可以引发异常。


推荐阅读