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 """Deprecated version of the RSA module |
| 18 |
| 19 .. deprecated:: 2.0 |
| 20 |
| 21 This submodule is deprecated and will be completely removed as of version 4.
0. |
| 22 |
| 23 Module for calculating large primes, and RSA encryption, decryption, |
| 24 signing and verification. Includes generating public and private keys. |
| 25 |
| 26 WARNING: this code implements the mathematics of RSA. It is not suitable for |
| 27 real-world secure cryptography purposes. It has not been reviewed by a security |
| 28 expert. It does not include padding of data. There are many ways in which the |
| 29 output of this module, when used without any modification, can be sucessfully |
| 30 attacked. |
| 31 """ |
| 32 |
| 33 __author__ = "Sybren Stuvel, Marloes de Boer and Ivo Tamboer" |
| 34 __date__ = "2010-02-05" |
| 35 __version__ = '1.3.3' |
| 36 |
| 37 # NOTE: Python's modulo can return negative numbers. We compensate for |
| 38 # this behaviour using the abs() function |
| 39 |
| 40 try: |
| 41 import cPickle as pickle |
| 42 except ImportError: |
| 43 import pickle |
| 44 from pickle import dumps, loads |
| 45 import base64 |
| 46 import math |
| 47 import os |
| 48 import random |
| 49 import sys |
| 50 import types |
| 51 import zlib |
| 52 |
| 53 from rsa._compat import byte |
| 54 |
| 55 # Display a warning that this insecure version is imported. |
| 56 import warnings |
| 57 warnings.warn('Insecure version of the RSA module is imported as %s, be careful' |
| 58 % __name__) |
| 59 warnings.warn('This submodule is deprecated and will be completely removed as of
version 4.0.', |
| 60 DeprecationWarning) |
| 61 |
| 62 |
| 63 def gcd(p, q): |
| 64 """Returns the greatest common divisor of p and q |
| 65 |
| 66 |
| 67 >>> gcd(42, 6) |
| 68 6 |
| 69 """ |
| 70 if p<q: return gcd(q, p) |
| 71 if q == 0: return p |
| 72 return gcd(q, abs(p%q)) |
| 73 |
| 74 def bytes2int(bytes): |
| 75 """Converts a list of bytes or a string to an integer |
| 76 """ |
| 77 |
| 78 if not (type(bytes) is types.ListType or type(bytes) is types.StringType): |
| 79 raise TypeError("You must pass a string or a list") |
| 80 |
| 81 # Convert byte stream to integer |
| 82 integer = 0 |
| 83 for byte in bytes: |
| 84 integer *= 256 |
| 85 if type(byte) is types.StringType: byte = ord(byte) |
| 86 integer += byte |
| 87 |
| 88 return integer |
| 89 |
| 90 def int2bytes(number): |
| 91 """Converts a number to a string of bytes |
| 92 """ |
| 93 |
| 94 if not (type(number) is types.LongType or type(number) is types.IntType): |
| 95 raise TypeError("You must pass a long or an int") |
| 96 |
| 97 string = "" |
| 98 |
| 99 while number > 0: |
| 100 string = "%s%s" % (byte(number & 0xFF), string) |
| 101 number /= 256 |
| 102 |
| 103 return string |
| 104 |
| 105 def fast_exponentiation(a, p, n): |
| 106 """Calculates r = a^p mod n |
| 107 """ |
| 108 result = a % n |
| 109 remainders = [] |
| 110 while p != 1: |
| 111 remainders.append(p & 1) |
| 112 p = p >> 1 |
| 113 while remainders: |
| 114 rem = remainders.pop() |
| 115 result = ((a ** rem) * result ** 2) % n |
| 116 return result |
| 117 |
| 118 def read_random_int(nbits): |
| 119 """Reads a random integer of approximately nbits bits rounded up |
| 120 to whole bytes""" |
| 121 |
| 122 nbytes = ceil(nbits/8.) |
| 123 randomdata = os.urandom(nbytes) |
| 124 return bytes2int(randomdata) |
| 125 |
| 126 def ceil(x): |
| 127 """ceil(x) -> int(math.ceil(x))""" |
| 128 |
| 129 return int(math.ceil(x)) |
| 130 |
| 131 def randint(minvalue, maxvalue): |
| 132 """Returns a random integer x with minvalue <= x <= maxvalue""" |
| 133 |
| 134 # Safety - get a lot of random data even if the range is fairly |
| 135 # small |
| 136 min_nbits = 32 |
| 137 |
| 138 # The range of the random numbers we need to generate |
| 139 range = maxvalue - minvalue |
| 140 |
| 141 # Which is this number of bytes |
| 142 rangebytes = ceil(math.log(range, 2) / 8.) |
| 143 |
| 144 # Convert to bits, but make sure it's always at least min_nbits*2 |
| 145 rangebits = max(rangebytes * 8, min_nbits * 2) |
| 146 |
| 147 # Take a random number of bits between min_nbits and rangebits |
| 148 nbits = random.randint(min_nbits, rangebits) |
| 149 |
| 150 return (read_random_int(nbits) % range) + minvalue |
| 151 |
| 152 def fermat_little_theorem(p): |
| 153 """Returns 1 if p may be prime, and something else if p definitely |
| 154 is not prime""" |
| 155 |
| 156 a = randint(1, p-1) |
| 157 return fast_exponentiation(a, p-1, p) |
| 158 |
| 159 def jacobi(a, b): |
| 160 """Calculates the value of the Jacobi symbol (a/b) |
| 161 """ |
| 162 |
| 163 if a % b == 0: |
| 164 return 0 |
| 165 result = 1 |
| 166 while a > 1: |
| 167 if a & 1: |
| 168 if ((a-1)*(b-1) >> 2) & 1: |
| 169 result = -result |
| 170 b, a = a, b % a |
| 171 else: |
| 172 if ((b ** 2 - 1) >> 3) & 1: |
| 173 result = -result |
| 174 a = a >> 1 |
| 175 return result |
| 176 |
| 177 def jacobi_witness(x, n): |
| 178 """Returns False if n is an Euler pseudo-prime with base x, and |
| 179 True otherwise. |
| 180 """ |
| 181 |
| 182 j = jacobi(x, n) % n |
| 183 f = fast_exponentiation(x, (n-1)/2, n) |
| 184 |
| 185 if j == f: return False |
| 186 return True |
| 187 |
| 188 def randomized_primality_testing(n, k): |
| 189 """Calculates whether n is composite (which is always correct) or |
| 190 prime (which is incorrect with error probability 2**-k) |
| 191 |
| 192 Returns False if the number if composite, and True if it's |
| 193 probably prime. |
| 194 """ |
| 195 |
| 196 q = 0.5 # Property of the jacobi_witness function |
| 197 |
| 198 # t = int(math.ceil(k / math.log(1/q, 2))) |
| 199 t = ceil(k / math.log(1/q, 2)) |
| 200 for i in range(t+1): |
| 201 x = randint(1, n-1) |
| 202 if jacobi_witness(x, n): return False |
| 203 |
| 204 return True |
| 205 |
| 206 def is_prime(number): |
| 207 """Returns True if the number is prime, and False otherwise. |
| 208 """ |
| 209 |
| 210 """ |
| 211 if not fermat_little_theorem(number) == 1: |
| 212 # Not prime, according to Fermat's little theorem |
| 213 return False |
| 214 """ |
| 215 |
| 216 if randomized_primality_testing(number, 5): |
| 217 # Prime, according to Jacobi |
| 218 return True |
| 219 |
| 220 # Not prime |
| 221 return False |
| 222 |
| 223 |
| 224 def getprime(nbits): |
| 225 """Returns a prime number of max. 'math.ceil(nbits/8)*8' bits. In |
| 226 other words: nbits is rounded up to whole bytes. |
| 227 """ |
| 228 |
| 229 nbytes = int(math.ceil(nbits/8.)) |
| 230 |
| 231 while True: |
| 232 integer = read_random_int(nbits) |
| 233 |
| 234 # Make sure it's odd |
| 235 integer |= 1 |
| 236 |
| 237 # Test for primeness |
| 238 if is_prime(integer): break |
| 239 |
| 240 # Retry if not prime |
| 241 |
| 242 return integer |
| 243 |
| 244 def are_relatively_prime(a, b): |
| 245 """Returns True if a and b are relatively prime, and False if they |
| 246 are not. |
| 247 """ |
| 248 |
| 249 d = gcd(a, b) |
| 250 return (d == 1) |
| 251 |
| 252 def find_p_q(nbits): |
| 253 """Returns a tuple of two different primes of nbits bits""" |
| 254 |
| 255 p = getprime(nbits) |
| 256 while True: |
| 257 q = getprime(nbits) |
| 258 if not q == p: break |
| 259 |
| 260 return (p, q) |
| 261 |
| 262 def extended_euclid_gcd(a, b): |
| 263 """Returns a tuple (d, i, j) such that d = gcd(a, b) = ia + jb |
| 264 """ |
| 265 |
| 266 if b == 0: |
| 267 return (a, 1, 0) |
| 268 |
| 269 q = abs(a % b) |
| 270 r = long(a / b) |
| 271 (d, k, l) = extended_euclid_gcd(b, q) |
| 272 |
| 273 return (d, l, k - l*r) |
| 274 |
| 275 # Main function: calculate encryption and decryption keys |
| 276 def calculate_keys(p, q, nbits): |
| 277 """Calculates an encryption and a decryption key for p and q, and |
| 278 returns them as a tuple (e, d)""" |
| 279 |
| 280 n = p * q |
| 281 phi_n = (p-1) * (q-1) |
| 282 |
| 283 while True: |
| 284 # Make sure e has enough bits so we ensure "wrapping" through |
| 285 # modulo n |
| 286 e = getprime(max(8, nbits/2)) |
| 287 if are_relatively_prime(e, n) and are_relatively_prime(e, phi_n): break |
| 288 |
| 289 (d, i, j) = extended_euclid_gcd(e, phi_n) |
| 290 |
| 291 if not d == 1: |
| 292 raise Exception("e (%d) and phi_n (%d) are not relatively prime" % (e, p
hi_n)) |
| 293 |
| 294 if not (e * i) % phi_n == 1: |
| 295 raise Exception("e (%d) and i (%d) are not mult. inv. modulo phi_n (%d)"
% (e, i, phi_n)) |
| 296 |
| 297 return (e, i) |
| 298 |
| 299 |
| 300 def gen_keys(nbits): |
| 301 """Generate RSA keys of nbits bits. Returns (p, q, e, d). |
| 302 |
| 303 Note: this can take a long time, depending on the key size. |
| 304 """ |
| 305 |
| 306 while True: |
| 307 (p, q) = find_p_q(nbits) |
| 308 (e, d) = calculate_keys(p, q, nbits) |
| 309 |
| 310 # For some reason, d is sometimes negative. We don't know how |
| 311 # to fix it (yet), so we keep trying until everything is shiny |
| 312 if d > 0: break |
| 313 |
| 314 return (p, q, e, d) |
| 315 |
| 316 def gen_pubpriv_keys(nbits): |
| 317 """Generates public and private keys, and returns them as (pub, |
| 318 priv). |
| 319 |
| 320 The public key consists of a dict {e: ..., , n: ....). The private |
| 321 key consists of a dict {d: ...., p: ...., q: ....). |
| 322 """ |
| 323 |
| 324 (p, q, e, d) = gen_keys(nbits) |
| 325 |
| 326 return ( {'e': e, 'n': p*q}, {'d': d, 'p': p, 'q': q} ) |
| 327 |
| 328 def encrypt_int(message, ekey, n): |
| 329 """Encrypts a message using encryption key 'ekey', working modulo |
| 330 n""" |
| 331 |
| 332 if type(message) is types.IntType: |
| 333 return encrypt_int(long(message), ekey, n) |
| 334 |
| 335 if not type(message) is types.LongType: |
| 336 raise TypeError("You must pass a long or an int") |
| 337 |
| 338 if message > 0 and \ |
| 339 math.floor(math.log(message, 2)) > math.floor(math.log(n, 2)): |
| 340 raise OverflowError("The message is too long") |
| 341 |
| 342 return fast_exponentiation(message, ekey, n) |
| 343 |
| 344 def decrypt_int(cyphertext, dkey, n): |
| 345 """Decrypts a cypher text using the decryption key 'dkey', working |
| 346 modulo n""" |
| 347 |
| 348 return encrypt_int(cyphertext, dkey, n) |
| 349 |
| 350 def sign_int(message, dkey, n): |
| 351 """Signs 'message' using key 'dkey', working modulo n""" |
| 352 |
| 353 return decrypt_int(message, dkey, n) |
| 354 |
| 355 def verify_int(signed, ekey, n): |
| 356 """verifies 'signed' using key 'ekey', working modulo n""" |
| 357 |
| 358 return encrypt_int(signed, ekey, n) |
| 359 |
| 360 def picklechops(chops): |
| 361 """Pickles and base64encodes it's argument chops""" |
| 362 |
| 363 value = zlib.compress(dumps(chops)) |
| 364 encoded = base64.encodestring(value) |
| 365 return encoded.strip() |
| 366 |
| 367 def unpicklechops(string): |
| 368 """base64decodes and unpickes it's argument string into chops""" |
| 369 |
| 370 return loads(zlib.decompress(base64.decodestring(string))) |
| 371 |
| 372 def chopstring(message, key, n, funcref): |
| 373 """Splits 'message' into chops that are at most as long as n, |
| 374 converts these into integers, and calls funcref(integer, key, n) |
| 375 for each chop. |
| 376 |
| 377 Used by 'encrypt' and 'sign'. |
| 378 """ |
| 379 |
| 380 msglen = len(message) |
| 381 mbits = msglen * 8 |
| 382 nbits = int(math.floor(math.log(n, 2))) |
| 383 nbytes = nbits / 8 |
| 384 blocks = msglen / nbytes |
| 385 |
| 386 if msglen % nbytes > 0: |
| 387 blocks += 1 |
| 388 |
| 389 cypher = [] |
| 390 |
| 391 for bindex in range(blocks): |
| 392 offset = bindex * nbytes |
| 393 block = message[offset:offset+nbytes] |
| 394 value = bytes2int(block) |
| 395 cypher.append(funcref(value, key, n)) |
| 396 |
| 397 return picklechops(cypher) |
| 398 |
| 399 def gluechops(chops, key, n, funcref): |
| 400 """Glues chops back together into a string. calls |
| 401 funcref(integer, key, n) for each chop. |
| 402 |
| 403 Used by 'decrypt' and 'verify'. |
| 404 """ |
| 405 message = "" |
| 406 |
| 407 chops = unpicklechops(chops) |
| 408 |
| 409 for cpart in chops: |
| 410 mpart = funcref(cpart, key, n) |
| 411 message += int2bytes(mpart) |
| 412 |
| 413 return message |
| 414 |
| 415 def encrypt(message, key): |
| 416 """Encrypts a string 'message' with the public key 'key'""" |
| 417 |
| 418 return chopstring(message, key['e'], key['n'], encrypt_int) |
| 419 |
| 420 def sign(message, key): |
| 421 """Signs a string 'message' with the private key 'key'""" |
| 422 |
| 423 return chopstring(message, key['d'], key['p']*key['q'], decrypt_int) |
| 424 |
| 425 def decrypt(cypher, key): |
| 426 """Decrypts a cypher with the private key 'key'""" |
| 427 |
| 428 return gluechops(cypher, key['d'], key['p']*key['q'], decrypt_int) |
| 429 |
| 430 def verify(cypher, key): |
| 431 """Verifies a cypher with the public key 'key'""" |
| 432 |
| 433 return gluechops(cypher, key['e'], key['n'], encrypt_int) |
| 434 |
| 435 # Do doctest if we're not imported |
| 436 if __name__ == "__main__": |
| 437 import doctest |
| 438 doctest.testmod() |
| 439 |
| 440 __all__ = ["gen_pubpriv_keys", "encrypt", "decrypt", "sign", "verify"] |
| 441 |
OLD | NEW |