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) }