0

I'm trying to use AES-CTR-128 in my code. I use Python 2.7 and utilize the cryptography module to do the encryption.

I need to set specific Counter value, for example counter_iv = 112. When I tried

import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
backend = default_backend()
key = os.urandom(32)
counter_iv = 112
cipher = Cipher(algorithms.AES(key), modes.CTR(counter_iv), backend=backend)
encryptor = cipher.encryptor()
ciphertext = encryptor.update(b"a secret message") + encryptor.finalize()

This gave me an error message:

Traceback (most recent call last):
File "aestest.py", line 14, in <module>
  cipher = Cipher(algorithms.AES(key), modes.CTR(counter_iv), backend=backend)
File "/usr/local/lib/python2.7/dist-packages/cryptography/hazmat/primitives/ciphers/modes.py", line 139, in __init__
  raise TypeError("nonce must be bytes")
TypeError: nonce must be bytes

I think it tells me that counter_iv should be a 16-byte string.

My question is how to convert a integer, or maybe a long integer into a 16-byte string?

Moreover, is there any way to convert an integer to any length string? Thanks for your help.

3
  • What is encryptor? Commented May 19, 2016 at 21:22
  • @Padraic Cunningham Forgot to add it. Now it's there. Commented May 19, 2016 at 21:24
  • 1
    Warning: Your counter should not be static, certainly not for CTR mode. Please understand the differences between a nonce and the counter value, or your scheme may be very insecure. Commented May 21, 2016 at 1:01

2 Answers 2

5

First do you have a good reason to use the low level hazardous material instead of the higher level API? This level is intended to be used only through the high level API of for special purposes.

Next, you are misleading any further reader by writing modes.CTR(counter_iv), because the counter mode does not use an initialization vector but a nonce according to its documentation. And the error you get is normal, since the doc states the nonce shall be a byte string of same size of the cipher block so for AES it must be 128 bits or 16 bytes.

BTW the doc also states that a nonce should never be reused

... It is critical to never reuse a nonce with a given key. Any reuse of a nonce with the same key compromises the security of every message encrypted with that key.

Nayuki's answer explain how to build a 16 bytes string from your int, but be sure to correctly use cryptography if you use the low level hazardous material

Sign up to request clarification or add additional context in comments.

1 Comment

Your answer gives a lot of insight into how the library should be used correctly. Thank you :)
3

In Python 2, you can convert an integer to a byte string in little endian like this:

counter_iv = 112  # This can be a pretty big number
iv_bytes = "".join(chr((counter_iv >> (i * 8)) & 0xFF) for i in range(16))

Expanding the code to explain:

counter_iv = 112  # Can be from 0 to 3.40e38
temp = []  # Will be an array of bytes
for i in range(16):
    # Get the i'th byte counting from the least significant end
    b = (counter_iv >> (i * 8)) & 0xFF
    temp.append(b)
# For example, temp == [0x70, 0x00, ... 0x00]

# Will be an array of 1-character strings
temp2 = [chr(b) for b in temp]
# For example, temp2 == ['\x70', '\x00', ..., '\x00']

# Concatenate all the above together
iv_bytes = "".join(temp2)
# For example, iv_bytes == '\0x70\0x00...\0x00'

3 Comments

Great it works. Could you give me a brief explain of this? Thanks.
In python3, you can simply counter_iv.to_bytes(16,"little")
@PadraicCunningham That is awesome! Learned something new today

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.