Go语言字符串加密解密出现字符丢失问题排查
问题分析与解决
一、加密后出现大量0、解密丢失数据的原因
你直接使用AES块密码的Encrypt方法处理数据,但AES的块大小固定为16字节。你的令牌长度远超过16字节,cipher.Encrypt仅会加密第一个16字节的块,剩余字节因make([]byte, len(original))初始化默认值为0,最终输出的十六进制字符串后段全是0。
解密时同理,cipher.Decrypt也只处理第一个16字节的块,后续的0解密后仍为0,转成字符串就丢失了原令牌的剩余内容。
解决方法
不能直接用块密码的原始Encrypt/Decrypt方法处理超过块大小的数据,必须使用分组密码模式(如CBC、GCM)。推荐使用GCM模式,它同时提供加密和认证,安全性更高,示例代码如下:
import ( "crypto/aes" "crypto/cipher" CR "crypto/rand" "encoding/hex" "log" ) var key = make([]byte, 32) func init() { // 程序启动时初始化密钥,比单独函数更可靠 _, err := CR.Read(key) if err != nil { log.Fatalf("生成密钥失败: %v", err) } } func encryptToken(t token) string { plaintext := []byte(t.ID) block, err := aes.NewCipher(key) if err != nil { log.Fatalf("创建密码器失败: %v", err) } // GCM模式需要随机nonce gcm, err := cipher.NewGCM(block) if err != nil { log.Fatalf("创建GCM模式失败: %v", err) } nonce := make([]byte, gcm.NonceSize()) _, err = CR.Read(nonce) if err != nil { log.Fatalf("生成nonce失败: %v", err) } // 加密结果格式: nonce + 密文 + 认证标签 ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) return hex.EncodeToString(ciphertext) } func decryptToken(s string) string { ciphertext, err := hex.DecodeString(s) if err != nil { log.Fatalf("十六进制解码失败: %v", err) } block, err := aes.NewCipher(key) if err != nil { log.Fatalf("创建密码器失败: %v", err) } gcm, err := cipher.NewGCM(block) if err != nil { log.Fatalf("创建GCM模式失败: %v", err) } nonceSize := gcm.NonceSize() if len(ciphertext) < nonceSize { log.Fatal("密文长度过短") } nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { log.Fatalf("解密失败: %v", err) } return string(plaintext) }
二、修改密钥长度触发panic的原因
AES算法仅支持三种密钥长度:16字节(AES-128)、24字节(AES-192)、32字节(AES-256)。若你将密钥长度改为这三个值之外的数值,aes.NewCipher会返回非nil错误,此时cipher变量为nil,后续调用cipher.Encrypt或cipher.Decrypt就会触发空指针引用panic。
另外你的createKey函数存在语法问题:函数内的err变量未声明,会导致编译错误。建议将密钥初始化放在init函数中,确保程序启动时完成密钥生成,避免使用未初始化的密钥。
内容的提问来源于stack exchange,提问作者John Harrington
相关产品推荐
相关产品推荐

