OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # |
| 3 # Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu> |
| 4 # |
| 5 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 # you may not use this file except in compliance with the License. |
| 7 # You may obtain a copy of the License at |
| 8 # |
| 9 # https://www.apache.org/licenses/LICENSE-2.0 |
| 10 # |
| 11 # Unless required by applicable law or agreed to in writing, software |
| 12 # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 # See the License for the specific language governing permissions and |
| 15 # limitations under the License. |
| 16 |
| 17 """Data transformation functions. |
| 18 |
| 19 From bytes to a number, number to bytes, etc. |
| 20 """ |
| 21 |
| 22 from __future__ import absolute_import |
| 23 |
| 24 try: |
| 25 # We'll use psyco if available on 32-bit architectures to speed up code. |
| 26 # Using psyco (if available) cuts down the execution time on Python 2.5 |
| 27 # at least by half. |
| 28 import psyco |
| 29 |
| 30 psyco.full() |
| 31 except ImportError: |
| 32 pass |
| 33 |
| 34 import binascii |
| 35 from struct import pack |
| 36 from rsa import common |
| 37 from rsa._compat import is_integer, b, byte, get_word_alignment, ZERO_BYTE, EMPT
Y_BYTE |
| 38 |
| 39 |
| 40 def bytes2int(raw_bytes): |
| 41 r"""Converts a list of bytes or an 8-bit string to an integer. |
| 42 |
| 43 When using unicode strings, encode it to some encoding like UTF8 first. |
| 44 |
| 45 >>> (((128 * 256) + 64) * 256) + 15 |
| 46 8405007 |
| 47 >>> bytes2int(b'\x80@\x0f') |
| 48 8405007 |
| 49 |
| 50 """ |
| 51 |
| 52 return int(binascii.hexlify(raw_bytes), 16) |
| 53 |
| 54 |
| 55 def _int2bytes(number, block_size=None): |
| 56 r"""Converts a number to a string of bytes. |
| 57 |
| 58 Usage:: |
| 59 |
| 60 >>> _int2bytes(123456789) |
| 61 b'\x07[\xcd\x15' |
| 62 >>> bytes2int(_int2bytes(123456789)) |
| 63 123456789 |
| 64 |
| 65 >>> _int2bytes(123456789, 6) |
| 66 b'\x00\x00\x07[\xcd\x15' |
| 67 >>> bytes2int(_int2bytes(123456789, 128)) |
| 68 123456789 |
| 69 |
| 70 >>> _int2bytes(123456789, 3) |
| 71 Traceback (most recent call last): |
| 72 ... |
| 73 OverflowError: Needed 4 bytes for number, but block size is 3 |
| 74 |
| 75 @param number: the number to convert |
| 76 @param block_size: the number of bytes to output. If the number encoded to |
| 77 bytes is less than this, the block will be zero-padded. When not given, |
| 78 the returned block is not padded. |
| 79 |
| 80 @throws OverflowError when block_size is given and the number takes up more |
| 81 bytes than fit into the block. |
| 82 """ |
| 83 |
| 84 # Type checking |
| 85 if not is_integer(number): |
| 86 raise TypeError("You must pass an integer for 'number', not %s" % |
| 87 number.__class__) |
| 88 |
| 89 if number < 0: |
| 90 raise ValueError('Negative numbers cannot be used: %i' % number) |
| 91 |
| 92 # Do some bounds checking |
| 93 if number == 0: |
| 94 needed_bytes = 1 |
| 95 raw_bytes = [ZERO_BYTE] |
| 96 else: |
| 97 needed_bytes = common.byte_size(number) |
| 98 raw_bytes = [] |
| 99 |
| 100 # You cannot compare None > 0 in Python 3x. It will fail with a TypeError. |
| 101 if block_size and block_size > 0: |
| 102 if needed_bytes > block_size: |
| 103 raise OverflowError('Needed %i bytes for number, but block size ' |
| 104 'is %i' % (needed_bytes, block_size)) |
| 105 |
| 106 # Convert the number to bytes. |
| 107 while number > 0: |
| 108 raw_bytes.insert(0, byte(number & 0xFF)) |
| 109 number >>= 8 |
| 110 |
| 111 # Pad with zeroes to fill the block |
| 112 if block_size and block_size > 0: |
| 113 padding = (block_size - needed_bytes) * ZERO_BYTE |
| 114 else: |
| 115 padding = EMPTY_BYTE |
| 116 |
| 117 return padding + EMPTY_BYTE.join(raw_bytes) |
| 118 |
| 119 |
| 120 def bytes_leading(raw_bytes, needle=ZERO_BYTE): |
| 121 """ |
| 122 Finds the number of prefixed byte occurrences in the haystack. |
| 123 |
| 124 Useful when you want to deal with padding. |
| 125 |
| 126 :param raw_bytes: |
| 127 Raw bytes. |
| 128 :param needle: |
| 129 The byte to count. Default \000. |
| 130 :returns: |
| 131 The number of leading needle bytes. |
| 132 """ |
| 133 |
| 134 leading = 0 |
| 135 # Indexing keeps compatibility between Python 2.x and Python 3.x |
| 136 _byte = needle[0] |
| 137 for x in raw_bytes: |
| 138 if x == _byte: |
| 139 leading += 1 |
| 140 else: |
| 141 break |
| 142 return leading |
| 143 |
| 144 |
| 145 def int2bytes(number, fill_size=None, chunk_size=None, overflow=False): |
| 146 """ |
| 147 Convert an unsigned integer to bytes (base-256 representation):: |
| 148 |
| 149 Does not preserve leading zeros if you don't specify a chunk size or |
| 150 fill size. |
| 151 |
| 152 .. NOTE: |
| 153 You must not specify both fill_size and chunk_size. Only one |
| 154 of them is allowed. |
| 155 |
| 156 :param number: |
| 157 Integer value |
| 158 :param fill_size: |
| 159 If the optional fill size is given the length of the resulting |
| 160 byte string is expected to be the fill size and will be padded |
| 161 with prefix zero bytes to satisfy that length. |
| 162 :param chunk_size: |
| 163 If optional chunk size is given and greater than zero, pad the front of |
| 164 the byte string with binary zeros so that the length is a multiple of |
| 165 ``chunk_size``. |
| 166 :param overflow: |
| 167 ``False`` (default). If this is ``True``, no ``OverflowError`` |
| 168 will be raised when the fill_size is shorter than the length |
| 169 of the generated byte sequence. Instead the byte sequence will |
| 170 be returned as is. |
| 171 :returns: |
| 172 Raw bytes (base-256 representation). |
| 173 :raises: |
| 174 ``OverflowError`` when fill_size is given and the number takes up more |
| 175 bytes than fit into the block. This requires the ``overflow`` |
| 176 argument to this function to be set to ``False`` otherwise, no |
| 177 error will be raised. |
| 178 """ |
| 179 |
| 180 if number < 0: |
| 181 raise ValueError("Number must be an unsigned integer: %d" % number) |
| 182 |
| 183 if fill_size and chunk_size: |
| 184 raise ValueError("You can either fill or pad chunks, but not both") |
| 185 |
| 186 # Ensure these are integers. |
| 187 number & 1 |
| 188 |
| 189 raw_bytes = b('') |
| 190 |
| 191 # Pack the integer one machine word at a time into bytes. |
| 192 num = number |
| 193 word_bits, _, max_uint, pack_type = get_word_alignment(num) |
| 194 pack_format = ">%s" % pack_type |
| 195 while num > 0: |
| 196 raw_bytes = pack(pack_format, num & max_uint) + raw_bytes |
| 197 num >>= word_bits |
| 198 # Obtain the index of the first non-zero byte. |
| 199 zero_leading = bytes_leading(raw_bytes) |
| 200 if number == 0: |
| 201 raw_bytes = ZERO_BYTE |
| 202 # De-padding. |
| 203 raw_bytes = raw_bytes[zero_leading:] |
| 204 |
| 205 length = len(raw_bytes) |
| 206 if fill_size and fill_size > 0: |
| 207 if not overflow and length > fill_size: |
| 208 raise OverflowError( |
| 209 "Need %d bytes for number, but fill size is %d" % |
| 210 (length, fill_size) |
| 211 ) |
| 212 raw_bytes = raw_bytes.rjust(fill_size, ZERO_BYTE) |
| 213 elif chunk_size and chunk_size > 0: |
| 214 remainder = length % chunk_size |
| 215 if remainder: |
| 216 padding_size = chunk_size - remainder |
| 217 raw_bytes = raw_bytes.rjust(length + padding_size, ZERO_BYTE) |
| 218 return raw_bytes |
| 219 |
| 220 |
| 221 if __name__ == '__main__': |
| 222 import doctest |
| 223 |
| 224 doctest.testmod() |
OLD | NEW |