-->

PHP AES加密/解密PHP AES加密/解密(PHP AES encrypt / decrypt

2019-06-17 10:38发布

我发现在PHP EN /解码串的例子。 起初,这看起来很不错,但它不会工作:-(

有谁知道问题是什么?

$Pass = "Passwort";
$Clear = "Klartext";

$crypted = fnEncrypt($Clear, $Pass);
echo "Encrypted: ".$crypted."</br>";

$newClear = fnDecrypt($crypted, $Pass);
echo "Decrypted: ".$newClear."</br>";

function fnEncrypt($sValue, $sSecretKey) {
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, $sDecrypted, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}

function fnDecrypt($sValue, $sSecretKey) {
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, base64_decode($sEncrypted), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}

其结果是:

加密: boKRNTYYNp7AiOvY1CidqsAn9wX4ufz/D9XrpjAOPk8=

解密: —‚(ÑÁ ^ yË~F'¸®Ó–í œð2Á_B‰Â—

Answer 1:

$sDecrypted$sEncrypted在你的代码中不明确的。 看到有效的解决方案( 但不保证!):


停!

这个例子是不安全的! 不要使用它!


$Pass = "Passwort";
$Clear = "Klartext";        

$crypted = fnEncrypt($Clear, $Pass);
echo "Encrypred: ".$crypted."</br>";

$newClear = fnDecrypt($crypted, $Pass);
echo "Decrypred: ".$newClear."</br>";        

function fnEncrypt($sValue, $sSecretKey)
{
    return rtrim(
        base64_encode(
            mcrypt_encrypt(
                MCRYPT_RIJNDAEL_256,
                $sSecretKey, $sValue, 
                MCRYPT_MODE_ECB, 
                mcrypt_create_iv(
                    mcrypt_get_iv_size(
                        MCRYPT_RIJNDAEL_256, 
                        MCRYPT_MODE_ECB
                    ), 
                    MCRYPT_RAND)
                )
            ), "\0"
        );
}

function fnDecrypt($sValue, $sSecretKey)
{
    return rtrim(
        mcrypt_decrypt(
            MCRYPT_RIJNDAEL_256, 
            $sSecretKey, 
            base64_decode($sValue), 
            MCRYPT_MODE_ECB,
            mcrypt_create_iv(
                mcrypt_get_iv_size(
                    MCRYPT_RIJNDAEL_256,
                    MCRYPT_MODE_ECB
                ), 
                MCRYPT_RAND
            )
        ), "\0"
    );
}

但也有在该代码,这使得它不安全,特别是使用ECB(它不是一个加密模式中,仅在顶部的积木其中加密模式可以被定义)的其它问题。 见的Fab萨的回答为最严重的问题,快速解决和斯科特的答案如何做到这一点的权利。



Answer 2:

请使用现有的安全PHP加密库

它通常是一个坏主意,写自己的密码,除非你有经验,打破其他人的加密实现。

的例子在这里没有身份验证的密文 ,这使得他们极易被位改写攻击。

如果你可以安装PECL扩展, libsodium甚至更好

<?php
// PECL libsodium 0.2.1 and newer

/**
 * Encrypt a message
 * 
 * @param string $message - message to encrypt
 * @param string $key - encryption key
 * @return string
 */
function safeEncrypt($message, $key)
{
    $nonce = \Sodium\randombytes_buf(
        \Sodium\CRYPTO_SECRETBOX_NONCEBYTES
    );

    return base64_encode(
        $nonce.
        \Sodium\crypto_secretbox(
            $message,
            $nonce,
            $key
        )
    );
}

/**
 * Decrypt a message
 * 
 * @param string $encrypted - message encrypted with safeEncrypt()
 * @param string $key - encryption key
 * @return string
 */
function safeDecrypt($encrypted, $key)
{   
    $decoded = base64_decode($encrypted);
    $nonce = mb_substr($decoded, 0, \Sodium\CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
    $ciphertext = mb_substr($decoded, \Sodium\CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');

    return \Sodium\crypto_secretbox_open(
        $ciphertext,
        $nonce,
        $key
    );
}    

然后测试一下:

<?php
// This refers to the previous code block.
require "safeCrypto.php"; 

// Do this once then store it somehow:
$key = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_KEYBYTES);
$message = 'We are all living in a yellow submarine';

$ciphertext = safeEncrypt($message, $key);
$plaintext = safeDecrypt($ciphertext, $key);

var_dump($ciphertext);
var_dump($plaintext);

这可以在你在哪里(用于会话例如加密的Cookie中没有服务器侧存储,加密URL参数,等)与相当高的程度的确定性将数据传递到客户端的任何情形中,最终用户无法破译或可靠地篡改用它。

由于libsodium是跨平台的 ,这也使得它更容易从,例如Java小程序或本机移动应用PHP通信。


注意:如果你特别需要搭载libsodium加密Cookie添加到您的应用程序,我的雇主模范倡议企业正在开发一种名为库岩盐 ,做这一切为您服务。



Answer 3:

如果你不希望使用的严重依赖的东西在代码15行可解,使用内置的OpenSSL的功能。 大多数PHP安装配备了OpenSSL的,它提供了PHP快,兼容,安全的AES加密。 那么,它作为您关注的最佳实践是安全的,因为长。

下面的代码:

  • 采用AES256 CBC模式
  • 是与其它AES实施兼容,但不是mcrypt的 ,因为使用的mcrypt PKCS#5而不是PKCS#7。
  • 生成使用SHA256提供的密码密钥
  • 生成加密数据的HMAC哈希用于完整性校验
  • 生成各消息的随机IV
  • 预先考虑IV(16个字节)和散列(32个字节)到密文
  • 应该是很安全的

IV是一种公共信息和需为无规每个消息。 散列确保数据不被篡改。

function encrypt($plaintext, $password) {
    $method = "AES-256-CBC";
    $key = hash('sha256', $password, true);
    $iv = openssl_random_pseudo_bytes(16);

    $ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
    $hash = hash_hmac('sha256', $ciphertext, $key, true);

    return $iv . $hash . $ciphertext;
}

function decrypt($ivHashCiphertext, $password) {
    $method = "AES-256-CBC";
    $iv = substr($ivHashCiphertext, 0, 16);
    $hash = substr($ivHashCiphertext, 16, 32);
    $ciphertext = substr($ivHashCiphertext, 48);
    $key = hash('sha256', $password, true);

    if (hash_hmac('sha256', $ciphertext, $key, true) !== $hash) return null;

    return openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
}

用法:

$encrypted = encrypt('Plaintext string.', 'password'); // this yields a binary string

echo decrypt($encrypted, 'password');
// decrypt($encrypted, 'wrong password') === null


Answer 4:

有关信息MCRYPT_MODE_ECB不使用IV(初始化矢量)。 ECB模式将您的消息转换成块,每块单独加密。 我真的不推荐它

CBC模式下使用IV使每个消息是唯一的。 CBC建议,应该用来代替欧洲央行。

例如:

<?php
$password = "myPassword_!";
$messageClear = "Secret message";

// 32 byte binary blob
$aes256Key = hash("SHA256", $password, true);

// for good entropy (for MCRYPT_RAND)
srand((double) microtime() * 1000000);
// generate random iv
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);


$crypted = fnEncrypt($messageClear, $aes256Key);

$newClear = fnDecrypt($crypted, $aes256Key);

echo
"IV:        <code>".$iv."</code><br/>".
"Encrypred: <code>".$crypted."</code><br/>".
"Decrypred: <code>".$newClear."</code><br/>";

function fnEncrypt($sValue, $sSecretKey) {
    global $iv;
    return rtrim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, $sValue, MCRYPT_MODE_CBC, $iv)), "\0\3");
}

