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. 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. 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.
The Python interface is badly designed here. It's overly flexible, but this flexibility is never useful in practice and makes it hard to use the API correctly. Furthermore the documentation is not clear at all:
counter
(callable) - (Only MODE_CTR
). A stateful function that returns the next counter block, which is a byte string of block_size
bytes. For better performance, use 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. 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. My answer shows how to use MODE_CTR
and counter
.
A second problem may be the initial counter value. There are two main strategies for choosing an initial counter value for CTR mode:
- For a single-use key, start at 0, and don't transmit the ICV with the message since it's a well-known constant.
- For a multiple-use key, generate a random value each time, and send the ICV at the beginning of the ciphertext.
I'm not familiar with the API in the encryption code you posted. 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.
(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.)