(using python 3 here, there are some nomenclature differences in 2)
Well first, you could just leave everything as bytes. This is perfectly valid:
reg_val_msb, reg_val_lsb = struct.pack('<H', 0xABCD)
bytes allows for "tuple unpacking" (not related to struct.unpack, tuple unpacking is used all over python). And bytes is an array of bytes, which can be accessed via index as you wanted.
b = struct.pack('<H',0xABCD)
b[0],b[1]
Out[52]: (205, 171)
If you truly wanted to get it into an array.array('B'), it's still rather easy:
ary = array('B',struct.pack('<H',0xABCD))
# ary = array('B', [205, 171])
print("0x%X" % ary[0])
# 0xCD
Answer from roippi on Stack Overflow(using python 3 here, there are some nomenclature differences in 2)
Well first, you could just leave everything as bytes. This is perfectly valid:
reg_val_msb, reg_val_lsb = struct.pack('<H', 0xABCD)
bytes allows for "tuple unpacking" (not related to struct.unpack, tuple unpacking is used all over python). And bytes is an array of bytes, which can be accessed via index as you wanted.
b = struct.pack('<H',0xABCD)
b[0],b[1]
Out[52]: (205, 171)
If you truly wanted to get it into an array.array('B'), it's still rather easy:
ary = array('B',struct.pack('<H',0xABCD))
# ary = array('B', [205, 171])
print("0x%X" % ary[0])
# 0xCD
For non-complex numbers you can use divmod(a, b), which returns a tuple of the quotient and remainder of arguments.
The following example uses map() for demonstration purposes. In both examples we're simply telling divmod to return a tuple (a/b, a%b), where a=0xABCD and b=256.
>>> map(hex, divmod(0xABCD, 1<<8)) # Add a list() call here if your working with python 3.x
['0xab', '0xcd']
# Or if the bit shift notation is distrubing:
>>> map(hex, divmod(0xABCD, 256))
Or you can just place them in the array:
>>> arr = array.array('B')
>>> arr.extend(divmod(0xABCD, 256))
>>> arr
array('B', [171, 205])
cryptography - Python convert integer to 16-byte bytes - Stack Overflow
python - Represent number as a bytes using 16-bit blocks - Stack Overflow
python - 16 bit Binary conversion - Stack Overflow
string - Convert 16 bytes of random data to integer in Python - Stack Overflow
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
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'
Use the .tobytes-method:
num = 683550
bytes = num.to_bytes((num.bit_length()+15)//16*2, "little")
Using python3:
def encode_to_my_hex_format(num, bytes_group_len=2, byteorder='little'):
"""
@param byteorder can take the values 'little' or 'big'
"""
bytes_needed = abs(-len(bin(num)[2: ]) // 8)
if bytes_needed % bytes_group_len:
bytes_needed += bytes_group_len - bytes_needed % bytes_group_len
num_in_bytes = num.to_bytes(bytes_needed, byteorder)
encoded_num_in_bytes = b''
for index in range(0, len(num_in_bytes), bytes_group_len):
bytes_group = num_in_bytes[index: index + bytes_group_len]
if byteorder == 'little':
bytes_group = bytes_group[-1: -len(bytes_group) -1 : -1]
encoded_num_in_bytes += bytes_group
encoded_num = ''
for byte in encoded_num_in_bytes:
encoded_num += r'\x' + hex(byte)[2: ].zfill(2)
return encoded_num
print(encode_to_my_hex_format(683550))
I had the same problem and I found a simpler and shorter solution.
Here's an example:
Encode:
In [1]: val = 15
In [2]: bin_ = '{0:016b}'.format(val)
In [3]: bin_
Out[3]: '0000000000001111'
Or:
In [4]: bin_ = bin(val)[2:].zfill(16)
In [5]: bin_
Out[5]: '0000000000001111'
Decode:
In [6]: int(bin_, 2)
Out[6]: 15
This isn't a very popular question to answer, I can see, so I'll put this up in the meantime:
def convert_to_binary(value):
'''
Converts a float to a 16-bit binary string.
'''
n = ['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0']
value = int(value)
if value > 2**15:
if value > 2**16:
print "Value too large"
else:
n[0] = '1'
value = value - (2**15)
if value > 2**14:
n[1] = '1'
value = value - (2**14)
if value > 2**13:
n[2] = '1'
value = value - (2**13)
if value > 2**12:
n[3] = '1'
value = value - (2**12)
if value > 2**11:
n[4] = '1'
value = value - (2**11)
if value > 2**10:
n[5] = '1'
value = value - (2**10)
if value > 2**9:
n[6] = '1'
value = value - (2**9)
if value > 2**8:
n[7] = '1'
value = value - (2**8)
if value > 2**7:
n[8] = '1'
value = value - (2**7)
if value > 2**6:
n[9] = '1'
value = value - (2**6)
if value > 2**5:
n[10] = '1'
value = value - (2**5)
if value > 2**4:
n[11] = '1'
value = value - (2**4)
if value > 2**3:
n[12] = '1'
value = value - (2**3)
if value > 2**2:
n[13] = '1'
value = value - (2**2)
if value > 2**1:
n[14] = '1'
value = value - (2**1)
if value >= 2**0:
n[15] = '1'
value = value - (2**0)
n = ''.join(n)
n = str(n)
print str(n)
return str(n)
def convert_back(bin_num):
"""
Converts binary string to a float.
"""
value = 0
print type(bin_num)
n = list(bin_num)
if n[0] == '1':
value = value + (2 ** 15)
if n[1] == '1':
value = value + (2 ** 14)
if n[2] == '1':
value = value + (2 ** 13)
if n[3] == '1':
value = value + (2 ** 12)
if n[4] == '1':
value = value + (2 ** 11)
if n[5] == '1':
value = value + (2 ** 10)
if n[6] == '1':
value = value + (2 ** 9)
if n[7] == '1':
value = value + (2 ** 8)
if n[8] == '1':
value = value + (2 ** 7)
if n[9] == '1':
value = value + (2 ** 6)
if n[10] == '1':
value = value + (2 ** 5)
if n[11] == '1':
value = value + (2 ** 4)
if n[12] == '1':
value = value + (2 ** 3)
if n[13] == '1':
value = value + (2 ** 2)
if n[14] == '1':
value = value + (2 ** 1)
if n[15] == '1':
value = value + (2 ** 0)
print value
return value
In Python 3.2+, you can use int.from_bytes():
>>> int.from_bytes(b'\xb68 \xe9L\xbd\x97\xe0\xd6Q\x91c\t\xc3z\\', byteorder='little')
122926391642694380673571917327050487990
You can also use 'big' byteorder:
>>> int.from_bytes(b'\xb68 \xe9L\xbd\x97\xe0\xd6Q\x91c\t\xc3z\\', byteorder='big')
242210931377951886843917078789492013660
You can also specify if you want to use two's complement representation. For more info: https://docs.python.org/3/library/stdtypes.html
A solution compatible both with Python 2 and Python 3 is to use struct.unpack:
import struct
n = b'\xb68 \xe9L\xbd\x97\xe0\xd6Q\x91c\t\xc3z\\'
m = struct.unpack("<QQ", n)
res = (m[0] << 64) | m[1]
print(res)
Result: 298534947350364316483256053893818307030L
I'm trying to take a number (such as -200) and send it to a robot. The number must be converted to big-endian and sent in two bytes. WolframAlpha does this (the result I need to send is 38ff) but I haven't found a way to do this in python.
Check out hex() and, more importantly struct:
http://docs.python.org/2/library/struct.html
This lets you convert a decimal into binary data. I've used it to read binary files, so it might be what you are looking for. I'm weak on theory so I tend to just bang on stuff until I get it right, but I would start with:
>>> import struct
>>> struct.pack('>h', -200)
b'\xff8'
And see what the machine makes of it, and adjust accordingly.
u/1328 was close with struct, the code you are looking for is:
import struct
print struct.pack('>i', your_int)
>I is the indicator for Big Endian as according to struct.
Python Struct Documentation
EDIT: I just tested this code, and got the same result as u/1328. I'm looking into this more.
EDIT 2: OK. Wolfram's representation of the number -200 in hexadecimal is as an unsigned 16 bit integer. THey make a note that this number overflowed, and the reason is that -200 is, inherently, a signed number.
Are you sure you need to send the number is ff38, and not xff8?
If so, then you need to do some hackery to get this working. Something like:
import struct
def toBigEndian(number):
if number < 0:
number = 65536 + number
return struct.pack('>i',number)
You can use int.from_bytes and a little list comprehension. Please note that byte_order needs to be specified, so you might have to change that depending on your application.
ba = bytearray([0x01, 0x02, 0x01, 0x03, 0xff, 0xff])
ia = [int.from_bytes(ba[i:i+2], "big") for i in range(0, len(ba), 2)]
That looks like a big endian encoding (the first byte is the high bits). You can use the struct package. It uses a format string to describe the bytes coming from some iterable.
import struct
unpacker = struct.Struct(">H")
ba = bytearray([0x01, 0x02, 0x01, 0x03, 0xff, 0xff])
result = [unpacked[0] for unpacked in unpacker.iter_unpack(ba)]
print([hex(r) for r in result])
The full set of endian specifiers is in the docs Byte order, size and alignment.