说明
- 主要用于隐私数据加密
- 使用128/256位ECB模式的AES加密算法
- 密钥联系技术支持获取(AES128密钥和AES256密钥不同,使用不同加密时记得获取相应的密钥)
注:对于外部出行人新增/修改接口不采用整体加密传输时只可采用AES128加密,密钥特殊,需单独申请
算法实现
php版本
AES128
<?php
class Aes
{
/**
* @desc aes加密
*
* @param $input 明文
* @param $key 密钥
* @return string 密文
*/
public function encrypt($input, $key)
{
$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$input = $this->pkcs5_pad($input, $size);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$data = base64_encode($data);
return $data;
}
/**
* @desc aes解密
*
* @param $cipher 密文
* @param $key 密钥
* @return bool|string 密文
*/
public function decrypt($cipher, $key)
{
$decrypted= mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$key,
base64_decode($cipher),
MCRYPT_MODE_ECB
);
$dec_s = strlen($decrypted);
$padding = ord($decrypted[$dec_s-1]);
$decrypted = substr($decrypted, 0, -$padding);
return $decrypted;
}
private function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
}
AES256
<?php
interface EncryptionStrategy {
public function encrypt($data, $key);
public function decrypt($encryptedData, $key);
}
class Aes256EncryptionStrategyImpl implements EncryptionStrategy {
private $cipher = 'AES-256-ECB';
/**
* 加密方法
* @param string $data 要加密的明文
* @param string $key 256 位(32 字节)的加密密钥
* @return string 加密并经过 Base64 编码后的密文
*/
public function encrypt($data, $key) {
// 检查密钥长度是否为 32 字节(256 位)
$keyBytes = hex2bin($key);
if (strlen($keyBytes) !== 32) {
throw new \InvalidArgumentException('Key must be 32 bytes (256 bits) long.');
}
// 执行加密操作,使用 OPENSSL_RAW_DATA 确保返回原始二进制数据
$encrypted = openssl_encrypt($data, $this->cipher, (string)$keyBytes, OPENSSL_RAW_DATA);
// 对加密后的二进制数据进行 Base64 编码
return $this->base64UrlEncode($encrypted);
}
/**
* 解密方法
* @param string $encryptedData 经过 Base64 编码的密文
* @param string $key 256 位(32 字节)的解密密钥
* @return string 解密后的明文
*/
public function decrypt($encryptedData, $key) {
// 检查密钥长度是否为 32 字节(256 位)
$keyBytes = hex2bin($key);
if (strlen($keyBytes) !== 32) {
throw new \InvalidArgumentException('Key must be 32 bytes (256 bits) long.');
}
// 对 Base64 编码的密文进行解码
$decodedCiphertext = $this->base64UrlDecode($encryptedData);
// 执行解密操作
return openssl_decrypt($decodedCiphertext, $this->cipher, (string)$keyBytes, OPENSSL_RAW_DATA);
}
function base64UrlEncode($data) {
// 标准 Base64 编码
$base64Encoded = base64_encode($data);
// 保留 = 号
return strtr($base64Encoded, '+/', '-_');
}
function base64UrlDecode($data) {
// 替换 - 和 _
$base64Encoded = strtr($data, '-_', '+/');
// 标准 Base64 解码
return base64_decode($base64Encoded);
}
}
go版本
AES128
package helper
import (
"encoding/base64"
"errors"
"fmt"
)
// Decrypt AES PKC#7解密
func Base64AESDecrypt(secretKey, ciphertext string) (response string, err error) {
defer func() {
if rErr := recover();rErr != nil{
err = errors.New(fmt.Sprintf("解密失败panic-%v",rErr))
//log.Trace.Errorf(context.Background(),consts.DL_TAG_PANIC_RECOVER,"msg=%v-%s",rErr,string(debug.Stack()))
}
}()
enc, err := base64.StdEncoding.DecodeString(ciphertext)
if err != nil {
// todo log
return
}
// ECB解密
origin, err := AesDecrypt(enc, []byte(secretKey))
if err != nil {
// todo log
return
}
// 使用PKCS#7对解密后的内容去除填充
response = string(PKCS7UnPadding(origin))
return
}
// Encrypt AES PKC#7解密
func Base64AESEncrypt(secretKey, content string) (response string, err error) {
defer func() {
if rErr := recover();rErr != nil{
err = errors.New(fmt.Sprintf("加密失败panic-%v",rErr))
//log.Trace.Errorf(context.Background(),consts.DL_TAG_PANIC_RECOVER,"msg=%v-%s",rErr,string(debug.Stack()))
}
}()
//使用PKCS#7对原文进行填充,BlockSize为16字节
ciphertext := PKCS7Padding([]byte(content), 16)
//ECB加密
crypted, err := AesEncrypt(ciphertext, []byte(secretKey))
if err != nil {
// todo log
return
}
response = base64.StdEncoding.EncodeToString(crypted)
return
}
package helper
// AES 解密逻辑处理
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"errors"
)
// AesEncrypt Aes/ECB模式的加密方法,PKCS7填充方式
func AesEncrypt(src, key []byte) ([]byte, error) {
Block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(src) == 0 {
return nil, errors.New("plaintext empty")
}
mode := NewECBEncrypter(Block)
ciphertext := src
mode.CryptBlocks(ciphertext, ciphertext)
return ciphertext, nil
}
// AesDecrypt Aes/ECB模式的解密方法,PKCS7填充方式
func AesDecrypt(src, key []byte) ([]byte, error) {
Block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(src) == 0 {
return nil, errors.New("plaintext empty")
}
mode := NewECBDecrypter(Block)
ciphertext := src
mode.CryptBlocks(ciphertext, ciphertext)
return ciphertext, nil
}
// ECB模式结构体
type ecb struct {
b cipher.Block
blockSize int
}
// 实例化ECB对象
func newECB(b cipher.Block) *ecb {
return &ecb{
b: b,
blockSize: b.BlockSize(),
}
}
// ECB加密类
type ecbEncrypter ecb
func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
return (*ecbEncrypter)(newECB(b))
}
func (x *ecbEncrypter) BlockSize() int {
return x.blockSize
}
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Encrypt(dst, src[:x.blockSize])
dst = dst[x.blockSize:]
src = src[x.blockSize:]
}
}
// ECB解密类
type ecbDecrypter ecb
func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
return (*ecbDecrypter)(newECB(b))
}
func (x *ecbDecrypter) BlockSize() int {
return x.blockSize
}
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Decrypt(dst, src[:x.blockSize])
dst = dst[x.blockSize:]
src = src[x.blockSize:]
}
}
// PKCS7Padding PKCS7填充
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
// PKCS7UnPadding PKCS7去除
func PKCS7UnPadding(ciphertext []byte) []byte {
length := len(ciphertext)
unpadding := int(ciphertext[length-1])
return ciphertext[:(length - unpadding)]
}
// ZerosPadding 零点填充
func ZerosPadding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(0)}, padding)
return append(ciphertext, padtext...)
}
// ZerosUnPadding 零点去除
func ZerosUnPadding(ciphertext []byte) []byte {
return bytes.TrimFunc(ciphertext, func(r rune) bool {
return r == rune(0)
})
}
AES256
java版本
请确认jdk在1.8.0_212版本之后,1.8.0_212版本之前会存在强制校验密钥长度的情况,此代码会报非法的密钥长度。

