英文:
Extract tag from cipher aes 256 GCM Golang
问题
我已经翻译了你提供的内容,请查看以下翻译结果:
我在Ruby中有加密和解密的代码,并尝试用Go重写。我逐步尝试,所以从Ruby中的加密开始,然后尝试在Go中解密,这部分是可以工作的。但是当我尝试在Go中编写加密并在Ruby中解密时遇到了困难。当我尝试提取标签时卡住了,我解释一下为什么需要提取认证标签。
Ruby中的加密代码如下:
plaintext = "Foo bar"
cipher = OpenSSL::Cipher.new('aes-256-gcm')
cipher.encrypt
cipher.iv = iv # 字符串,长度为12
cipher.key = key # 字符串,长度为32
cipher.auth_data = # 字符串,长度为12
cipherText = cipher.update(JSON.generate({value: plaintext})) + cipher.final
authTag = cipher.auth_tag
hexString = (iv + cipherText + authTag).unpack('H*').first
我尝试将初始向量、密文和认证标签连接在一起,这样在解密之前我就可以提取它们,特别是认证标签,因为我需要在调用Ruby的Cipher#final之前设置它。
关于认证标签的说明:
在调用Cipher#decrypt、Cipher#key=和Cipher#iv=之后,但在调用Cipher#final之前,必须设置标签。在执行所有解密操作后,标签会在调用Cipher#final时自动进行验证。
下面是Go中的加密函数:
ciphertext := aesgcm.Seal(nil, []byte(iv), []byte(plaintext), []byte(authData))
src := iv + string(ciphertext) // + 在这里尝试添加认证标签
fmt.Printf(hex.EncodeToString([]byte(src)))
我该如何提取认证标签并将其与iv和密文连接起来,以便我可以使用Ruby中的解密函数进行解密?
raw_data = [hexString].pack('H*')
cipher_text = raw_data.slice(12, raw_data.length - 28)
auth_tag = raw_data.slice(raw_data.length - 16, 16)
cipher = OpenSSL::Cipher.new('aes-256-gcm').decrypt
cipher.iv = iv # 字符串,长度为12
cipher.key = key # 字符串,长度为32
cipher.auth_data = # 字符串,长度为12
cipher.auth_tag = auth_tag
JSON.parse(cipher.update(cipher_text) + cipher.final)
我希望能够在Go中进行加密,并尝试在Ruby中进行解密。
英文:
I have encryption and decryption in Ruby and try to rewrite with Go. I try step by step, so start with encryption in ruby and try to decryption in go, it's works. But when I try to write encryption in Go and decrypt in ruby. I'm stuck when try to extract the tag, I explain the reason why I need extract the auth tag
Encryption In ruby
plaintext = "Foo bar"
cipher = OpenSSL::Cipher.new('aes-256-gcm')
cipher.encrypt
cipher.iv = iv # string 12 len
cipher.key = key # string 32 len
cipher.auth_data = # string 12 len
cipherText = cipher.update(JSON.generate({value: plaintext})) + cipher.final
authTag = cipher.auth_tag
hexString = (iv + cipherText + authTag).unpack('H*').first
I try to concatenate an initial vector, a ciphertext and the authentication tag, so before decrypt I can extract them, especially the authentication tag, because I need set it before calling Cipher#final in Ruby
> The tag must be set after calling Cipher#decrypt, Cipher#key= and
> Cipher#iv=, but before calling Cipher#final. After all decryption is
> performed, the tag is verified automatically in the call to
> Cipher#final
Here is function encryption in golang
ciphertext := aesgcm.Seal(nil, []byte(iv), []byte(plaintext), []byte(authData))
src := iv + string(ciphertext) // + try to add authentication tag here
fmt.Printf(hex.EncodeToString([]byte(src)))
How can I extract the authentication tag and concatenate it with iv and ciphertext, so I can decrypt with decryption function in ruby
raw_data = [hexString].pack('H*')
cipher_text = raw_data.slice(12, raw_data.length - 28)
auth_tag = raw_data.slice(raw_data.length - 16, 16)
cipher = OpenSSL::Cipher.new('aes-256-gcm').decrypt
cipher.iv = iv # string 12 len
cipher.key = key # string 32 len
cipher.auth_data = # string 12 len
cipher.auth_tag = auth_tag
JSON.parse(cipher.update(cipher_text) + cipher.final)
I want to be able doing encryption in Go, and try to decryption in Ruby.
答案1
得分: 4
你希望你的加密流程如下所示:
func encrypt(in []byte, key []byte) (out []byte, err error) {
c, err := aes.NewCipher(key)
if err != nil {
return
}
gcm, err := cipher.NewGCM(c)
if err != nil {
return
}
nonce := make([]byte, gcm.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
return
}
out = gcm.Seal(nonce, nonce, in, nil) // 将nonce包含在out的前导中
return
}
根据aes.NewCipher文档,你的输入key
应该是16、24或32字节长。
上述函数生成的加密后的out
字节会包含nonce
前缀(长度为16、24或32字节),因此在解密阶段可以轻松提取,如下所示:
// 这里的`in`是密文
nonce, ciphertext := in[:ns], in[ns:]
其中,ns
的计算方式如下:
c, err := aes.NewCipher(key)
if err != nil {
return
}
gcm, err := cipher.NewGCM(c)
if err != nil {
return
}
ns := gcm.NonceSize()
if len(in) < ns {
err = fmt.Errorf("missing nonce - input shorter than %d bytes", ns)
return
}
编辑:
如果你在go
端使用默认的密码设置进行加密(参见上文):
gcm, err := cipher.NewGCM(c)
根据源代码,标签的字节大小将为16
。
注意:如果使用cipher.NewGCMWithTagSize,则标签大小显然会有所不同(基本上在12
到16
字节之间)。
因此,假设标签大小为16
,根据这个信息,并且知道完整的有效负载排列方式为:
IV/nonce + raw_ciphertext + auth_tag
在Ruby
端进行解密时,auth_tag
是有效负载的最后16个字节;而raw_ciphertext
是从IV/nonce
之后的所有字节,直到auth_tag
开始的位置。
英文:
You want your encryption flow to be something like this:
func encrypt(in []byte, key []byte) (out []byte, err error) {
c, err := aes.NewCipher(key)
if err != nil {
return
}
gcm, err := cipher.NewGCM(c)
if err != nil {
return
}
nonce := make([]byte, gcm.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
return
}
out = gcm.Seal(nonce, nonce, in, nil) // include the nonce in the preable of 'out'
return
}
Your input key
should be of 16, 24 or 32 bytes in length as per aes.NewCipher docs.
The encrypted out
bytes from the above function will include the nonce
prefix (16, 24 or 32 bytes in length) - so it can be easily extracted during the decryption stage like so:
// `in` here is ciphertext
nonce, ciphertext := in[:ns], in[ns:]
where ns
is computed like so:
c, err := aes.NewCipher(key)
if err != nil {
return
}
gcm, err := cipher.NewGCM(c)
if err != nil {
return
}
ns := gcm.NonceSize()
if len(in) < ns {
err = fmt.Errorf("missing nonce - input shorter than %d bytes", ns)
return
}
EDIT:
If you are encrypting on the go
side with defaults cipher settings (see above):
gcm, err := cipher.NewGCM(c)
from the source the tag byte-size will be 16
.
Note: if cipher.NewGCMWithTagSize is used - then the size will obviously be different (basically anywhere between 12
to 16
bytes)
So lets assume the tag size is 16
, armed with this knowledge, and knowing the full payload arrangement is:
IV/nonce + raw_ciphertext + auth_tag
the auth_tag
on the Ruby
side for decryption, is the final 16 bytes of the payload; and the raw_ciphertext is all bytes after the IV/nonce
up until where the auth_tag
begins.
答案2
得分: 3
aesgcm.Seal
函数会自动在密文的末尾添加GCM标签。你可以在源代码中看到这一点:
var tag [gcmTagSize]byte
g.auth(tag[:], out[:len(plaintext)], data, &tagMask)
copy(out[len(plaintext):], tag[:]) // <---------------- 这里
所以,你已经完成了,不需要其他操作。gcm.Seal
函数已经返回了在密文末尾添加了认证标签的密文。
同样,对于gcm.Open
函数,你也不需要提取认证标签,它会自动处理,参考链接:
tag := ciphertext[len(ciphertext)-g.tagSize:] // <---------------- 这里
ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
因此,在解密过程中,你只需要提取IV(nonce),然后将剩余部分作为密文传入即可。
英文:
aesgcm.Seal
automatically appends the GCM tag at the end of the ciphertext. You can see it in the source:
var tag [gcmTagSize]byte
g.auth(tag[:], out[:len(plaintext)], data, &tagMask)
copy(out[len(plaintext):], tag[:]) // <---------------- here
So you're done, you don't need anything else. gcm.Seal
already returns the ciphertext with the auth tag appended at the end.
Similarly you don't need to extract the auth tag for gcm.Open
, it does it automatically, too:
tag := ciphertext[len(ciphertext)-g.tagSize:] // <---------------- here
ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
So all you have to do during decryption is to extract the IV (nonce) and pass the rest in as ciphertext.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论