aes-256-gcm_python3_php7_golang
转载注明来源: 本文链接 来自osnosn的博客,写于 2021-02-07.
以下的,不同语言的加解密函数,输出内容可以互通。
python3
#!/usr/bin/python3
### coding: utf-8
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import cryptography.exceptions
import binascii
import base64
import os
def encrypt_aes256gcm(key, ciphertext, aad):
'''
aes-256-gcm 加密
key: 为str,hex字符串,64字符(32字节)
aad: 为str,hex字符串,32字符(16字节)
ciphertext: 为bytes, 明文
返回: 为bytes, base64 的密文
'''
aes_gcm_ivlen = 12
key_bytes = binascii.unhexlify(key)
aad_bytes = binascii.unhexlify(aad)
data = ciphertext
iv_bytes = os.urandom(aes_gcm_ivlen)
aesgcm = AESGCM(key_bytes) # tag_length=16
crypt_bytes = aesgcm.encrypt(iv_bytes, data, aad_bytes)
return base64.b64encode(iv_bytes + crypt_bytes)
def decrypt_aes256gcm(key, ciphertext, aad):
'''
aes-256-gcm 解密
key: 为str,hex字符串,64字符(32字节)
aad: 为str,hex字符串,32字符(16字节)
ciphertext: 为bytes, base64 的密文
返回: bytes 的明文, 或者解密失败 返回 b''
'''
aes_gcm_ivlen = 12
key_bytes = binascii.unhexlify(key)
aad_bytes = binascii.unhexlify(aad)
try:
data = base64.b64decode(ciphertext)
except binascii.Error as e:
#print(e)
return b''
iv_bytes = data[0:aes_gcm_ivlen]
data = data[aes_gcm_ivlen:]
aesgcm = AESGCM(key_bytes) # tag_length=16
try:
text_bytes = aesgcm.decrypt(iv_bytes, data, aad_bytes)
except cryptography.exceptions.InvalidTag as e:
return b''
return text_bytes
if __name__ =='__main__':
key='1100222233334444555566667777888899990000aaaabbbbccccddddeeeeffff'
aad='22223311223311221122331122331122'
ciphertext = encrypt_aes256gcm(key, b"a secret message!", aad)
print(ciphertext)
ssss=b'YO4uAtkNBFpKF8GRni8tT2IW6WUQRox8D1ujcCkPKtxYsbWHDdInvvjxqzN/'
ciphertext = decrypt_aes256gcm(key, ssss,aad)
print(ciphertext)
php7.1 或以上
<?php
function encrypt_aes256gcm($key, $ciphertext, $aad){
// 加密
// $key: hex字符串,64字符(32字节)
// $aad: hex字符串,32字符(16字节)
// 返回 base64编码的密文
$cipher='aes-256-gcm';
$ivlen= openssl_cipher_iv_length($cipher); // 12
$iv=openssl_random_pseudo_bytes($ivlen);
$key=hex2bin($key);
$aad=hex2bin($aad);
$ss=openssl_encrypt($ciphertext,$cipher,$key,OPENSSL_RAW_DATA,$iv,$tag,$aad,16);
$ssss=$iv.$ss.$tag;
return base64_encode($ssss);
}
function decrypt_aes256gcm($key, $ciphertext, $aad){
// 解密
// $key: hex字符串,64字符(32字节)
// $aad: hex字符串,32字符(16字节)
// 返回 明文,或空
$cipher='aes-256-gcm';
$ivlen= openssl_cipher_iv_length($cipher); // 12
if(preg_match('/^[/+=0-9a-zA-Z]+$/',$ciphertext)) {
$text1=base64_decode($ciphertext);
$tag=substr($text1,-16);
$iv =substr($text1,0,$ivlen);
$text1=substr($text1,$ivlen,-16);
$key=hex2bin($key);
$aad=hex2bin($aad);
$txt01=openssl_decrypt($text1,$cipher,$key,OPENSSL_RAW_DATA,$iv,$tag,$aad);
if($txt01===false) return '';
return $txt01;
} else return '';
}
$key='1100222233334444555566667777888899990000aaaabbbbccccddddeeeeffff';
$aad='22223311223311221122331122331122';
$ciphertext = encrypt_aes256gcm($key, b"a secret message!", $aad);
echo $ciphertext ."
";
$ssss=b'YO4uAtkNBFpKF8GRni8tT2IW6WUQRox8D1ujcCkPKtxYsbWHDdInvvjxqzN/';
$ciphertext = decrypt_aes256gcm($key, $ssss, $aad);
echo $ciphertext ."
";
golang
package main
//go build -ldflags "-w -s" -s:去掉符号信息 -w:去掉DWARF调试信息
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"strings"
)
func en_aesgcm(hex_key string, plaintext []byte, hex_aad string) (string, error) {
//秘钥长度按需:AES-128(16bytes)或者AES-256(32bytes)
key, _ := hex.DecodeString(hex_key)
aad, _ := hex.DecodeString(hex_aad)
block, err := aes.NewCipher(key) //生成加解密用的block
if err != nil {
return "", err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
// 对IV有随机性要求,但没有保密性要求,所以常见的做法是将IV包含在加密文本当中
iv := make([]byte, aesgcm.NonceSize()) // NonceSize=12
rand.Read(iv) //获取随机值
ciphertext := aesgcm.Seal(iv, iv, plaintext, aad) //加密,密文为:iv+密文+tag
//return base64.RawStdEncoding.EncodeToString(ciphertext), nil // 生成的BS64,无尾部的pad"="
return base64.StdEncoding.EncodeToString(ciphertext), nil // 生成的BS64
}
func de_aesgcm(hex_key string, cipherbs64 string, hex_aad string) ([]byte, error) {
//秘钥长度按需:AES-128(16bytes)或者AES-256(32bytes)
key, _ := hex.DecodeString(hex_key)
aad, _ := hex.DecodeString(hex_aad)
cipherbs64 = strings.TrimRight(cipherbs64, "=")
ciphertext, err := base64.RawStdEncoding.DecodeString(cipherbs64) // 要先去掉尾部的pad"=",否则解bs64失败
if err != nil {
return []byte(""), err
}
block, err := aes.NewCipher(key) //生成加解密用的block
if err != nil {
return []byte(""), err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return []byte(""), err
}
if len(ciphertext) <= aesgcm.NonceSize() { // 长度应该>iv
return []byte(""), errors.New("string: too short") //解密失败
}
iv := ciphertext[:aesgcm.NonceSize()] //分离出IV
ciphertext = ciphertext[aesgcm.NonceSize():] // 密文+tag
plaintext, err := aesgcm.Open(nil, iv, ciphertext, aad)
return plaintext, err //err!=nil时,plaintext=byte[]("")
}
func main() {
key := "1234567812345678123456781234567812345678123456781234567812345678"
aad := "11223344556677881122334455667788"
fmt.Printf("len(key),len(aad): %d,%d
", len(key), len(aad))
plaintext := []byte("this is a security text12")
v1, err := en_aesgcm(key, plaintext, aad)
fmt.Printf("加密结果: %s , %q
", v1, err)
v1 = "rkaaPGZmO/KtQrbePAjqxzN6y9yvmf4EFM6b/8rgkjp5RtOXgKU7m7qQTA3s40tHBfScOlc="
v3, err := de_aesgcm(key, v1, aad)
fmt.Printf("解密: %q , %q
", v3, err)
}