在Golang中解密Python AES CFB加密的内容

7
基于Golang CFB解密文档,我编写了一个简单的工作示例来解密使用AES CFB加密并在python3中进行base64编码的字符串。
当消息是在Golang中加密(使用Golang文档示例中的加密函数)时,Golang解密可以正常工作。然而,当我在Python脚本中使用Python加密包对消息进行加密时,我无法成功地在Golang脚本中解密它。我没有得到正确的字节返回。
$ python3 stack.py 
Going to encrypt and base64 "This is not encrypted" result:
b'jf9A5LCxKWPuNb1XiH+G3APAgR//'

Now going to call the Golang script:
b'Hello from Golang, going to decrypt: jf9A5LCxKWPuNb1XiH+G3APAgR//
Result:  Tl!\xca/\xf1\xc0\xb2\xd01Y\x02V\xec\xdf\xecy\xd38&\xd9\n'

默认情况下,AES实现的块大小为16。

所以问题是:出了什么问题?

Golang脚本:

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "fmt"
    "os"

)

func main() {
    key := []byte("TfvY7I358yospfWKcoviZizOShpm5hyH")
    iv := []byte("mb13KcoviZizvYhp")
    payload_python := os.Args[1]

    fmt.Println("Hello from Golang, going to decrypt: "+payload_python+" Result: "+string(decrypt(key, payload_python, iv)))
}


func decrypt(key []byte, cryptoText string, iv []byte) []byte {
    ciphertext, _ := base64.StdEncoding.DecodeString(cryptoText)    //decode base64 coding

    //prepare decryption based on key and iv
    block, _ := aes.NewCipher(key)
    stream := cipher.NewCFBDecrypter(block, iv)

    //decrypt
    stream.XORKeyStream(ciphertext, ciphertext)

    return ciphertext
}

Python脚本:

 #!/usr/bin/env python3
import base64
from Crypto.Cipher import AES
from subprocess import check_output


original_message = 'This is not encrypted'

key = 'TfvY7I358yospfWKcoviZizOShpm5hyH'
iv = 'mb13KcoviZizvYhp'

#prepare encryption
cfb_cipher_encrypt = AES.new(key, AES.MODE_CFB, iv)
#encrypt and base64 encode
encryptedpayload = base64.b64encode(cfb_cipher_encrypt.encrypt(original_message))

print('Going to encrypt and base64 "{}" result:\n{}\n'.format(original_message,encryptedpayload))

print('Now going to call the Golang script:')
print(check_output('go run stack.go {}'.format(encryptedpayload.decode()),shell=True))

1
首先,你在 Go 中使用了 base64 URL 编码解码有效载荷,但是你从 Python 输出的明显是标准的 base64 编码(它包含斜杠)。 - Adrian
2
你还忽略了Go代码中的所有错误,如果遇到无法轻松解决的问题,这是需要首先修复的。 - Adrian
1
@Adrian 的关于 base64 标准编码的观点很好! 我已经更改了它,但不幸的是没有效果。 当我在错误不为 nil 时添加代码到 panic() 中,仍然得到相同的输出。 - Sebastian
此外,Python2 可能使用 ASCII,但 Python3 默认为 UTF-8,因此我同意,那似乎不是问题所在。 刚才我发现了这篇 SO 帖子:https://dev59.com/r4Lba4cB1Zd3GeqPisDT 看起来有些相同的问题,但我不知道如何检查块大小?块大小对于两者都是16。 - Sebastian
似乎与填充和段大小有关,请参见我下面的答案。 - eugenioy
显示剩余2条评论
1个回答

5

尝试使用Python进行加密,像这样。

然后可以成功地从Go解密结果。

 #!/usr/bin/env python3
import base64
from Crypto.Cipher import AES

MODE = AES.MODE_CFB
BLOCK_SIZE = 16
SEGMENT_SIZE = 128

def _pad_string(value):
    length = len(value)
    pad_size = BLOCK_SIZE - (length % BLOCK_SIZE)
    return value.ljust(length + pad_size, '\x00')

def encrypt(key, iv, plaintext):
    aes = AES.new(key, MODE, iv, segment_size=SEGMENT_SIZE)
    plaintext = _pad_string(plaintext)
    encrypted_text = aes.encrypt(plaintext)
    return encrypted_text

key = 'TfvY7I358yospfWKcoviZizOShpm5hyH'
iv = 'mb13KcoviZizvYhp'
original_message = 'This is not encrypted'

encryptedpayload = base64.b64encode(encrypt(key, iv, original_message))

print('Going to encrypt and base64 "{}" result:\n{}\n'.format(original_message,encryptedpayload))

来源:http://chase-seibert.github.io/blog/2016/01/29/cryptojs-pycrypto-ios-aes256.html

(以下为翻译内容)

是的,它有效!来自Golang的问候,将要解密:jfsIXb8pmvFQa5B1u/06QpzqlWItvB70V1204lf+5gw= 结果:这不是加密\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 因此,它们都有不同的默认实现,是否有一种更常见的实现?我能否调整Go参数以便成功解密默认的Python AES CFB加密?还是需要更改源代码? - Sebastian
从我在答案中包含的链接所说的内容来看,似乎Go更具互操作性,但不确定如何调整Go参数以适应另一个。 - eugenioy
注意填充代码。你的值可能会被额外填充16个字节,这可能不是正确的行为。在我看来,额外的“module”应该解决这个问题。 - Dáve
可以在eugenioy的答案中添加一些细节:段大小是不匹配的原因。当您将PyCrypto中的段大小增加到128(Go的默认值)时,您还需要将输入填充到块大小(16),原因超出了我的理解范围。如果您真的想这样做,您也可以编写Go代码将段大小更改为8(PyCrypto的默认值),请参见: https://dev59.com/TmAg5IYBdhLWcg3wLYaI#37234233 但是,似乎某些实现(如CryptoJS)不支持更改段大小。 - Sebastian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接