我试图在python中实现RC4和DH密钥交换。问题是我不知道如何将密钥交换中的python long/int转换为RC4实现所需的字节数组。有没有一种简单的方法将long转换为所需长度的字节数组?将python long/int转换为固定大小的字节数组
更新:忘记提及我正在处理的数字是768位无符号整数。
我试图在python中实现RC4和DH密钥交换。问题是我不知道如何将密钥交换中的python long/int转换为RC4实现所需的字节数组。有没有一种简单的方法将long转换为所需长度的字节数组?将python long/int转换为固定大小的字节数组
更新:忘记提及我正在处理的数字是768位无符号整数。
我还没有做任何基准测试,但这个配方“适合我”。
简短版本:使用'%x' % val
,然后unhexlify
的结果。尽管如此,恶魔仍在细节中,因为unhexlify
需要偶数个十六进制数字,而%x
并不能保证。有关详细信息,请参阅文档字符串和自由内联注释。
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://stackoverflow.com/a/931095/309233
s = s[::-1]
return s
...我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(0xab23456c89)
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(0x123456789)
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(0xab23456c89, '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(0x123456789, 'little')
assert s == '\x67\x45\x23\x01\x89\x67\x45\x23\x01'
当值为0时遇到问题(Python 3.5)'''binascii.Error:奇数长度字符串''',快速修复:如果fmt%val =='0',用'''s = unhexlify('00')替换'''s = unhexlify(fmt%val)'else unhexlify(fmt% val)''' – Kevin 2016-11-30 14:05:23
长/ INT字节数组貌似struct.pack
确切目的。对于超过4(8)字节长的整数,你能拿出类似下一:
>>> 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
但是它对大数字(> 8字节)没有帮助,通常用于加密应用程序。 – interjay 2012-01-04 17:48:13
它被写为不是通用的,但更像是固定大小的解决方案,以表示所有可能的IP或类似的常见问题... – bigkahunaburger 2016-09-08 21:38:50
基本上你需要做的是转换INT /长入其基体256的表示 - 即一个数其“数字”范围从0-255。这是一个相当有效的方式做这样的事情:
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
你们中许多人并不需要reversed()
呼叫取决于字节序所需的(这样做需要填充做不同以及)。另外请注意,正如它所写的,它不处理负数。
您可能还想看看number.py
模块中类似但高度优化的long_to_bytes()
函数,该函数是开源Python Cryptography Toolkit的一部分。它实际上将数字转换为一个字符串,而不是字节数组,但这是一个小问题。
小端,如果你想大端逆转的结果或范围。
def int_to_bytes(val, num_bytes):
return [(val & (0xff << pos*8)) >> pos*8 for pos in range(num_bytes)]
一行代码:
bytearray.fromhex('{:0192x}'.format(big_int))
的192是768/4,因为OP想768位数字,并有一个十六进制数字4位。如果您需要更大的bytearray
,请使用数字较大的格式字符串。例如:
>>> 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')
[我的回答之前用过hex()
。我纠正它与format()
为了处理与奇数大小的字节表达式整数。这修复了以前对ValueError
的投诉。]
它不起作用,如果你不产生一个龙虽然。我认为smt像 bytearray.fromhex(十六进制(2 ** 61-1).strip('0x')。strip('L'))更安全 – 2014-07-07 09:30:29
@MarioAlemi评论中的代码是错误的。 strip('0x')'也会去掉尾部的零,这会导致错误的结果(有时候也会产生'ValueError')! – Lepi 2014-12-05 18:07:24
@Jess Austin:你的解决方案是完全错误的,因为它仅在x由偶数个十六进制数组成时才起作用。 实施例: 'X = 0x963b685edb4a8f336f624c9cc2b02d9ea4536a2df669c19e9794854d1d93105c81c289cde061c0448176dfeda9c18370db55f1d0fe5229ce07de704d88cc7f765c1c8d69874e008da8bd5b3cdfaf137a3a48edc229a41e0fa792a7c61686f1fL' – Lepi 2014-12-05 18:26:06
与Python 3。2和更高版本,可以使用int.to_bytes
和int.from_bytes
:https://docs.python.org/3/library/stdtypes.html#int.to_bytes
大家都过于复杂的这样的回答:
some_int = <256 bit integer>
some_bytes = some_int.to_bytes(32, sys.byteorder)
my_bytearray = bytearray(some_bytes)
你只需要知道你正试图转换的字节数。在我的用例中,通常我只使用这个大数字作为加密函数,那时我不得不担心模数和不是什么,所以我不认为这是需要知道最大数量的大问题的字节返回。
既然你正在做它为768位数学,然后代替32作为自变量,它是96
的Python 2.7没有实现int.to-非常slow_bytes()方法。
我试图3种方法:
所有这些方法的原因有两个非常低效:
i = 0x12345678
s = struct.pack('<I',i)
b = struct.unpack('BBBB',s)
不知道这是否会帮助,但检查'struct'模块:http://docs.python.org/library/struct.html – 2012-01-04 17:34:13
有多大你的号码? – interjay 2012-01-04 17:41:44