AES256-GCM兼容性:在Go中加密,在Python中解密

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

在连接MinIO admin API时,我一直在解密服务器生成的AES256-GCM有效负载。MinIO服务器是用Go编写的,我的客户端应用程序是用Python编写的。在深入研究和测试时,我发现我无法创建相同的密文,尽管我传递的是非常相同的密钥和nonce(IV)

这是in中的MinIO代码,使用一些
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
没有限制。