function fnDecrypt($sValue, $sSecretKey) {
    global $iv;
    return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, base64_decode($sValue), MCRYPT_MODE_CBC, $iv), "\0\3");
}

你必须股票的四每条消息(IV 不是秘密的)解码。 每个消息是唯一的,因为每个消息有一个独特的IV。

  • 关于更详细的信息的操作模式(维基百科) 。


Answer 5:

与AES加密需要注意的几个重要事项:

  1. 千万不要使用纯文本加密密钥。 始终哈希明文密钥,然后使用加密。
  2. 总是使用随机IV(初始化矢量)进行加密和解密。 真正的随机化是很重要的。
  3. 如上所述,不使用ECB模式下,使用CBC代替。


Answer 6:

如果您正在使用MCRYPT_RIJNDAEL_128,尝试rtrim($output, "\0\3") 如果字符串的长度小于16,解密函数将返回一个字符串的16个字符的长度,在末处加入03。

您可以轻松地检查这一点,例如,通过尝试:

$string = "TheString";
$decrypted_string = decrypt_function($stirng, $key);

echo bin2hex($decrypted_string)."=".bin2hex("TheString");


Answer 7:

我使用的东西代码CCAVenue付款Getway

class AES {

    public function encrypt($plainText, $key) {
        $secretKey = $this->hextobin(md5($key));
        $initVector = pack("C*", 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f);
        $openMode = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', '');
        $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, 'cbc');
        $plainPad = $this->pkcs5_pad($plainText, $blockSize);
        if (mcrypt_generic_init($openMode, $secretKey, $initVector) != -1) {
            $encryptedText = mcrypt_generic($openMode, $plainPad);
            mcrypt_generic_deinit($openMode);
        }
        return bin2hex($encryptedText);
    }

    public function decrypt($encryptedText, $key) {
        $secretKey = $this->hextobin(md5($key));
        $initVector = pack("C*", 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f);
        $encryptedText = $this->hextobin($encryptedText);
        $openMode = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', '');
        mcrypt_generic_init($openMode, $secretKey, $initVector);
        $decryptedText = mdecrypt_generic($openMode, $encryptedText);
        $decryptedText = rtrim($decryptedText, "\0");
        mcrypt_generic_deinit($openMode);
        return $decryptedText;
    }

    //*********** Padding Function *********************

    public function pkcs5_pad($plainText, $blockSize) {
        $pad = $blockSize - (strlen($plainText) % $blockSize);
        return $plainText . str_repeat(chr($pad), $pad);
    }

    //********** Hexadecimal to Binary function for php 4.0 version ********

    public function hextobin($hexString) {
        $length = strlen($hexString);
        $binString = "";
        $count = 0;
        while ($count < $length) {
            $subString = substr($hexString, $count, 2);
            $packedString = pack("H*", $subString);
            if ($count == 0) {
                $binString = $packedString;
            } else {
                $binString .= $packedString;
            }

            $count += 2;
        }
        return $binString;
    }

}

代码的用户

$obj = new AES();
$key = "XXXXXXXXXXXXXXXX";
$plainText = "Hello World";
$encryptedText = $obj->encrypt($plainText, $key);
$rcvdString=$obj->decrypt($encryptedText,$key);


Answer 8:

如果你正在使用PHP> = 7.2考虑使用encrption内置钠核心扩展。

在这里找到更多的信息- http://php.net/manual/en/intro.sodium.php



文章来源: PHP AES encrypt / decrypt