AES128
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class AesHelper {
private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
/**
* AES加密
*
* @param input 明文
* @param key 密钥
* @return 密文
* @throws Exception
*/
public static String encrypt(String input, String key) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypted = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
}
/**
* AES解密
*
* @param cipher 密文
* @param key 密钥
* @return 明文
* @throws Exception
*/
public static String decrypt(String cipher, String key) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
Cipher decipher = Cipher.getInstance(ALGORITHM);
decipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decrypted = decipher.doFinal(Base64.getDecoder().decode(cipher));
return new String(decrypted, StandardCharsets.UTF_8).trim();
}
public static void main(String[] args) {
try {
String key = "g4hh9cc33a969b610b05ed0e004d4e52";
String originalText = "312984412739843123";
String encryptedText = encrypt(originalText, key);
System.out.println("Encrypted: " + encryptedText);
String decryptedText = decrypt(encryptedText, key);
System.out.println("Decrypted: " + decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
}
AES256
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class Aes256Helper {
private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
public static String encrypt(String data, String hexKey) {
try {
// 十六进制转字节数组
byte[] keyBytes = hexToBytes(hexKey);
// 验证密钥长度
if (keyBytes.length != 32) {
throw new IllegalArgumentException("Key must be 32 bytes (256 bits) long.");
}
// 初始化加密器
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// 执行加密
byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
// URL安全Base64编码
return base64UrlEncode(encrypted);
} catch (Exception e) {
throw new RuntimeException("Encryption failed", e);
}
}
public static String decrypt(String encryptedData, String hexKey) {
try {
// 十六进制转字节数组
byte[] keyBytes = hexToBytes(hexKey);
// 验证密钥长度
if (keyBytes.length != 32) {
throw new IllegalArgumentException("Key must be 32 bytes (256 bits) long.");
}
// Base64解码
byte[] decoded = base64UrlDecode(encryptedData);
// 初始化解密器
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
// 执行解密
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted, StandardCharsets.UTF_8).trim();
} catch (Exception e) {
throw new RuntimeException("Decryption failed", e);
}
}
// Java密钥处理(与PHP的hex2bin对应)
public static byte[] hexToBytes(String hex) {
if (hex.length() % 2 != 0) {
throw new IllegalArgumentException();
}
byte[] bytes = new byte[hex.length() / 2];
for (int i = 0; i < hex.length(); i += 2) {
bytes[i/2] = (byte) Integer.parseInt(hex.substring(i, i+2), 16);
}
return bytes;
}
// 编码:替换 +/ 为 -_,保留 =
private static String base64UrlEncode(byte[] data) {
String base64 = Base64.getEncoder().encodeToString(data);
return base64.replace('+', '-').replace('/', '_');
}
// 解码:替换 -_ 为 +/,自动补全 =
private static byte[] base64UrlDecode(String input) {
String replaced = input.replace('-', '+').replace('_', '/');
// 补全缺失的 = 号(兼容 Java 8)
int padding = (4 - (replaced.length() % 4)) % 4;
StringBuilder sb = new StringBuilder(replaced);
for (int i = 0; i < padding; i++) {
sb.append('=');
}
return Base64.getDecoder().decode(sb.toString());
}
public static void main(String[] args) {
// 测试用例
String hexKey = "0495ad3bc8f9e8e9d425fde24af5ca03225465ef37e242c6243df32baf79f48e";
String original = "ent=2&companyId=1125909874810584&company_id=1125909874810584×tamp=1741774912437&offset=0&length=100";
// 加密
String encrypted = encrypt(original, hexKey);
System.out.println("加密结果: " + encrypted); // 例如:JzETiB6sW8R3wKwN...
// 解密
String decrypted = decrypt(encrypted, hexKey);
System.out.println("解密结果: " + decrypted); // 应与原始输入相同
}
}
Go版本
AES 128
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"reflect"
"strings"
"testing"
)
type AesTool struct {
key string
}
func NewAESTool(k string) *AesTool {
return &AesTool{
key: k,
}
}
func (a *AesTool) ECBEncrypt128(data interface{}) (s string, err error) {
defer func() {
if e := recover(); e != nil {
err = errors.New(e.(string))
}
}()
if data == nil {
return "", nil
}
// 类型转换处理器
var src []byte
switch v := data.(type) {
case []byte:
src = v
case string:
src = []byte(v)
default:
rv := reflect.Indirect(reflect.ValueOf(v))
if rv.Kind() == reflect.Struct {
jsonData, err := json.Marshal(v)
if err != nil {
return "", errors.New("json序列化失败")
}
src = jsonData
} else {
return "", errors.New("不支持的数据类型")
}
}
keyBytes, err := GenerateSecretKeyBytes(1, a.key)
if err != nil {
return "", err
}
ciphertext := PKCS7Padding([]byte(src), 16)
//ECB加密
crypted, err := AesEncrypt(ciphertext, keyBytes)
if err != nil {
return "", err
}
response := base64.StdEncoding.EncodeToString(crypted)
return response, nil
}
func (a *AesTool) ECBDecrypt128(src string) (s string, err error) {
defer func() {
if e := recover(); e != nil {
err = errors.New(e.(string))
}
}()
replacer := strings.NewReplacer("/", "_", "+", "-")
src = replacer.Replace(src)
// 自动补全填充符
if len(src)%4 != 0 {
src += strings.Repeat("=", (4-len(src)%4)%4)
}
enc, err := base64.URLEncoding.DecodeString(src)
if err != nil {
return "", err
}
keyBytes, err := GenerateSecretKeyBytes(1, a.key)
if err != nil {
return "", err
}
// ECB解密
origin, err := AesDecrypt(enc, []byte(keyBytes))
if err != nil {
return "", err
}
// 使用PKCS#7对解密后的内容去除填充
response := string(PKCS7UnPadding(origin))
return response, nil
}
func AesEncrypt(src, key []byte) ([]byte, error) {
Block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(src) == 0 {
return nil, errors.New("plaintext empty")
}
mode := NewECBEncrypter(Block)
ciphertext := src
mode.CryptBlocks(ciphertext, ciphertext)
return ciphertext, nil
}
// AesDecrypt Aes/ECB模式的解密方法,PKCS7填充方式
func AesDecrypt(src, key []byte) ([]byte, error) {
Block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(src) == 0 {
return nil, errors.New("plaintext empty")
}
mode := NewECBDecrypter(Block)
ciphertext := src
mode.CryptBlocks(ciphertext, ciphertext)
return ciphertext, nil
}
// ECB模式结构体
type ecb struct {
b cipher.Block
blockSize int
}
// 实例化ECB对象
func newECB(b cipher.Block) *ecb {
return &ecb{
b: b,
blockSize: b.BlockSize(),
}
}
// ECB加密类
type ecbEncrypter ecb
func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
return (*ecbEncrypter)(newECB(b))
}
func (x *ecbEncrypter) BlockSize() int {
return x.blockSize
}
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Encrypt(dst, src[:x.blockSize])
dst = dst[x.blockSize:]
src = src[x.blockSize:]
}
}
// ECB解密类
type ecbDecrypter ecb
func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
return (*ecbDecrypter)(newECB(b))
}
func (x *ecbDecrypter) BlockSize() int {
return x.blockSize
}
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Decrypt(dst, src[:x.blockSize])
dst = dst[x.blockSize:]
src = src[x.blockSize:]
}
}
// PKCS7Padding PKCS7填充
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
// PKCS7UnPadding PKCS7去除
func PKCS7UnPadding(ciphertext []byte) []byte {
length := len(ciphertext)
unpadding := int(ciphertext[length-1])
step := length - unpadding
if step < 0 {
return []byte{}
}
return ciphertext[:step]
}
// GenerateSecretKeyBytes 生成符合AES标准的密钥 ent=0返回空字符串,ent=1使用MD5(128bit),ent=2使用SHA256(256bit)
func GenerateSecretKeyBytes(ent int64, key string) ([]byte, error) {
switch ent {
case 0:
return []byte{}, nil
case 1:
return []byte(key), nil
case 2:
return HexToBin(key)
default:
return nil, errors.New("生成秘钥失败:ent只能是0、1、2")
}
}
func HexToBin(hexStr string) ([]byte, error) {
if len(hexStr)%2 != 0 {
return nil, errors.New("密钥长度必须是128或者256")
}
binData, err := hex.DecodeString(hexStr)
if err != nil {
return nil, errors.New("密钥长度必须是128或者256")
}
return binData, nil
}
//单测用例
func TestAesTool_ECBEncrypt128(t *testing.T) {
type fields struct {
key string
}
type args struct {
data interface{}
}
tests := []struct {
name string
fields fields
args args
wantS string
wantErr bool
}{
{
name: "128加密",
fields: fields{key: "64ecd6a08ced45ad5d7fedd0c347f6c9"},
args: args{data: "{\"phone\": \"00016270252\",\"birth_date\": \"2050-01-01\", \"name\": \"\\u5916\\u90e8\\u51fa\\u884c\\u4eba_\\u6d4b\\u8bd5_1\", \"card_list\": [{\"card_type\": 1, \"card_no\": \"513126199803290017\", \"expire_date\": \"2050-01-01\"}]}"},
wantS: "UyCHdn/a5NOCBo9iY+3bTk9hsa4wFK6w1JBjc6L/LKxBuG2/uEgWleRsdtsFT1T6ZkJsbHGC3CBis3IxZN5//SxrZT2VB0gbiewV0cLQH4re6ekMTLWu6AKtJ4IU9ys62QApFypCWVUy2aGlN9WbhvIRD5iJYgXD2J5CIJ5xbpBpzMvLqiBfb3tmicVI3+p8hxXxfSqKr2z99BMzQiFeSsL0TkGniLHUUiuYmfkZVblpnhqYuKidE6Xzeqh6vvMVxlmUjUZ3ZPkrWx+b6ypbTg==",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &AesTool{
key: tt.fields.key,
}
gotS, err := a.ECBEncrypt128(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("ECBEncrypt128() error = %v, wantErr %v", err, tt.wantErr)
return
}
if gotS != tt.wantS {
t.Errorf("ECBEncrypt128() gotS = %v, want %v", gotS, tt.wantS)
}
})
}
}
func TestAesTool_ECBDecrypt128(t *testing.T) {
type fields struct {
key string
}
type args struct {
src string
}
tests := []struct {
name string
fields fields
args args
wantS string
wantErr bool
}{
{
name: "128解密",
fields: fields{key: "64ecd6a08ced45ad5d7fedd0c347f6c9"},
args: args{src: "UyCHdn/a5NOCBo9iY+3bTk9hsa4wFK6w1JBjc6L/LKxBuG2/uEgWleRsdtsFT1T6ZkJsbHGC3CBis3IxZN5//SxrZT2VB0gbiewV0cLQH4re6ekMTLWu6AKtJ4IU9ys62QApFypCWVUy2aGlN9WbhvIRD5iJYgXD2J5CIJ5xbpBpzMvLqiBfb3tmicVI3+p8hxXxfSqKr2z99BMzQiFeSsL0TkGniLHUUiuYmfkZVblpnhqYuKidE6Xzeqh6vvMVxlmUjUZ3ZPkrWx+b6ypbTg=="},
wantS: "{\"phone\": \"00016270252\",\"birth_date\": \"2050-01-01\", \"name\": \"\\u5916\\u90e8\\u51fa\\u884c\\u4eba_\\u6d4b\\u8bd5_1\", \"card_list\": [{\"card_type\": 1, \"card_no\": \"513126199803290017\", \"expire_date\": \"2050-01-01\"}]}",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &AesTool{
key: tt.fields.key,
}
gotS, err := a.ECBDecrypt128(tt.args.src)
if (err != nil) != tt.wantErr {
t.Errorf("ECBDecrypt128() error = %v, wantErr %v", err, tt.wantErr)
return
}
if gotS != tt.wantS {
t.Errorf("ECBDecrypt128() gotS = %v, want %v", gotS, tt.wantS)
}
})
}
}
AES 256
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"reflect"
"strings"
"testing"
)
type AesTool struct {
key string
}
func NewAESTool(k string) *AesTool {
return &AesTool{
key: k,
}
}
func (a *AesTool) ECBEncrypt256(data interface{}) (s string, err error) {
defer func() {
if e := recover(); e != nil {
err = errors.New(e.(string))
}
}()
if data == nil {
return "", nil
}
// 类型转换处理器
var src []byte
switch v := data.(type) {
case []byte:
src = v
case string:
src = []byte(v)
default:
rv := reflect.Indirect(reflect.ValueOf(v))
if rv.Kind() == reflect.Struct {
jsonData, err := json.Marshal(v)
if err != nil {
return "", errors.New("json序列化失败")
}
src = jsonData
} else {
return "", errors.New("不支持的数据类型")
}
}
keyBytes, err := GenerateSecretKeyBytes(2, a.key)
if err != nil {
return "", err
}
ciphertext := PKCS7Padding([]byte(src), 16)
//ECB加密
crypted, err := AesEncrypt(ciphertext, keyBytes)
if err != nil {
return "", err
}
enc := base64.URLEncoding.WithPadding(base64.StdPadding)
response := enc.EncodeToString(crypted)
return response, nil
}
func (a *AesTool) ECBDecrypt256(src string) (s string, err error) {
defer func() {
if e := recover(); e != nil {
err = errors.New(e.(string))
}
}()
replacer := strings.NewReplacer("/", "_", "+", "-")
src = replacer.Replace(src)
// 自动补全填充符
if len(src)%4 != 0 {
src += strings.Repeat("=", (4-len(src)%4)%4)
}
enc, err := base64.URLEncoding.DecodeString(src)
if err != nil {
return "", err
}
keyBytes, err := GenerateSecretKeyBytes(2, a.key)
if err != nil {
return "", err
}
// ECB解密
origin, err := AesDecrypt(enc, []byte(keyBytes))
if err != nil {
return "", err
}
// 使用PKCS#7对解密后的内容去除填充
response := string(PKCS7UnPadding(origin))
return response, nil
}
func (a *AesTool) ECBEncrypt128(data interface{}) (s string, err error) {
defer func() {
if e := recover(); e != nil {
err = errors.New(e.(string))
}
}()
if data == nil {
return "", nil
}
// 类型转换处理器
var src []byte
switch v := data.(type) {
case []byte:
src = v
case string:
src = []byte(v)
default:
rv := reflect.Indirect(reflect.ValueOf(v))
if rv.Kind() == reflect.Struct {
jsonData, err := json.Marshal(v)
if err != nil {
return "", errors.New("json序列化失败")
}
src = jsonData
} else {
return "", errors.New("不支持的数据类型")
}
}
keyBytes, err := GenerateSecretKeyBytes(1, a.key)
if err != nil {
return "", err
}
ciphertext := PKCS7Padding([]byte(src), 16)
//ECB加密
crypted, err := AesEncrypt(ciphertext, keyBytes)
if err != nil {
return "", err
}
response := base64.StdEncoding.EncodeToString(crypted)
return response, nil
}
func (a *AesTool) ECBDecrypt128(src string) (s string, err error) {
defer func() {
if e := recover(); e != nil {
err = errors.New(e.(string))
}
}()
replacer := strings.NewReplacer("/", "_", "+", "-")
src = replacer.Replace(src)
// 自动补全填充符
if len(src)%4 != 0 {
src += strings.Repeat("=", (4-len(src)%4)%4)
}
enc, err := base64.URLEncoding.DecodeString(src)
if err != nil {
return "", err
}
keyBytes, err := GenerateSecretKeyBytes(1, a.key)
if err != nil {
return "", err
}
// ECB解密
origin, err := AesDecrypt(enc, []byte(keyBytes))
if err != nil {
return "", err
}
// 使用PKCS#7对解密后的内容去除填充
response := string(PKCS7UnPadding(origin))
return response, nil
}
func AesEncrypt(src, key []byte) ([]byte, error) {
Block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(src) == 0 {
return nil, errors.New("plaintext empty")
}
mode := NewECBEncrypter(Block)
ciphertext := src
mode.CryptBlocks(ciphertext, ciphertext)
return ciphertext, nil
}
// AesDecrypt Aes/ECB模式的解密方法,PKCS7填充方式
func AesDecrypt(src, key []byte) ([]byte, error) {
Block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(src) == 0 {
return nil, errors.New("plaintext empty")
}
mode := NewECBDecrypter(Block)
ciphertext := src
mode.CryptBlocks(ciphertext, ciphertext)
return ciphertext, nil
}
// ECB模式结构体
type ecb struct {
b cipher.Block
blockSize int
}
// 实例化ECB对象
func newECB(b cipher.Block) *ecb {
return &ecb{
b: b,
blockSize: b.BlockSize(),
}
}
// ECB加密类
type ecbEncrypter ecb
func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
return (*ecbEncrypter)(newECB(b))
}
func (x *ecbEncrypter) BlockSize() int {
return x.blockSize
}
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Encrypt(dst, src[:x.blockSize])
dst = dst[x.blockSize:]
src = src[x.blockSize:]
}
}
// ECB解密类
type ecbDecrypter ecb
func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
return (*ecbDecrypter)(newECB(b))
}
func (x *ecbDecrypter) BlockSize() int {
return x.blockSize
}
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Decrypt(dst, src[:x.blockSize])
dst = dst[x.blockSize:]
src = src[x.blockSize:]
}
}
// PKCS7Padding PKCS7填充
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
// PKCS7UnPadding PKCS7去除
func PKCS7UnPadding(ciphertext []byte) []byte {
length := len(ciphertext)
unpadding := int(ciphertext[length-1])
step := length - unpadding
if step < 0 {
return []byte{}
}
return ciphertext[:step]
}
// GenerateSecretKeyBytes 生成符合AES标准的密钥 ent=0返回空字符串,ent=1使用MD5(128bit),ent=2使用SHA256(256bit)
func GenerateSecretKeyBytes(ent int64, key string) ([]byte, error) {
switch ent {
case 0:
return []byte{}, nil
case 1:
return []byte(key), nil
case 2:
return HexToBin(key)
default:
return nil, errors.New("生成秘钥失败:ent只能是0、1、2")
}
}
func HexToBin(hexStr string) ([]byte, error) {
if len(hexStr)%2 != 0 {
return nil, errors.New("密钥长度必须是128或者256")
}
binData, err := hex.DecodeString(hexStr)
if err != nil {
return nil, errors.New("密钥长度必须是128或者256")
}
return binData, nil
}
//AES256单测用例
func TestAesTool_ECBEncrypt256(t *testing.T) {
type fields struct {
key string
}
type args struct {
data interface{}
}
tests := []struct {
name string
fields fields
args args
wantS string
wantErr bool
}{
{
name: "256加密",
fields: fields{key: "a84c3b673ce6afee65c3c60917c5d0a945504539b8227a827194278b8d1fe77e"},
args: args{data: "{\"phone\": \"00016270252\",\"birth_date\": \"2050-01-01\", \"name\": \"\\u5916\\u90e8\\u51fa\\u884c\\u4eba_\\u6d4b\\u8bd5_1\", \"card_list\": [{\"card_type\": 1, \"card_no\": \"513126199803290017\", \"expire_date\": \"2050-01-01\"}]}"},
wantS: "ARasLgstrPRPcLXHvI2r1c17OcPui760okbQp5j8ejzOHX4FaBGN-AvsF-x4DUcD9UPS4ovSavh04q2QGYGkeoNyeSkWAzTvfGiX_8t_hLCGOmfaKhnpxhHluLulZE86yDjYt2dYwinmmOO1XNnmajDVGHqIRfYYHK2Grgf6K3wcgGu1wgahhkG0rBPIAI3Y26E3x_INAZZ4EJSxSiH8rx_UzxOz8gLDr53hDyrG1PuUtDdz9bY7lHVGf8oDe_biF1zvqwwOwfZ2uY5bXmxoMA==", // MD5生成16字节密钥:ml-citation{ref="1,4" data="citationList"}
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &AesTool{
key: tt.fields.key,
}
gotS, err := a.ECBEncrypt256(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("ECBEncrypt256() error = %v, wantErr %v", err, tt.wantErr)
return
}
if gotS != tt.wantS {
t.Errorf("ECBEncrypt256() gotS = %v, want %v", gotS, tt.wantS)
}
})
}
}
func TestAesTool_ECBDecrypt256(t *testing.T) {
type fields struct {
key string
}
type args struct {
src string
}
tests := []struct {
name string
fields fields
args args
wantS string
wantErr bool
}{
{
name: "256解密",
fields: fields{key: "a84c3b673ce6afee65c3c60917c5d0a945504539b8227a827194278b8d1fe77e"},
args: args{src: "ARasLgstrPRPcLXHvI2r1c17OcPui760okbQp5j8ejzOHX4FaBGN-AvsF-x4DUcD9UPS4ovSavh04q2QGYGkeoNyeSkWAzTvfGiX_8t_hLCGOmfaKhnpxhHluLulZE86yDjYt2dYwinmmOO1XNnmajDVGHqIRfYYHK2Grgf6K3wcgGu1wgahhkG0rBPIAI3Y26E3x_INAZZ4EJSxSiH8rx_UzxOz8gLDr53hDyrG1PuUtDdz9bY7lHVGf8oDe_biF1zvqwwOwfZ2uY5bXmxoMA=="},
wantS: "{\"phone\": \"00016270252\",\"birth_date\": \"2050-01-01\", \"name\": \"\\u5916\\u90e8\\u51fa\\u884c\\u4eba_\\u6d4b\\u8bd5_1\", \"card_list\": [{\"card_type\": 1, \"card_no\": \"513126199803290017\", \"expire_date\": \"2050-01-01\"}]}", // MD5生成16字节密钥:ml-citation{ref="1,4" data="citationList"}
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &AesTool{
key: tt.fields.key,
}
gotS, err := a.ECBDecrypt256(tt.args.src)
if (err != nil) != tt.wantErr {
t.Errorf("ECBDecrypt256() error = %v, wantErr %v", err, tt.wantErr)
return
}
if gotS != tt.wantS {
t.Errorf("ECBDecrypt256() gotS = %v, want %v", gotS, tt.wantS)
}
})
}
}
版本记录
|
日期 |
更新内容 |
上线时间 |
|---|---|---|
|
2025.3.24 |
增加AES256各版本加密算法 |
2025.3.24 |
|
2025.05.08 |
java版本加密算法对版本的要求 |
2025.05.08 |