首页 >后端开发 >php教程 >如何使用 OpenSSL 在 PHP 中实现简单的双向加密?

如何使用 OpenSSL 在 PHP 中实现简单的双向加密?

Barbara Streisand
Barbara Streisand原创
2024-12-13 04:49:13314浏览

How Can I Implement Simple Two-Way Encryption in PHP Using OpenSSL?

PHP 中最简单的双向加密

重要提示:

在继续之前,强调本文至关重要旨在提供对未经身份验证的加密的简化理解。为了实现强大的数据保护,请始终考虑使用行业标准的经过身份验证的加密库或 bcrypt/argon2 进行密码存储。

本机加密方法

如果使用 PHP 5.4 或更高版本,请考虑使用 openssl_* 函数用于密码操作。它们通过本机支持提供强大的加密功能。

简单的加密和解密

OpenSSL 的 openssl_encrypt() 和 openssl_decrypt() 函数提供了一种可访问的方法来加密和解密数据。推荐的加密算法是 AES-CTR 的 128、192 或 256 位变体。

注意:由于 mcrypt 已弃用和潜在的安全风险,请避免使用 mcrypt。

简单加密/解密包装器

简化加密和解密解密过程中,您可以使用以下包装类:

class UnsafeCrypto
{
    // Encryption method (CTR mode)
    const METHOD = 'aes-256-ctr';

    /**
     * Encrypts data using the specified key.
     *
     * @param string $message Plaintext message
     * @param string $key Encryption key
     * @param bool $encode Whether to encode the result
     *
     * @return string Ciphertext
     */
    public static function encrypt($message, $key, $encode = false)
    {
        // Generate random IV
        $ivSize = openssl_cipher_iv_length(self::METHOD);
        $iv = openssl_random_pseudo_bytes($ivSize);

        // Encrypt using OpenSSL
        $ciphertext = openssl_encrypt($message, self::METHOD, $key, OPENSSL_RAW_DATA, $iv);

        // Concatenate IV and ciphertext
        if ($encode) {
            return base64_encode($iv . $ciphertext);
        }
        return $iv . $ciphertext;
    }

    /**
     * Decrypts data using the specified key.
     *
     * @param string $message Ciphertext
     * @param string $key Encryption key
     * @param bool $encoded Whether the message is encoded
     *
     * @return string Decrypted message
     */
    public static function decrypt($message, $key, $encoded = false)
    {
        if ($encoded) {
            $message = base64_decode($message, true);
            if ($message === false) {
                throw new Exception('Encryption failure');
            }
        }

        // Extract IV and ciphertext
        $ivSize = openssl_cipher_iv_length(self::METHOD);
        $iv = substr($message, 0, $ivSize);
        $ciphertext = substr($message, $ivSize);

        // Decrypt using OpenSSL
        $plaintext = openssl_decrypt($ciphertext, self::METHOD, $key, OPENSSL_RAW_DATA, $iv);

        return $plaintext;
    }
}

身份验证加密

上述方法仅提供加密,使数据容易被篡改。为了解决这个问题,请实施经过身份验证的加密方案:

class SaferCrypto extends UnsafeCrypto
{
    // MAC algorithm
    const HASH_ALGO = 'sha256';

    /**
     * Encrypts and authenticates data using the specified key.
     *
     * @param string $message Plaintext message
     * @param string $key Encryption key
     * @param bool $encode Whether to encode the result
     *
     * @return string Encrypted and authenticated data
     */
    public static function encrypt($message, $key, $encode = false)
    {
        // Split key into encryption and authentication keys
        list($encKey, $authKey) = self::splitKeys($key);

        // Encrypt using UnsafeCrypto::encrypt
        $ciphertext = parent::encrypt($message, $encKey);

        // Calculate MAC
        $mac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true);

        // Concatenate MAC and ciphertext
        if ($encode) {
            return base64_encode($mac . $ciphertext);
        }
        return $mac . $ciphertext;
    }

    /**
     * Decrypts and authenticates data using the specified key.
     *
     * @param string $message Encrypted and authenticated data
     * @param string $key Encryption key
     * @param bool $encoded Whether the message is encoded
     *
     * @throws Exception
     *
     * @return string Decrypted message
     */
    public static function decrypt($message, $key, $encoded = false)
    {
        // Split key
        list($encKey, $authKey) = self::splitKeys($key);

        // Decode message if necessary
        if ($encoded) {
            $message = base64_decode($message, true);
            if ($message === false) {
                throw new Exception('Encryption failure');
            }
        }

        // Extract MAC and ciphertext
        $hs = strlen(hash(self::HASH_ALGO, '', true), '8bit');
        $mac = substr($message, 0, $hs);
        $ciphertext = substr($message, $hs);

        // Calculate expected MAC
        $expectedMac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true);

        // Verify MAC
        if (!self::hashEquals($mac, $expectedMac)) {
            throw new Exception('Encryption failure');
        }

        // Decrypt message using UnsafeCrypto::decrypt
        $plaintext = parent::decrypt($ciphertext, $encKey);

        return $plaintext;
    }

    /**
     * Splits a key into two separate keys for encryption and authentication.
     *
     * @param string $masterKey Master key
     *
     * @return string[] Array of encryption and authentication keys
     */
    protected static function splitKeys($masterKey)
    {
        return [
            hash_hmac(self::HASH_ALGO, 'ENCRYPTION', $masterKey, true),
            hash_hmac(self::HASH_ALGO, 'AUTHENTICATION', $masterKey, true)
        ];
    }

    /**
     * Compares two strings without leaking timing information
     * (PHP 7+).
     *
     * @param string $a
     * @param string $b
     *
     * @return bool
     */
    protected static function hashEquals($a, $b)
    {
        if (function_exists('hash_equals')) {
            return hash_equals($a, $b);
        }

        $nonce = openssl_random_pseudo_bytes(32);
        return hash_hmac(self::HASH_ALGO, $a, $nonce) === hash_hmac(self::HASH_ALGO, $b, $nonce);
    }
}

请记住,为了强大的安全性,请考虑使用信誉良好的加密库。

以上是如何使用 OpenSSL 在 PHP 中实现简单的双向加密?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn