Skip to content

Commit 6a918c4

Browse files
committed
use native methods for number to bytes conversion
1 parent 56b47c6 commit 6a918c4

File tree

2 files changed

+79
-33
lines changed

2 files changed

+79
-33
lines changed

tlslite/utils/compat.py

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,21 @@
1616
if sys.version_info >= (3,0):
1717

1818
def compat26Str(x): return x
19-
20-
# Python 3 requires bytes instead of bytearrays for HMAC
21-
19+
20+
# Python 3.3 requires bytes instead of bytearrays for HMAC
2221
# So, python 2.6 requires strings, python 3 requires 'bytes',
23-
# and python 2.7 can handle bytearrays...
24-
def compatHMAC(x): return bytes(x)
22+
# and python 2.7 and 3.5 can handle bytearrays...
23+
# pylint: disable=invalid-name
24+
# we need to keep compatHMAC and `x` for API compatibility
25+
if sys.version_info < (3, 4):
26+
def compatHMAC(x):
27+
"""Convert bytes-like input to format acceptable for HMAC."""
28+
return bytes(x)
29+
else:
30+
def compatHMAC(x):
31+
"""Convert bytes-like input to format acceptable for HMAC."""
32+
return x
33+
# pylint: enable=invalid-name
2534

2635
def compatAscii2Bytes(val):
2736
"""Convert ASCII string to bytes."""
@@ -80,7 +89,24 @@ def remove_whitespace(text):
8089
"""Removes all whitespace from passed in string"""
8190
return re.sub(r"\s+", "", text, flags=re.UNICODE)
8291

92+
# pylint: disable=invalid-name
93+
# pylint is stupid here and deson't notice it's a function, not
94+
# constant
8395
bytes_to_int = int.from_bytes
96+
# pylint: enable=invalid-name
97+
98+
def bit_length(val):
99+
"""Return number of bits necessary to represent an integer."""
100+
return val.bit_length()
101+
102+
def int_to_bytes(val, length=None, byteorder="big"):
103+
"""Return number converted to bytes"""
104+
if length is None:
105+
length = byte_length(val)
106+
# for gmpy we need to convert back to native int
107+
if type(val) != int:
108+
val = int(val)
109+
return bytearray(val.to_bytes(length=length, byteorder=byteorder))
84110

85111
else:
86112
# Python 2.6 requires strings instead of bytearrays in a couple places,
@@ -94,13 +120,23 @@ def compat26Str(x): return str(x)
94120
def remove_whitespace(text):
95121
"""Removes all whitespace from passed in string"""
96122
return re.sub(r"\s+", "", text)
123+
124+
def bit_length(val):
125+
"""Return number of bits necessary to represent an integer."""
126+
if val == 0:
127+
return 0
128+
return len(bin(val))-2
97129
else:
98130
def compat26Str(x): return x
99131

100132
def remove_whitespace(text):
101133
"""Removes all whitespace from passed in string"""
102134
return re.sub(r"\s+", "", text, flags=re.UNICODE)
103135

136+
def bit_length(val):
137+
"""Return number of bits necessary to represent an integer."""
138+
return val.bit_length()
139+
104140
def compatAscii2Bytes(val):
105141
"""Convert ASCII string to bytes."""
106142
return val
@@ -159,6 +195,25 @@ def bytes_to_int(val, byteorder):
159195
return int(b2a_hex(val[::-1]), 16)
160196
raise ValueError("Only 'big' and 'little' endian supported")
161197

198+
def int_to_bytes(val, length=None, byteorder="big"):
199+
"""Return number converted to bytes"""
200+
if length is None:
201+
length = byte_length(val)
202+
if byteorder == "big":
203+
return bytearray((val >> i) & 0xff
204+
for i in reversed(range(0, length*8, 8)))
205+
if byteorder == "little":
206+
return bytearray((val >> i) & 0xff
207+
for i in range(0, length*8, 8))
208+
raise ValueError("Only 'big' or 'little' endian supported")
209+
210+
211+
def byte_length(val):
212+
"""Return number of bytes necessary to represent an integer."""
213+
length = bit_length(val)
214+
return (length + 7) // 8
215+
216+
162217
try:
163218
# Fedora and Red Hat Enterprise Linux versions have small curves removed
164219
getattr(ecdsa, 'NIST192p')

tlslite/utils/cryptomath.py

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
import math
1414
import base64
1515
import binascii
16-
import sys
1716

18-
from .compat import compat26Str, compatHMAC, compatLong, bytes_to_int
17+
from .compat import compat26Str, compatHMAC, compatLong, \
18+
bytes_to_int, int_to_bytes, bit_length, byte_length
1919
from .codec import Writer
2020

2121
from . import tlshashlib as hashlib
@@ -215,16 +215,14 @@ def numberToByteArray(n, howManyBytes=None, endian="big"):
215215
not be larger. The returned bytearray will contain a big- or little-endian
216216
encoding of the input integer (n). Big endian encoding is used by default.
217217
"""
218-
if howManyBytes == None:
219-
howManyBytes = numBytes(n)
220-
if endian == "big":
221-
return bytearray((n >> i) & 0xff
222-
for i in reversed(range(0, howManyBytes*8, 8)))
223-
elif endian == "little":
224-
return bytearray((n >> i) & 0xff
225-
for i in range(0, howManyBytes*8, 8))
226-
else:
227-
raise ValueError("Only 'big' and 'little' endian supported")
218+
if howManyBytes is not None:
219+
length = byte_length(n)
220+
if howManyBytes < length:
221+
ret = int_to_bytes(n, length, endian)
222+
if endian == "big":
223+
return ret[length-howManyBytes:length]
224+
return ret[:howManyBytes]
225+
return int_to_bytes(n, howManyBytes, endian)
228226

229227

230228
def mpiToNumber(mpi):
@@ -255,23 +253,16 @@ def numberToMPI(n):
255253
# Misc. Utility Functions
256254
# **************************************************************************
257255

258-
def numBits(n):
259-
"""Return number of bits necessary to represent the integer in binary"""
260-
if n==0:
261-
return 0
262-
if sys.version_info < (2, 7):
263-
# bit_length() was introduced in 2.7, and it is an order of magnitude
264-
# faster than the below code
265-
return len(bin(n))-2
266-
else:
267-
return n.bit_length()
268256

269-
def numBytes(n):
270-
"""Return number of bytes necessary to represent the integer in bytes"""
271-
if n==0:
272-
return 0
273-
bits = numBits(n)
274-
return (bits + 7) // 8
257+
# pylint: disable=invalid-name
258+
# pylint recognises them as constants, not function names, also
259+
# we can't change their names without API change
260+
numBits = bit_length
261+
262+
263+
numBytes = byte_length
264+
# pylint: enable=invalid-name
265+
275266

276267
# **************************************************************************
277268
# Big Number Math

0 commit comments

Comments
 (0)