You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang AES解密无法还原完整UUID问题求助及原因分析

问题原因
  1. 单块加密限制:你直接调用aes.Cipher的Encrypt/Decrypt方法,该方法仅支持处理16字节的单个AES数据块。你的UUID长度为36字节,超出单块容量,因此只有前16字节被加密,剩余20字节在加密过程中保持初始的0值。
  2. 空字符截断:解密后字节数组中存在大量\x00空字符,Go将字节数组转换为字符串时,会把\x00视为字符串终止标记,导致后续内容无法显示。
解决办法

AES作为块加密算法,必须配合分组模式(如GCM、CBC)和填充方案才能处理任意长度的数据。推荐使用GCM模式,它同时提供加密和数据完整性认证,安全性更高。

以下是修正后的GCM模式实现代码:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
)

func main() {
	key := "thisis32bitlongpassphraseimusing" // 32字节对应AES-256
	pt := "a30a1777-e9f4-ed45-4755-add00172ebae"

	ct, err := EncryptAESGCM([]byte(key), []byte(pt))
	if err != nil {
		panic(err)
	}
	fmt.Println("明文:", pt)
	fmt.Println("密文(hex):", hex.EncodeToString(ct))

	decrypted, err := DecryptAESGCM([]byte(key), ct)
	if err != nil {
		panic(err)
	}
	fmt.Println("解密结果:", string(decrypted))
}

// EncryptAESGCM 使用AES-GCM模式加密数据
func EncryptAESGCM(key, plaintext []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	// GCM模式需要随机Nonce,推荐长度12字节
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	nonce := make([]byte, gcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return nil, err
	}

	// 加密:密文 = Nonce + GCM加密结果(包含认证标签)
	ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
	return ciphertext, nil
}

// DecryptAESGCM 使用AES-GCM模式解密数据
func DecryptAESGCM(key, ciphertext []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	nonceSize := gcm.NonceSize()
	if len(ciphertext) < nonceSize {
		return nil, fmt.Errorf("密文长度不足")
	}

	nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
	if err != nil {
		return nil, err // 验证失败,可能密文被篡改
	}
	return plaintext, nil
}

关键说明

  • Nonce:每次加密必须使用唯一的随机Nonce,不能重复使用,否则会导致密钥泄露。GCM推荐Nonce长度为12字节。
  • 密文结构:加密后的密文包含Nonce + 加密数据 + 认证标签,解密时需要先分离Nonce。
  • 安全性:GCM模式会自动验证数据完整性,若密文被篡改,解密会直接报错,避免恶意数据被解密。

如果需要使用CBC模式(需手动处理填充),可以参考以下实现:

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
)

// PKCS7填充
func pkcs7Pad(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padText := make([]byte, padding)
	for i := range padText {
		padText[i] = byte(padding)
	}
	return append(data, padText...)
}

// PKCS7去填充
func pkcs7Unpad(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, fmt.Errorf("空数据")
	}
	padding := int(data[length-1])
	if padding > length || padding == 0 {
		return nil, fmt.Errorf("填充无效")
	}
	return data[:length-padding], nil
}

func EncryptAESCBC(key, plaintext []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	// CBC需要IV,长度等于块大小(16字节)
	iv := make([]byte, aes.BlockSize)
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}

	// 填充明文到块大小倍数
	paddedPlaintext := pkcs7Pad(plaintext, aes.BlockSize)

	mode := cipher.NewCBCEncrypter(block, iv)
	ciphertext := make([]byte, len(paddedPlaintext))
	mode.CryptBlocks(ciphertext, paddedPlaintext)

	// 密文 = IV + 加密数据
	return append(iv, ciphertext...), nil
}

func DecryptAESCBC(key, ciphertext []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	if len(ciphertext) < aes.BlockSize {
		return nil, fmt.Errorf("密文长度不足")
	}

	iv := ciphertext[:aes.BlockSize]
	ciphertext = ciphertext[aes.BlockSize:]

	mode := cipher.NewCBCDecrypter(block, iv)
	plaintext := make([]byte, len(ciphertext))
	mode.CryptBlocks(plaintext, ciphertext)

	// 去除填充
	return pkcs7Unpad(plaintext)
}

func main() {
	key := "thisis32bitlongpassphraseimusing"
	pt := "a30a1777-e9f4-ed45-4755-add00172ebae"

	ct, err := EncryptAESCBC([]byte(key), []byte(pt))
	if err != nil {
		panic(err)
	}
	fmt.Println("明文:", pt)
	fmt.Println("密文(hex):", hex.EncodeToString(ct))

	decrypted, err := DecryptAESCBC([]byte(key), ct)
	if err != nil {
		panic(err)
	}
	fmt.Println("解密结果:", string(decrypted))
}

内容的提问来源于stack exchange,提问作者Ananda G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 10:35:48