简体   繁体   English

用python编写AES-CTR解密例程

[英]Writing AES-CTR decryption routine in python

I have the following code 我有以下代码

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
}

Where byteKey = []byte("4e8f1670f502a3d40717709e5f80d67c") (Not sure if that's right syntax, but that's the key in hex.) 其中byteKey = []byte("4e8f1670f502a3d40717709e5f80d67c") (不确定语法是否正确,但这就是十六进制的关键。)

I have been tasked with writing the decryption routine in any language and this is what I have so far: 我的任务是用任何一种语言编写解密例程,这是我到目前为止的工作:

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))

I'm doing something wrong I just don't know what. 我做错了什么,我只是不知道。 Can an expert please help? 请专家帮忙吗? Thanks in advance. 提前致谢。

Hint: think about how counter mode works. 提示:考虑一下计数器模式是如何工作的。 What is the initial counter value in your code and what are the subsequent values? 您的代码中的初始计数器值是多少,后续值是什么? What should they be? 他们应该是什么?


 counter=lambda: nonce 

This is a constant function that always returns the same value, which is 0 in your program. 这是一个常数函数,始终返回相同的值,该值在程序中为0。 But that's not what you need to pass to counter : you need to pass a function which returns the current counter value each time it is called. 但这不是您需要传递给counter :您需要传递一个函数,该函数每次调用时都会返回当前计数器值 For example, if the initial counter value is 0, then this function must return 0 the first time it's called, 1 the second time, 2 the third time, etc. More precisely, it must return '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00' , then '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01' , etc. 例如,如果初始计数器值为0,则此函数在第一次调用时必须返回0,在第二次调用时返回1,在第二次调用时返回2, '\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00' 。更准确地说,它必须返回'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00' ,然后是'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01'

The Python interface is badly designed here. Python界面在这里设计不好。 It's overly flexible, but this flexibility is never useful in practice and makes it hard to use the API correctly. 它过于灵活,但是这种灵活性在实践中从没有用过,因此很难正确使用API​​。 Furthermore the documentation is not clear at all: 此外, 文档根本不清楚:

counter (callable) - (Only MODE_CTR ). counter (可调用)-(仅MODE_CTR )。 A stateful function that returns the next counter block, which is a byte string of block_size bytes. 返回下一个计数器块的有状态函数,该计数器块是block_size个字节的字节串。 For better performance, use Crypto.Util.Counter . 为了获得更好的性能,请使用Crypto.Util.Counter

In fact you pretty much need to use Crypto.Util.Counter , not just for “performance”, but just to make the calculation correct. 实际上,您几乎需要使用Crypto.Util.Counter ,不仅是为了“性能”,还只是为了使计算正确。 Don't feel bad: you aren't the first to trip over this. 别难过:您不是第一个尝试此操作的人。

Confronted with an API that you can't figure out, you might turn to Stack Overflow next… and this very question has been answered, at PyCrypto problem using AES+CTR , but beware that for 7 years this question did not have a correct answer, despite having one that's upvoted and accepted. 面对您无法弄清的API,接下来您可能会转向Stack Overflow…,这个问题已经在使用AES + CTR的PyCrypto问题中得到了解答,但是请注意,这个问题7年以来没有一个正确的答案。 ,尽管有人推荐并接受了。 My answer shows how to use MODE_CTR and counter . 我的答案显示了如何使用MODE_CTRcounter

A second problem may be the initial counter value. 第二个问题可能是初始计数器值。 There are two main strategies for choosing an initial counter value for CTR mode: 选择CTR模式的初始计数器值有两种主要策略:

  • For a single-use key, start at 0, and don't transmit the ICV with the message since it's a well-known constant. 对于一次性密钥,请从0开始,并且不要随消息一起发送ICV,因为它是众所周知的常数。
  • For a multiple-use key, generate a random value each time, and send the ICV at the beginning of the ciphertext. 对于多次使用的密钥,每次生成一个随机值,然后在密文的开头发送ICV。

I'm not familiar with the API in the encryption code you posted. 您发布的加密代码中的API我不熟悉。 But since it returns ciphertext that's the same length as the plaintext, it probably uses a constant ICV (which is fine for a single-use key, but catastrophic if the key is reused), most likely 0. Still, check the documentation of that API. 但是,由于它返回的密文长度与明文长度相同,因此它可能使用恒定的ICV(对于一次性密钥来说是好的,但如果密钥被重用则会带来灾难性的后果),很可能为0。仍然,请查阅该文档API。

(If you need further coding help, ask on Stack Overflow rather than Cryptography , because coding questions are off-topic on Cryptography.SE. And be sure to post complete code to reproduce the problem , including inputs and outputs.) (如果您需要进一步的编码帮助,请在Stack Overflow而不是Cryptography上询问,因为编码问题在Cryptography.SE上是不重要的。请确保发布完整的代码以重现该问题 ,包括输入和输出。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM