print library ejemplos array python bytearray long-integer diffie-hellman rc4-cipher

library - Convierte python long/int en una matriz de bytes de tamaño fijo



struct python library (10)

Estoy intentando implementar el intercambio de claves RC4 y DH en python. El problema es que no tengo idea de cómo convertir el python long / int del intercambio de claves a la matriz de bytes que necesito para la implementación de RC4. ¿Existe una manera simple de convertir una matriz de bytes de longitud larga a la requerida?

Actualización : se olvidó de mencionar que los números con los que estoy tratando son enteros sin signo de 768 bits.


Básicamente, lo que necesita hacer es convertir el int / long en su representación base 256, es decir, un número cuyos "dígitos" van desde 0 hasta 255. Aquí hay una forma bastante eficiente de hacer algo como eso:

def base256_encode(n, minwidth=0): # int/long to byte array if n > 0: arr = [] while n: n, rem = divmod(n, 256) arr.append(rem) b = bytearray(reversed(arr)) elif n == 0: b = bytearray(b''/x00'') else: raise ValueError if minwidth > 0 and len(b) < minwidth: # zero padding needed? b = (minwidth-len(b)) * ''/x00'' + b return b

Muchos no necesitan la llamada reversed() dependiendo de la endianancia deseada (si lo hace, también requerirá que el relleno se haga de forma diferente). También tenga en cuenta que, tal como está escrito, no maneja números negativos.

También es posible que desee echar un vistazo a la función long_to_bytes() similar pero altamente optimizada en el módulo number.py que forma parte del kit de herramientas de criptografía Python de código abierto. En realidad, convierte el número en una cadena, no en una matriz de bytes, pero eso es un problema menor.



Little-endian, invierte el resultado o el rango si quieres Big-endian.

def int_to_bytes(val, num_bytes): return [(val & (0xff << pos*8)) >> pos*8 for pos in range(num_bytes)]


No he hecho ningún punto de referencia, pero esta receta "funciona para mí".

La versión corta: use ''%x'' % val , luego unhexlify el resultado. El demonio está en los detalles, sin embargo, como unhexlify requiere un número par de dígitos hexadecimales, que %x no garantiza. Vea la docstring y los comentarios liberales en línea para más detalles.

from binascii import unhexlify def long_to_bytes (val, endianness=''big''): """ Use :ref:`string formatting` and :func:`~binascii.unhexlify` to convert ``val``, a :func:`long`, to a byte :func:`str`. :param long val: The value to pack :param str endianness: The endianness of the result. ``''big''`` for big-endian, ``''little''`` for little-endian. If you want byte- and word-ordering to differ, you''re on your own. Using :ref:`string formatting` lets us use Python''s C innards. """ # one (1) hex digit per four (4) bits width = val.bit_length() # unhexlify wants an even multiple of eight (8) bits, but we don''t # want more digits than we need (hence the ternary-ish ''or'') width += 8 - ((width % 8) or 8) # format width specifier: four (4) bits per hex digit fmt = ''%%0%dx'' % (width // 4) # prepend zero (0) to the width, to zero-pad the output s = unhexlify(fmt % val) if endianness == ''little'': # see http://.com/a/931095/309233 s = s[::-1] return s

... y mis pruebas de unidad nosetest ;-)

class TestHelpers (object): def test_long_to_bytes_big_endian_small_even (self): s = long_to_bytes(0x42) assert s == ''/x42'' s = long_to_bytes(0xFF) assert s == ''/xff'' def test_long_to_bytes_big_endian_small_odd (self): s = long_to_bytes(0x1FF) assert s == ''/x01/xff'' s = long_to_bytes(0x201FF) assert s == ''/x02/x01/xff'' def test_long_to_bytes_big_endian_large_even (self): s = long_to_bytes(0xab23456c8901234567) assert s == ''/xab/x23/x45/x6c/x89/x01/x23/x45/x67'' def test_long_to_bytes_big_endian_large_odd (self): s = long_to_bytes(0x12345678901234567) assert s == ''/x01/x23/x45/x67/x89/x01/x23/x45/x67'' def test_long_to_bytes_little_endian_small_even (self): s = long_to_bytes(0x42, ''little'') assert s == ''/x42'' s = long_to_bytes(0xFF, ''little'') assert s == ''/xff'' def test_long_to_bytes_little_endian_small_odd (self): s = long_to_bytes(0x1FF, ''little'') assert s == ''/xff/x01'' s = long_to_bytes(0x201FF, ''little'') assert s == ''/xff/x01/x02'' def test_long_to_bytes_little_endian_large_even (self): s = long_to_bytes(0xab23456c8901234567, ''little'') assert s == ''/x67/x45/x23/x01/x89/x6c/x45/x23/xab'' def test_long_to_bytes_little_endian_large_odd (self): s = long_to_bytes(0x12345678901234567, ''little'') assert s == ''/x67/x45/x23/x01/x89/x67/x45/x23/x01''


Puedes intentar usar struct :

import struct struct.pack(''L'',longvalue)


Python 2.7 no implementa el método int.to-very slow_bytes ().

Intenté 3 métodos:

  1. desempaquetar / paquete hexagonal: muy lento
  2. byte cambiando 8 bits a la vez: significativamente más rápido.
  3. usando un módulo "C" y empacando en los bytes inferiores (7 ia64 o 3 i32). Esto fue aproximadamente el doble de rápido que 2 /. Es la opción más rápida, pero aún demasiado lenta.

Todos estos métodos son muy ineficientes por dos razones:

  • Python 2.7 no es compatible con esta operación útil.
  • c no es compatible con la aritmética de precisión extendida utilizando los indicadores carry / borrow / overflow disponibles en la mayoría de las plataformas.

Todos han complicado demasiado esta respuesta:

some_int = <256 bit integer> some_bytes = some_int.to_bytes(32, sys.byteorder) my_bytearray = bytearray(some_bytes)

Solo necesita saber la cantidad de bytes que intenta convertir. En mis casos de uso, normalmente solo utilizo esta gran cantidad de números para cifrado, y en ese momento tengo que preocuparme por el módulo y lo que no, así que no creo que este sea un gran problema para conocer el número máximo. de bytes a devolver.

Como lo está haciendo como matemática de 768 bits, entonces en lugar de 32 como argumento, sería 96.


Un trazador de líneas:

bytearray.fromhex(''{:0192x}''.format(big_int))

El 192 es 768/4, porque OP quería números de 768 bits y hay 4 bits en un dígito hexadecimal. Si necesita un bytearray más grande, use una cadena de formato con un número más alto. Ejemplo:

>>> big_int = 911085911092802609795174074963333909087482261102921406113936886764014693975052768158290106460018649707059449553895568111944093294751504971131180816868149233377773327312327573120920667381269572962606994373889233844814776702037586419 >>> bytearray.fromhex(''{:0192x}''.format(big_int)) bytearray(b''/x96;h^/xdbJ/x8f3obL/x9c/xc2/xb0-/x9e/xa4Sj-/xf6i/xc1/x9e/x97/x94/x85M/x1d/x93/x10///x81/xc2/x89/xcd/xe0a/xc0D/x81v/xdf/xed/xa9/xc1/x83p/xdbU/xf1/xd0/xfeR)/xce/x07/xdepM/x88/xcc/x7fv///x1c/x8di/x87N/x00/x8d/xa8/xbd[</xdf/xaf/x13z:H/xed/xc2)/xa4/x1e/x0f/xa7/x92/xa7/xc6/x16/x86/xf1/xf3'') >>> lepi_int = 0x963b685edb4a8f336f624c9cc2b02d9ea4536a2df669c19e9794854d1d93105c81c289cde061c0448176dfeda9c18370db55f1d0fe5229ce07de704d88cc7f765c1c8d69874e008da8bd5b3cdfaf137a3a48edc229a41e0fa792a7c61686f1f >>> bytearray.fromhex(''{:0192x}''.format(lepi_int)) bytearray(b''/tc/xb6/x85/xed/xb4/xa8/xf36/xf6$/xc9/xcc+/x02/xd9/xeaE6/xa2/xdff/x9c/x19/xe9yHT/xd1/xd91/x05/xc8/x1c(/x9c/xde/x06/x1c/x04H/x17m/xfe/xda/x9c/x187/r/xb5_/x1d/x0f/xe5"/x9c/xe0}/xe7/x04/xd8/x8c/xc7/xf7e/xc1/xc8/xd6/x98t/xe0/x08/xda/x8b/xd5/xb3/xcd/xfa/xf17/xa3/xa4/x8e/xdc"/x9aA/xe0/xfay*|aho/x1f'')

[Mi respuesta había usado hex() antes. Lo corregí con format() para manejar ints con expresiones de bytes de tamaño impar. Esto soluciona las quejas anteriores sobre ValueError .]


long / int a la matriz de bytes parece el objetivo exacto de struct.pack . Para enteros largos que superan los 4 (8) bytes, puede encontrar algo como el siguiente:

>>> limit = 256*256*256*256 - 1 >>> i = 1234567890987654321 >>> parts = [] >>> while i: parts.append(i & limit) i >>= 32 >>> struct.pack(''>'' + ''L''*len(parts), *parts ) ''/xb1l/x1c/xb1/x11"/x10/xf4'' >>> struct.unpack(''>LL'', ''/xb1l/x1c/xb1/x11"/x10/xf4'') (2976652465L, 287445236) >>> (287445236L << 32) + 2976652465L 1234567890987654321L


i = 0x12345678 s = struct.pack(''<I'',i) b = struct.unpack(''BBBB'',s)