gpt4 book ai didi

go - Go中AES-GCM + Base64后无法解密

转载 作者:IT王子 更新时间:2023-10-29 00:43:28 26 4
gpt4 key购买 nike

情况

我正在尝试实现一个结构(CryptoService),从主程序流中隐藏加密/解密。我已经实现了“正常”函数和 base64 变体,它们应该将密码编码为它的 base64 等价物,反之亦然。这是因为我们的内部网络协议(protocol)使用换行符 \n 作为分隔符。

见下面的实现代码

问题

写完下面的代码后我开始测试它。起初一切顺利,加密和解密工作正常,但很快我开始注意到解密过程中“随机发生”的错误:cipher: message authentication failed。现在重要的事实是:DecryptBase64 函数返回的错误。但是 base64 在 go 中的使用非常简单,不用担心,所以我不知道问题出在哪里。

代码

下面是我的 CryptoService 实现代码和相关的测试文件。我尝试在不删除上下文的情况下尽可能多地清理代码(删除注释、额外的输入检查等)。尽管如此,还是有很多代码,所以感谢所有阅读它的人 - 非常感谢您的帮助!

cryptoservice.go

type CryptoService struct {
gcm cipher.AEAD
}

func NewCryptoService(key []byte) (cs *CryptoService, err error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
return &CryptoService{
gcm: gcm,
}, nil
}

func (cs CryptoService) Encrypt(plain []byte) (cipher []byte, err error) {
nonce := make([]byte, cs.gcm.NonceSize())
_, err = io.ReadFull(rand.Reader, nonce)
if err != nil {
return nil, err
}

cipher = cs.gcm.Seal(nil, nonce, plain, nil)
cipher = append(nonce, cipher...)

return cipher, nil
}

func (cs CryptoService) EncryptBase64(plain []byte) (base64Cipher []byte, err error) {
cipher, err := cs.Encrypt(plain)
if err != nil {
return nil, err
}

base64Cipher = make([]byte, base64.StdEncoding.EncodedLen(len(cipher)))
base64.StdEncoding.Encode(base64Cipher, cipher)

return
}

func (cs CryptoService) Decrypt(cipher []byte) (plain []byte, err error) {
nonce := cipher[0:cs.gcm.NonceSize()]
ciphertext := cipher[cs.gcm.NonceSize():]

plain, err = cs.gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
}

return
}

func (cs CryptoService) DecryptBase64(base64Cipher []byte) (plain []byte, err error) {
cipher := make([]byte, base64.StdEncoding.DecodedLen(len(base64Cipher)))
_, err = base64.StdEncoding.Decode(cipher, base64Cipher)
if err != nil {
return nil, err
}

return cs.Decrypt(cipher)
}

cryptoservice_test.go

  • TestCryptoService_EncryptDecryptRoundtrip 工作正常
  • TestCryptoService_EncryptBase64DecryptBase64Roundtrip“有时”失败(另请注意,它并不总是在相同的测试用例上失败)

附加信息:动态测试用例创建中的 FastRandomString(n int) 函数实际上只是从接受的答案中复制粘贴:How to generate a random string of a fixed length in golang?

func TestCryptoService_EncryptDecryptRoundtrip(t *testing.T) {
tests := []struct {
name string
aeskey string
text string
}{
{"Simple 1", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", "Text"},
{"Simple 2", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", "Some random content"},
{"Simple 3", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua."},

{"Dynamic 1", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", FastRandomString(32)},
{"Dynamic 2", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", FastRandomString(1024)},
{"Dynamic 3", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", FastRandomString(1024 * 64)},
{"Dynamic 4", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", FastRandomString(1024 * 256)},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for i := 0; i < 1000; i++ {
key, _ := hex.DecodeString(tt.aeskey)
cs, _ := NewCryptoService(key)
cipher, err := cs.Encrypt([]byte(tt.text))
if err != nil {
t.Errorf("CryptoService.Encrypt() error = %v", err)
return
}

plain, err := cs.Decrypt(cipher)
if err != nil {
t.Errorf("CryptoService.Decrypt() error = %v", err)
return
}

plainStr := string(plain)
if plainStr != tt.text {
t.Errorf("CryptoService.Decrypt() plain = %v, want = %v", plainStr, tt.text)
return
}
}
})
}
}

func TestCryptoService_EncryptBase64DecryptBase64Roundtrip(t *testing.T) {
tests := []struct {
name string
aeskey string
text string
}{
{"Simple 1", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", "Text"},
{"Simple 2", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", "Some random content"},
{"Simple 3", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua."},

{"Dynamic 1", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", FastRandomString(32)},
{"Dynamic 2", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", FastRandomString(1024)},
{"Dynamic 3", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", FastRandomString(1024 * 64)},
{"Dynamic 4", "c4cc0dfc4ae0e45c045727f84ffd373127453bc232230bf1386972ac692436c1", FastRandomString(1024 * 256)},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for i := 0; i < 1000; i++ {
key, _ := hex.DecodeString(tt.aeskey)
cs, _ := NewCryptoService(key)
cipher, err := cs.EncryptBase64([]byte(tt.text))
if err != nil {
t.Errorf("CryptoService.EncryptBase64() error = %v", err)
return
}

plain, err := cs.DecryptBase64(cipher)
if err != nil {
t.Errorf("CryptoService.DecryptBase64() error = %v", err)
return
}

plainStr := string(plain)
if plainStr != tt.text {
t.Errorf("CryptoService.DecryptBase64() plain = %v, want = %v", plainStr, tt.text)
return
}
}
})
}
}

最佳答案

GopherSlack 社区的某个人提出了解决方案:

StdEncoding 填充它的结果,在这种情况下,当(在加密过程中)需要填充输出时,会导致解密问题。因此,您应该在此示例中使用 RawStdEncoding

感谢您的帮助! :)

关于go - Go中AES-GCM + Base64后无法解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47382035/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com