- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在尝试实现一个结构(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/
我想我理解 GCM 的新 notification_key 功能背后的基本原理是“只需将消息发送给用户并且只让他们阅读一次”。我从文档的这一部分推断出来: With user notification
我实现了网络推送通知。获取错误的步骤: 打开网站 订阅推送通知 通过 gcm 发送许多推送 - 一切正常 关闭网站标签 发送推送和接收“双推送”- 第一个正常,第二个是“此站点已在后台更新” 重新打开
我正在手机上测试 GCM。 (2.3.6 安卓). list 文件(MainActivity、First 和 Second Activity 不执行任何操作,它们用于其他一些测试目的,不干扰 GCM)
首先,我是 iOS 开发的新手,也是 swift 的新手。我正在尝试让适用于 iOS 的谷歌云消息传递示例。 我已经从 https://developers.google.com/cloud-mess
你们中的任何人都可以提供 GCM 推送通知的代码,其中消息从移动设备推送到 GCM 服务器。我已经从 GCM 服务器到移动设备及其工作进行了操作,但我不知道反之亦然如何操作。任何人都可以提供帮助吗?谢
我们有两个不同的应用程序,但都需要来自 Google Cloud Messages 的相同推送通知,并且我在两个应用程序中只使用了一个发件人 ID(启用 Google 控制台之一的项目编号)。 这样做
我有一个广播接收器,当应用程序打开并在后台时,它会检测即将到来的通知,但当最近的应用程序被清除时,接收器无法工作,请给我建议。 public class GcmBroadcastReceiver ex
我想从我的应用程序向 GCM 服务器发送一个心跳信号,以便连接保持有效。 我该怎么做,我怎么知道我的 GCM 服务器的 URL? 提前致谢! 最佳答案 如何发送心跳 这个类可以发送正确的 Intent
新的 GCM 3.0 应该允许 GCM 自动显示从服务器发送的通知,如果它们包含 notification 参数。 如 docs 中所述: The notification parameter wit
这个问题在这里已经有了答案: Do I need to migrate GCM to FCM on client side? (2 个答案) 关闭 3 年前。 Google 已于 2018 年 4
我遇到了 GCM 推送通知无法正确到达 Android 设备的问题。经过几天的研究,我发现 Android 设备使用心跳来保持与 GCM 服务的连接。遗憾的是,心跳似乎太高了,因此 Android 设
阅读堆栈溢出 2 天后我做了什么: 问题关键字:“Apple-Mach-O 链接器错误”、“libGcmLib.a(GCMRmqManager.o) ", sqlite3", "GCMRmq2Pers
我已经从 GCM 订阅了主题,当我通过 Android 设置删除所有应用程序数据时,GCM token 是相同的,关于主题的 GCM 通知仍然可用,所以我收到了我不想收到的通知。 我的问题是: 如何从
由于 gcm 已弃用,我们希望迁移我们的代码。正如在谷歌的迁移指南中提到的那样,对于我们的服务器应用程序,应该只需要将端点从 gcm 更改为 fcm。应用迁移已成功完成。 我们现在使用的是 com.g
这只发生在我的 Kyocera Rise 上。我有一个依赖 GCM 在手机之间进行通信的应用程序。我的 Nexus 4 和我的 HTC One X 之间的通信工作正常,每当我发送推送通知时,两部手机都
我遇到了与 this 相同的问题.我会尝试提供更多信息。 我正在使用 Play Framework,用 Java 编写。我写了一个叫做 PushNotificationQueue 的插件。 PushN
我需要在我的应用程序中接收来自不同发件人的推送通知。会成功吗? 最佳答案 你的问题的答案是是! 根据 GCM 的官方文档,您的应用可以接收来自多个发件人的消息(限制为 100 个不同的发件人),并且您
我有一个使用 GCM 推送通知的应用程序。它工作正常,我的设备注册并接收推送消息。 如果我从我的设备上卸载该应用程序,我将不再像您期望的那样收到消息。在我卸载应用程序后,您在服务器上发送消息的文本框仍
我正在处理另一个开发人员的现有项目,我需要获取 PubNub 设置的 GCM 服务器 key ,因为它被意外删除了。 有什么方法可以从 Google 设置中检索它?我在凭据和项目设置中找不到它。 我暂
嘿,我在调用 `subscribeToTopicP 类时遇到了一些 Gcm Intent 服务的问题,总是出现空指针异常。 这是我的代码: GcmIntentService.java private
我是一名优秀的程序员,十分优秀!