AES256-GCM兼容性:在Go中加密,在Python中解密
在连接MinIO admin API时,我一直在解密服务器生成的AES256-GCM有效负载。MinIO服务器是用Go编写的,我的客户端应用程序是用Python编写的。在深入研究和测试时,我发现我无法创建相同的密文,尽管我传递的是非常相同的密钥和nonce(IV) 这是in中的MinIO代码,使用一些AES256-GCM兼容性:在Go中加密,在Python中解密,python,go,encryption,aes-gcm,Python,Go,Encryption,Aes Gcm,在连接MinIO admin API时,我一直在解密服务器生成的AES256-GCM有效负载。MinIO服务器是用Go编写的,我的客户端应用程序是用Python编写的。在深入研究和测试时,我发现我无法创建相同的密文,尽管我传递的是非常相同的密钥和nonce(IV) 这是in中的MinIO代码,使用一些Fprintf来提取机密: func EncryptData(密码字符串,数据[]字节)([]字节,错误){ 盐:=sioutil.MustRandom(32) 变量( id字节 错误 溪流*sio
Fprintf
来提取机密:
func EncryptData(密码字符串,数据[]字节)([]字节,错误){
盐:=sioutil.MustRandom(32)
变量(
id字节
错误
溪流*sio.stream
)
如果FIPSEnabled(){
key:=pbkdf2.key([]字节(密码),salt,pbkdf2Cost,32,sha256.New)
流,err=sio.AES_256_GCM.stream(键)
如果错误!=零{
返回零,错误
}
id=pbkdf2AESGCM
}否则{
key:=argon2.IDKey([]字节(密码),salt,argon2idTime,argon2idMemory,argon2idThreads,32)
如果sioutil.NativeAES(){
流,err=sio.AES_256_GCM.stream(键)
如果错误!=零{
返回零,错误
}
id=argon2idAESGCM
fmt.Fprintf(os.Stdout,“键:\n%s\n”,十六进制转储([]字节(键)))
}否则{
流,err=sio.ChaCha20Poly1305.流(键)
如果错误!=零{
返回零,错误
}
id=argon2idChaCHa20Poly1305
}
}
nonce:=sioutil.MustRandom(stream.NonceSize())
fmt.Fprintf(os.Stdout,“Id:\n%d\n”,Id)
fmt.Fprintf(os.Stdout,“密码:\n%s\n”,十六进制转储([]字节(密码)))
fmt.Fprintf(os.Stdout,“Salt:\n%s\n”,十六进制转储([]字节(Salt)))
fmt.Fprintf(os.Stdout,“Nonce:\n%s\n”,十六进制转储([]字节(Nonce)))
//密文=salt | | AEAD ID | nonce |加密数据
cLen:=int64(len(salt)+1+len(nonce)+len(data))+流开销(int64(len(data)))
密文:=bytes.NewBuffer(make([]字节,0,cLen))//预分配正确的长度
//在密文前面加上salt、AEAD ID和nonce
密文写入(salt)
密文写入字节(id)
密文写入(nonce)
w:=stream.EncryptWriter(密文,nonce,nil)
如果3;,err=w.Write(数据);err!=nil{
返回零,错误
}
如果err=w.Close();err!=nil{
返回零,错误
}
fmt.Fprintf(os.Stdout,“纯文本数据:\n%s\n”,十六进制转储(数据))
fmt.Fprintf(os.Stdout,“密文:\n%s\n”,十六进制转储(Ciphertext.Bytes())
返回密文.Bytes(),无
}
0的id
表示argon2idAESGCM
这是示例请求的结果:
Key:
00000000 b9 6b 3a 5a 77 37 94 67 ae b8 9a 06 63 78 cb 87 |.k:Zw7.g....cx..|
00000010 11 4d 54 cd e5 2b 2f 40 f1 af 30 29 fa ad 78 6d |.MT..+/@..0)..xm|
Id:
0
Password:
00000000 6d 69 6e 69 6f 73 74 6f 72 61 67 65 |miniostorage|
Salt:
00000000 d0 82 60 d8 2d d4 d0 c0 24 45 c6 09 0e 19 38 54 |..`.-...$E....8T|
00000010 88 a1 1b 8d aa 9c 43 3c 81 e9 91 04 12 d3 41 a4 |......C<......A.|
Nonce:
00000000 10 9e 23 ff bb 12 97 0a |..#.....|
Plain text data:
00000000 7b 22 66 6f 6f 75 73 65 72 22 3a 7b 22 73 74 61 |{"foouser":{"sta|
00000010 74 75 73 22 3a 22 65 6e 61 62 6c 65 64 22 7d 7d |tus":"enabled"}}|
Ciphertext:
00000000 d0 82 60 d8 2d d4 d0 c0 24 45 c6 09 0e 19 38 54 |..`.-...$E....8T|
00000010 88 a1 1b 8d aa 9c 43 3c 81 e9 91 04 12 d3 41 a4 |......C<......A.|
00000020 00 10 9e 23 ff bb 12 97 0a a0 6c ff 5c 9c ad 03 |...#......l.\...|
00000030 8a 2f 42 6b 06 cf 8c 28 b0 13 e7 2c df 5f 28 96 |./Bk...(...,._(.|
00000040 1c cb 1f 93 52 58 8b 97 14 8a 8b 44 72 f5 39 61 |....RX.....Dr.9a|
00000050 70 01 dd 12 bb 1c c6 ad 4f |p.......O|
Python计算的密文是
ciphertext:
00000000: CC 1C AC BE C2 FF 4A 33 00 23 55 0F 7A E8 88 51 ......J3.#U.z..Q
00000010: 95 93 7A BF 29 2A BE CC 4C 69 A3 78 D3 7D BC 97 ..z.)*..Li.x.}..
tag:
00000000: 41 8E C7 87 1E C0 CE 87 EE CC 7D 01 30 87 A6 C1 A.........}.0...
显然与a0 6c ff 5c…
不匹配
我错过了什么
(为了完整性:在Python中通过Argon2id导出密钥效果很好。真正产生不同结果的是AES操作。)您也必须深入研究这个流。这不是Go标准库的一部分。它不支持GCM模式下的流媒体,所以这是家酿的。64位nonce大小也不常见;96位是GCM的标准。仔细检查Python API以确保这不需要做特殊的事情。感谢您的提示。根据文档,当前长度对模式mode\u GCM
没有限制。