我有以下代码
func encrypt(key, data string) (string, error) {
byteKey := []byte(key)
plaintext := []byte(data)
block, err := aes.NewCipher(byteKey)
if err != nil {
return "", err
}
ciphertext := make([]byte, len(plaintext))
stream := cipher.NewCTR(block, byteKey[aes.BlockSize:])
stream.XORKeyStream(ciphertext, plaintext)
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
byteKey = []byte("4e8f1670f502a3d40717709e5f80d67c")
(不确定语法是否正确,但这是十六进制的关键。)
我的任务是用任何一种语言编写解密例程,这是我到目前为止所要做的:
import base64
from Crypto.Cipher import AES
def decrypt(ct):
key = '4e8f1670f502a3d40717709e5f80d67c'.decode('hex')
nonce = 0
ct1 = base64.b64decode(ct)
cipher = AES.new(key, mode=AES.MODE_CTR, counter=lambda: nonce)
print str(cipher.decrypt(ct1))
我做错了什么,我只是不知道是什么。请专家帮忙吗?预先感谢。
答案 0 :(得分:2)
提示:考虑计数器模式如何工作。您的代码中的初始计数器值是多少,后续值是什么?他们应该是什么?
counter=lambda: nonce
这是一个常数函数,始终返回相同的值,该值在程序中为0。但这不是您需要传递给counter
的东西:您需要传递一个函数,该函数每次调用时都会返回当前计数器值。例如,如果初始计数器值为0,则此函数必须在首次调用时返回0,在第二次调用时返回1,在第二次调用时返回2,以此类推。更准确地说,它必须返回'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
,然后返回{{ 1}}等。
此处的Python接口设计不良。它过于灵活,但是这种灵活性在实践中从没有用过,因此很难正确使用API。此外,documentation根本不清楚:
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
(可调用)-(仅MODE_CTR
)。返回下一个计数器块的有状态函数,该计数器块是counter
个字节的字节串。为了获得更好的性能,请使用Crypto.Util.Counter
。
实际上,您非常需要使用block_size
来使用Crypto.Util.Counter
,不仅仅是为了“性能”,而且只是为了使计算正确。别难过:您不是第一个尝试过这个的人。
面对一个您可能不知道的API,接下来您可能会转向Stack Overflow…,这个问题已经在PyCrypto problem using AES+CTR处得到了回答,但是请注意,这个问题已经有7年没有了。正确的答案,尽管有一个被认可和接受的答案。我的答案显示了如何使用MODE_CTR
和counter
。
第二个问题可能是初始计数器值。为点击率模式选择初始计数器值的主要策略有两种:
我对您发布的加密代码中的API不熟悉。但是,由于它返回的密文长度与明文长度相同,因此它可能使用恒定的ICV(对于一次性密钥来说是好的,但如果密钥被重用则会带来灾难性的后果),很可能为0。仍然,请查阅该文档API。
(如果您需要进一步的编码帮助,请在Stack Overflow而不是Cryptography上提问,因为编码问题不在Cryptography.SE上。并且请务必发布complete code to reproduce the problem,包括输入和输出。)