【PHP】对称加密算法 AES-256-GCM 代码示例

前言

下面介绍在PHP代码中,如何对数据进行 AES-256-GCM 加密和解密。我们可以使用 openssl 和 sodium 扩展来实现加密,它们都支持 AES-256-GCM 算法,下面将给出两种扩展的代码示例。

环境

PHP 7.3

一、使用openssl扩展

php 复制代码
<?php

function aes256gcm_encrypt(string $data, string $keygen, string $aad = ''): array
{
    $cipher = 'aes-256-gcm';
    $ivLen = openssl_cipher_iv_length($cipher);
    $iv = random_bytes($ivLen); // 12字节的iv
    $encrypt = openssl_encrypt($data, $cipher, $keygen, OPENSSL_RAW_DATA, $iv,$tag, $aad);
    return [
        'iv'          => base64_encode($iv),
        'tag'         => base64_encode($tag),
        'aad'         => base64_encode($aad),
        'cipher_text' => base64_encode($encrypt),
    ];
}

function aes256gcm_decrypt(array $secretData, string $keygen)
{
    $iv = base64_decode($secretData['iv']);
    $tag = base64_decode($secretData['tag']);
    $aad = base64_decode($secretData['aad']);
    $cipherText = base64_decode($secretData['cipher_text']);

    $cipher = 'aes-256-gcm';
    return openssl_decrypt($cipherText, $cipher, $keygen, OPENSSL_RAW_DATA, $iv, $tag, $aad);
}

function main()
{
    // AES-256-GCM需要32字节的密钥
    $keygen = bin2hex(random_bytes(16));
    // 加密
    $data = 'Hello World!';
    $secretData = aes256gcm_encrypt($data, $keygen, 'foobar');
    // 解密
    $plainText = aes256gcm_decrypt($secretData, $keygen);

    echo "原文:$data\n";
    echo "密文数据:" . json_encode($secretData) . "\n";
    echo "解密后:$plainText\n";
}

main();

二、使用 sodium 扩展

php 复制代码
<?php

function aes256gcm_encrypt(string $data, string $keygen, string $aad = ''): array
{
    $iv = random_bytes(SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES);
    $encrypt = sodium_crypto_aead_aes256gcm_encrypt($data, $aad, $iv, $keygen); // 包含密文、tag
    return [
        'iv'          => sodium_bin2base64($iv, SODIUM_BASE64_VARIANT_ORIGINAL),
        'aad'         => sodium_bin2base64($aad, SODIUM_BASE64_VARIANT_ORIGINAL),
        'cipher_text' => sodium_bin2base64($encrypt, SODIUM_BASE64_VARIANT_ORIGINAL),
    ];
}

function aes256gcm_decrypt(array $secretData, string $keygen)
{
    $iv = sodium_base642bin($secretData['iv'], SODIUM_BASE64_VARIANT_ORIGINAL);
    $aad = sodium_base642bin($secretData['aad'], SODIUM_BASE64_VARIANT_ORIGINAL);
    $cipherText = sodium_base642bin($secretData['cipher_text'], SODIUM_BASE64_VARIANT_ORIGINAL);
    return sodium_crypto_aead_aes256gcm_decrypt($cipherText, $aad, $iv, $keygen);
}

function main()
{
    if (!sodium_crypto_aead_aes256gcm_is_available()) {
        exit('Not support AES-256-GCM');
    }

    // 生成AES-256-GCM的密钥
    $keygen = sodium_crypto_aead_aes256gcm_keygen();
    // 加密
    $data = 'Hello World!';
    $secretData = aes256gcm_encrypt($data, $keygen, 'foobar');
    // 解密
    $plainText = aes256gcm_decrypt($secretData, $keygen);

    echo "原文:$data\n";
    echo "密文数据:" . json_encode($secretData) . "\n";
    echo "解密后:$plainText\n";
}

main();

AAD参数(Additional Authenticated Data)

在上面的代码示例中,可以看到在加密的时候有一个$aad参数,如果在加密的时候使用了这个参数,那么在解密时也需要使用同样的AAD值才能成功解密。

什么时候会需要用到AAD呢?下面举个例子:

用户Alice在CSDN博客上写了一篇私密文章,CSDN使用 AES-256-GCM 加密了这篇文章,然后存储到了数据库里,AAD的取值是Alice的用户ID。

后续如果Alice去查看这篇文章,CSDN会使用Alice的用户ID(AAD值)去解密,因为解密的AAD值与加密的AAD值相同,所以可以成功解密。

然后有一个黑客Bob,他也向CSDN发出解密这篇文章的请求,CSDN就会使用Bob的用户ID作为AAD去解密这篇文章,但因为AAD值错误,肯定是解密不了的,所以这时候AAD的作用就体现了出来。

参阅

相关推荐
wheelmouse77889 小时前
网络排查基础与实战指南:Ping 与 Telnet
开发语言·网络·php
向往着的青绿色10 小时前
备份是个好习惯 BugKuCTF题目题解
网络安全·php·安全威胁分析·ctf·安全架构·安全性测试·威胁分析
大尚来也12 小时前
PHP 反序列化漏洞深度解析:从原理利用到 allowed_classes 防御实战
android·开发语言·php
毕设源码-郭学长17 小时前
【开题答辩全过程】以 剧本杀交流平台为例,包含答辩的问题和答案
php
浮尘笔记17 小时前
PHP中常规通用接口验签加密规则设计
开发语言·后端·网络安全·php
Risehuxyc17 小时前
PHP 的缓存机制
开发语言·缓存·php
我叫黑大帅19 小时前
php 如何使用mysqli连接mysql
后端·面试·php
JACK的服务器笔记19 小时前
Day12_网络吞吐基线测试
开发语言·网络·php
我叫黑大帅19 小时前
PHP mysqli 实用开发指南
后端·面试·php
博语小屋19 小时前
Reactor、epoll下设计一个简单的网络版本计算器
服务器·开发语言·网络·网络协议·http·php