Go语言使用AES加密无法处理超4096字节文本的问题求解
问题根源
你遇到的长文本截断问题和AES模块本身没有任何关系。Go标准库的AES-CFB实现是流式加密,不存在内置的长度限制,只要传入的明文完整,多长的内容都可以正常加密。
截断的真正原因是bufio.Reader的默认行为:你每次调用bufio.NewReader(os.Stdin)创建的读取器默认缓冲区大小为4096字节,当输入的单行文本长度超过这个阈值时,ReadString('\n')只会返回缓冲区中已读取的前4096字节内容,完整的长文本根本没有传入加密函数。
另外你在循环中重复创建新的bufio.Reader的写法本身也有问题,会丢弃上一次读取残留在缓冲区中的内容,进一步导致输入读取不完整。
修复方案
有两种简单的方案可以解决这个问题:
- 方案1:全局只创建一次bufio.Reader,初始化时手动指定足够大的缓冲区尺寸,覆盖你需要处理的最大文本长度
- 方案2:如果不需要按行交互读取,可以直接用
io.ReadAll一次性读取标准输入的全部内容,完全绕开缓冲区长度限制
修正后的参考代码
package main import ( "bufio" "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" "fmt" "io" "os" "strings" ) func encrypt(text, keyText string) string { key := []byte(keyText) plaintext := []byte(text) block, err := aes.NewCipher(key) if err != nil { panic(err) } ciphertext := make([]byte, aes.BlockSize+len(plaintext)) iv := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { panic(err) } stream := cipher.NewCFBEncrypter(block, iv) stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) return base64.URLEncoding.EncodeToString(ciphertext) } func main() { fmt.Println("Encryption Program v1.0.0 ~ by: Sam Sepiol") fmt.Print("[Encryption Key (32 bytes)]>>: ") // 全局只创建一次reader,指定10MB缓冲区,足够覆盖绝大多数长文本场景 in := bufio.NewReaderSize(os.Stdin, 10*1024*1024) plaintextKey, err := in.ReadString('\n') if err != nil { fmt.Println("Error reading key") return } plaintextKey = strings.TrimRight(plaintextKey, "\r\n") // 同时兼容windows和unix换行符 for { fmt.Print(">> ") plaintext, err := in.ReadString('\n') if err != nil { fmt.Println("Error reading plaintext") continue } plaintext = strings.TrimRight(plaintext, "\r\n") result := encrypt(plaintext, plaintextKey) fmt.Printf("\n\n%s\n\n", result) } }
额外提示
你当前使用的CFB加密模式没有完整性校验,攻击者可以篡改密文而不被发现,如果你的场景需要防篡改,可以替换为AES-GCM模式;如果只是为了避免字符串被直接从二进制文件中明文提取,当前的CFB模式已经可以满足需求。
内容的提问来源于stack exchange,提问作者Sam Sepiol
相关产品推荐
相关产品推荐

