| 1 | """RSA module |
|---|
| 2 | |
|---|
| 3 | !!! This is just a playground, for understanding some bits and pieces, |
|---|
| 4 | this is not at all the production code!!! |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | Module for calculating large primes, and RSA encryption, decryption, |
|---|
| 9 | signing and verification. Includes generating public and private keys. |
|---|
| 10 | """ |
|---|
| 11 | |
|---|
| 12 | __author__ = "Sybren Stuvel, Marloes de Boer and Ivo Tamboer" |
|---|
| 13 | __date__ = "2004-11-17" |
|---|
| 14 | |
|---|
| 15 | # NOTE: Python's modulo can return negative numbers. We compensate for |
|---|
| 16 | # this behaviour using the abs() function |
|---|
| 17 | |
|---|
| 18 | import math |
|---|
| 19 | import sys |
|---|
| 20 | import random # For picking semi-random numbers |
|---|
| 21 | import types |
|---|
| 22 | from pickle import dumps, loads |
|---|
| 23 | import base64 |
|---|
| 24 | import zlib |
|---|
| 25 | |
|---|
| 26 | RANDOM_DEV="/dev/urandom" |
|---|
| 27 | testing = False |
|---|
| 28 | has_broken_randint = False |
|---|
| 29 | |
|---|
| 30 | try: |
|---|
| 31 | #random.randint(1, 10000000000000000000000000L) |
|---|
| 32 | 1+1 |
|---|
| 33 | pass |
|---|
| 34 | except: |
|---|
| 35 | has_broken_randint = True |
|---|
| 36 | print "This system's random.randint() can't handle large numbers" |
|---|
| 37 | print "Random integers will all be read from %s" % RANDOM_DEV |
|---|
| 38 | |
|---|
| 39 | |
|---|
| 40 | def log(x, base = 10): |
|---|
| 41 | return math.log(x) / math.log(base) |
|---|
| 42 | |
|---|
| 43 | def gcd(p, q): |
|---|
| 44 | """Returns the greatest common divisor of p and q |
|---|
| 45 | |
|---|
| 46 | |
|---|
| 47 | >>> gcd(42, 6) |
|---|
| 48 | 6 |
|---|
| 49 | """ |
|---|
| 50 | if p<q: return gcd(q, p) |
|---|
| 51 | if q == 0: return p |
|---|
| 52 | return gcd(q, abs(p%q)) |
|---|
| 53 | |
|---|
| 54 | def bytes2int(bytes): |
|---|
| 55 | """Converts a list of bytes or a string to an integer |
|---|
| 56 | |
|---|
| 57 | >>> (128*256 + 64)*256 + + 15 |
|---|
| 58 | 8405007 |
|---|
| 59 | >>> l = [128, 64, 15] |
|---|
| 60 | >>> bytes2int(l) |
|---|
| 61 | 8405007 |
|---|
| 62 | """ |
|---|
| 63 | |
|---|
| 64 | #if not (type(bytes) is types.ListType or type(bytes) is types.StringType): |
|---|
| 65 | # raise TypeError("You must pass a string or a list") |
|---|
| 66 | |
|---|
| 67 | # Convert byte stream to integer |
|---|
| 68 | integer = 0 |
|---|
| 69 | for byte in bytes: |
|---|
| 70 | integer *= 256 |
|---|
| 71 | if type(byte) is types.StringType: byte = ord(byte) |
|---|
| 72 | integer += byte |
|---|
| 73 | |
|---|
| 74 | return integer |
|---|
| 75 | |
|---|
| 76 | def int2bytes(number): |
|---|
| 77 | """Converts a number to a string of bytes |
|---|
| 78 | |
|---|
| 79 | >>> bytes2int(int2bytes(123456789)) |
|---|
| 80 | 123456789 |
|---|
| 81 | """ |
|---|
| 82 | |
|---|
| 83 | if not (type(number) is types.LongType or type(number) is types.IntType): |
|---|
| 84 | raise TypeError("You must pass a long or an int") |
|---|
| 85 | |
|---|
| 86 | string = "" |
|---|
| 87 | |
|---|
| 88 | while number > 0: |
|---|
| 89 | string = "%s%s" % (chr(number & 0xFF), string) |
|---|
| 90 | number /= 256 |
|---|
| 91 | |
|---|
| 92 | return string |
|---|
| 93 | |
|---|
| 94 | |
|---|
| 95 | def read_random_int(nbits): |
|---|
| 96 | """Reads a random integer from RANDOM_DEV of approximately nbits |
|---|
| 97 | bits rounded up to whole bytes""" |
|---|
| 98 | #print nbits |
|---|
| 99 | nbytes = ceil(nbits/8) |
|---|
| 100 | |
|---|
| 101 | bytes = [] |
|---|
| 102 | for i in range(nbytes): |
|---|
| 103 | bytes.append(random.randint(0,255)) |
|---|
| 104 | return bytes2int(bytes) |
|---|
| 105 | |
|---|
| 106 | |
|---|
| 107 | #jhb |
|---|
| 108 | # Read 'nbits' bits of random data |
|---|
| 109 | #fd = open(RANDOM_DEV) |
|---|
| 110 | #randomdata = fd.read(nbytes) |
|---|
| 111 | #fd.close() |
|---|
| 112 | |
|---|
| 113 | if len(randomdata) != nbytes: |
|---|
| 114 | raise Exception("Unable to read enough random bytes") |
|---|
| 115 | |
|---|
| 116 | return bytes2int(randomdata) |
|---|
| 117 | |
|---|
| 118 | def ceil(x): |
|---|
| 119 | """Returns int(math.ceil(x))""" |
|---|
| 120 | |
|---|
| 121 | return int(math.ceil(x)) |
|---|
| 122 | |
|---|
| 123 | def randint(minvalue, maxvalue): |
|---|
| 124 | """Returns a random integer x with minvalue <= x <= maxvalue""" |
|---|
| 125 | #jhb |
|---|
| 126 | #if not has_broken_randint: |
|---|
| 127 | # return random.randint(minvalue, maxvalue) |
|---|
| 128 | |
|---|
| 129 | # Safety - get a lot of random data even if the range is fairly |
|---|
| 130 | # small |
|---|
| 131 | min_nbits = 32 |
|---|
| 132 | |
|---|
| 133 | # The range of the random numbers we need to generate |
|---|
| 134 | range = maxvalue - minvalue |
|---|
| 135 | |
|---|
| 136 | # Which is this number of bytes |
|---|
| 137 | rangebytes = ceil(log(range, 2) / 8) |
|---|
| 138 | |
|---|
| 139 | # Convert to bits, but make sure it's always at least min_nbits*2 |
|---|
| 140 | rangebits = max(rangebytes * 8, min_nbits * 2) |
|---|
| 141 | |
|---|
| 142 | # Take a random number of bits between min_nbits and rangebits |
|---|
| 143 | nbits = random.randint(min_nbits, rangebits) |
|---|
| 144 | |
|---|
| 145 | return (read_random_int(nbits) % range) + minvalue |
|---|
| 146 | |
|---|
| 147 | def fermat_little_theorem(p): |
|---|
| 148 | """Returns 1 if p may be prime, and something else if p definitely |
|---|
| 149 | is not prime""" |
|---|
| 150 | |
|---|
| 151 | a = randint(1, p-1) |
|---|
| 152 | return fast_exponentiation(a, p-1, p) |
|---|
| 153 | |
|---|
| 154 | def jacobi(a, b): |
|---|
| 155 | """Calculates the value of the Jacobi symbol (a/b) |
|---|
| 156 | """ |
|---|
| 157 | |
|---|
| 158 | if a == 0: return 0 |
|---|
| 159 | if a == 1: return 1 |
|---|
| 160 | |
|---|
| 161 | if a % 2 == 0: |
|---|
| 162 | if (b**2-1)/8 % 2 == 0: |
|---|
| 163 | return jacobi(a/2, b) |
|---|
| 164 | return -jacobi(a/2, b) |
|---|
| 165 | |
|---|
| 166 | if (a-1) * (b-1) / 4 % 2 == 0: |
|---|
| 167 | return jacobi(b % a, a) |
|---|
| 168 | |
|---|
| 169 | return -jacobi(b % a, a) |
|---|
| 170 | |
|---|
| 171 | def jacobi_witness(x, n): |
|---|
| 172 | """Returns False if n is an Euler pseudo-prime with base x, and |
|---|
| 173 | True otherwise. |
|---|
| 174 | """ |
|---|
| 175 | |
|---|
| 176 | j = jacobi(x, n) % n |
|---|
| 177 | f = fast_exponentiation(x, (n-1)/2, n) |
|---|
| 178 | |
|---|
| 179 | if j == f: return False |
|---|
| 180 | return True |
|---|
| 181 | |
|---|
| 182 | def randomized_primality_testing(n, k): |
|---|
| 183 | """Calculates whether n is composite (which is always correct) or |
|---|
| 184 | prime (which is incorrect with error probability 2**-k) |
|---|
| 185 | |
|---|
| 186 | Returns False if the number if composite, and True if it's |
|---|
| 187 | probably prime. |
|---|
| 188 | """ |
|---|
| 189 | |
|---|
| 190 | q = 0.5 # Property of the jacobi_witness function |
|---|
| 191 | |
|---|
| 192 | # t = int(math.ceil(k / log(1/q, 2))) |
|---|
| 193 | t = ceil(k / log(1/q, 2)) |
|---|
| 194 | for i in range(t+1): |
|---|
| 195 | x = randint(1, n-1) |
|---|
| 196 | if jacobi_witness(x, n): return False |
|---|
| 197 | |
|---|
| 198 | return True |
|---|
| 199 | |
|---|
| 200 | def is_prime(number): |
|---|
| 201 | """Returns True if the number is prime, and False otherwise. |
|---|
| 202 | |
|---|
| 203 | >>> is_prime(42) |
|---|
| 204 | 0 |
|---|
| 205 | >>> is_prime(41) |
|---|
| 206 | 1 |
|---|
| 207 | """ |
|---|
| 208 | |
|---|
| 209 | """ |
|---|
| 210 | if not fermat_little_theorem(number) == 1: |
|---|
| 211 | # Not prime, according to Fermat's little theorem |
|---|
| 212 | return False |
|---|
| 213 | """ |
|---|
| 214 | |
|---|
| 215 | if randomized_primality_testing(number, 5): |
|---|
| 216 | # Prime, according to Jacobi |
|---|
| 217 | return True |
|---|
| 218 | |
|---|
| 219 | # Not prime |
|---|
| 220 | return False |
|---|
| 221 | |
|---|
| 222 | |
|---|
| 223 | def getprime(nbits): |
|---|
| 224 | """Returns a prime number of max. 'math.ceil(nbits/8)*8' bits. In |
|---|
| 225 | other words: nbits is rounded up to whole bytes. |
|---|
| 226 | |
|---|
| 227 | >>> p = getprime(8) |
|---|
| 228 | >>> is_prime(p-1) |
|---|
| 229 | 0 |
|---|
| 230 | >>> is_prime(p) |
|---|
| 231 | 1 |
|---|
| 232 | >>> is_prime(p+1) |
|---|
| 233 | 0 |
|---|
| 234 | """ |
|---|
| 235 | |
|---|
| 236 | nbytes = int(math.ceil(nbits/8)) |
|---|
| 237 | |
|---|
| 238 | while True: |
|---|
| 239 | integer = read_random_int(nbits) |
|---|
| 240 | |
|---|
| 241 | # Make sure it's odd |
|---|
| 242 | integer |= 1 |
|---|
| 243 | |
|---|
| 244 | # Test for primeness |
|---|
| 245 | if is_prime(integer): break |
|---|
| 246 | |
|---|
| 247 | # Retry if not prime |
|---|
| 248 | |
|---|
| 249 | return integer |
|---|
| 250 | |
|---|
| 251 | def are_relatively_prime(a, b): |
|---|
| 252 | """Returns True if a and b are relatively prime, and False if they |
|---|
| 253 | are not. |
|---|
| 254 | |
|---|
| 255 | >>> are_relatively_prime(2, 3) |
|---|
| 256 | 1 |
|---|
| 257 | >>> are_relatively_prime(2, 4) |
|---|
| 258 | 0 |
|---|
| 259 | """ |
|---|
| 260 | |
|---|
| 261 | d = gcd(a, b) |
|---|
| 262 | return (d == 1) |
|---|
| 263 | |
|---|
| 264 | def find_p_q(nbits): |
|---|
| 265 | """Returns a tuple of two different primes of nbits bits""" |
|---|
| 266 | |
|---|
| 267 | print 'finding p' |
|---|
| 268 | p = getprime(nbits) |
|---|
| 269 | while True: |
|---|
| 270 | print 'finding q' |
|---|
| 271 | q = getprime(nbits) |
|---|
| 272 | if not q == p: break |
|---|
| 273 | |
|---|
| 274 | return (p, q) |
|---|
| 275 | |
|---|
| 276 | def extended_euclid_gcd(a, b): |
|---|
| 277 | """Returns a tuple (d, i, j) such that d = gcd(a, b) = ia + jb |
|---|
| 278 | """ |
|---|
| 279 | |
|---|
| 280 | if b == 0: |
|---|
| 281 | return (a, 1, 0) |
|---|
| 282 | |
|---|
| 283 | q = abs(a % b) |
|---|
| 284 | r = long(a / b) |
|---|
| 285 | (d, k, l) = extended_euclid_gcd(b, q) |
|---|
| 286 | |
|---|
| 287 | return (d, l, k - l*r) |
|---|
| 288 | |
|---|
| 289 | # Main function: calculate encryption and decryption keys |
|---|
| 290 | def calculate_keys(p, q, nbits): |
|---|
| 291 | """Calculates an encryption and a decryption key for p and q, and |
|---|
| 292 | returns them as a tuple (e, d)""" |
|---|
| 293 | |
|---|
| 294 | n = p * q |
|---|
| 295 | phi_n = (p-1) * (q-1) |
|---|
| 296 | |
|---|
| 297 | while True: |
|---|
| 298 | print 'c' |
|---|
| 299 | # Make sure e has enough bits so we ensure "wrapping" through |
|---|
| 300 | # modulo n |
|---|
| 301 | e = getprime(max(8, nbits/2)) |
|---|
| 302 | if are_relatively_prime(e, n) and are_relatively_prime(e, phi_n): break |
|---|
| 303 | |
|---|
| 304 | (d, i, j) = extended_euclid_gcd(e, phi_n) |
|---|
| 305 | |
|---|
| 306 | if not d == 1: |
|---|
| 307 | raise Exception("e (%d) and phi_n (%d) are not relatively prime" % (e, phi_n)) |
|---|
| 308 | |
|---|
| 309 | if not (e * i) % phi_n == 1: |
|---|
| 310 | raise Exception("e (%d) and i (%d) are not mult. inv. modulo phi_n (%d)" % (e, i, phi_n)) |
|---|
| 311 | |
|---|
| 312 | return (e, i) |
|---|
| 313 | |
|---|
| 314 | |
|---|
| 315 | def gen_keys(nbits): |
|---|
| 316 | """Generate RSA keys of nbits bits. Returns (p, q, e, d). |
|---|
| 317 | """ |
|---|
| 318 | |
|---|
| 319 | while True: |
|---|
| 320 | print 'find' |
|---|
| 321 | (p, q) = find_p_q(nbits) |
|---|
| 322 | print 'calculate' |
|---|
| 323 | (e, d) = calculate_keys(p, q, nbits) |
|---|
| 324 | |
|---|
| 325 | # For some reason, d is sometimes negative. We don't know how |
|---|
| 326 | # to fix it (yet), so we keep trying until everything is shiny |
|---|
| 327 | if d > 0: break |
|---|
| 328 | |
|---|
| 329 | return (p, q, e, d) |
|---|
| 330 | |
|---|
| 331 | def gen_pubpriv_keys(nbits): |
|---|
| 332 | """Generates public and private keys, and returns them as (pub, |
|---|
| 333 | priv). |
|---|
| 334 | |
|---|
| 335 | The public key consists of a dict {e: ..., , n: ....). The private |
|---|
| 336 | key consists of a dict {d: ...., p: ...., q: ....). |
|---|
| 337 | """ |
|---|
| 338 | |
|---|
| 339 | (p, q, e, d) = gen_keys(nbits) |
|---|
| 340 | |
|---|
| 341 | return ( {'e': e, 'n': p*q}, {'d': d, 'p': p, 'q': q} ) |
|---|
| 342 | |
|---|
| 343 | def encrypt_int(message, ekey, n): |
|---|
| 344 | """Encrypts a message using encryption key 'ekey', working modulo |
|---|
| 345 | n""" |
|---|
| 346 | |
|---|
| 347 | if type(message) is types.IntType: |
|---|
| 348 | return encrypt_int(long(message), ekey, n) |
|---|
| 349 | |
|---|
| 350 | if not type(message) is types.LongType: |
|---|
| 351 | raise TypeError("You must pass a long or an int") |
|---|
| 352 | |
|---|
| 353 | #if math.floor(log(message, 2)) > math.floor(log(n, 2)): |
|---|
| 354 | # raise OverflowError("The message is too long") |
|---|
| 355 | |
|---|
| 356 | return fast_exponentiation(message, ekey, n) |
|---|
| 357 | |
|---|
| 358 | def decrypt_int(cyphertext, dkey, n): |
|---|
| 359 | """Decrypts a cypher text using the decryption key 'dkey', working |
|---|
| 360 | modulo n""" |
|---|
| 361 | |
|---|
| 362 | return encrypt_int(cyphertext, dkey, n) |
|---|
| 363 | |
|---|
| 364 | def sign_int(message, dkey, n): |
|---|
| 365 | """Signs 'message' using key 'dkey', working modulo n""" |
|---|
| 366 | |
|---|
| 367 | return decrypt_int(message, dkey, n) |
|---|
| 368 | |
|---|
| 369 | def verify_int(signed, ekey, n): |
|---|
| 370 | """verifies 'signed' using key 'ekey', working modulo n""" |
|---|
| 371 | |
|---|
| 372 | return encrypt_int(signed, ekey, n) |
|---|
| 373 | |
|---|
| 374 | def picklechops(chops): |
|---|
| 375 | """Pickles and base64encodes it's argument chops""" |
|---|
| 376 | |
|---|
| 377 | value = zlib.compress(dumps(chops)) |
|---|
| 378 | encoded = base64.encodestring(value) |
|---|
| 379 | return encoded.strip() |
|---|
| 380 | |
|---|
| 381 | def unpicklechops(string): |
|---|
| 382 | """base64decodes and unpickes it's argument string into chops""" |
|---|
| 383 | |
|---|
| 384 | return loads(zlib.decompress(base64.decodestring(string))) |
|---|
| 385 | |
|---|
| 386 | def chopstring(message, key, n, funcref): |
|---|
| 387 | """Splits 'message' into chops that are at most as long as n, |
|---|
| 388 | converts these into integers, and calls funcref(integer, key, n) |
|---|
| 389 | for each chop. |
|---|
| 390 | |
|---|
| 391 | Used by 'encrypt' and 'sign'. |
|---|
| 392 | """ |
|---|
| 393 | |
|---|
| 394 | msglen = len(message) |
|---|
| 395 | mbits = msglen * 8 |
|---|
| 396 | #nbits = int(math.floor(log(n, 2))) |
|---|
| 397 | nbits = 1024 |
|---|
| 398 | nbytes = nbits / 8 |
|---|
| 399 | blocks = msglen / nbytes |
|---|
| 400 | |
|---|
| 401 | if msglen % nbytes > 0: |
|---|
| 402 | blocks += 1 |
|---|
| 403 | |
|---|
| 404 | cypher = [] |
|---|
| 405 | |
|---|
| 406 | for bindex in range(blocks): |
|---|
| 407 | offset = bindex * nbytes |
|---|
| 408 | block = message[offset:offset+nbytes] |
|---|
| 409 | value = bytes2int(block) |
|---|
| 410 | cypher.append(funcref(value, key, n)) |
|---|
| 411 | |
|---|
| 412 | return picklechops(cypher) |
|---|
| 413 | |
|---|
| 414 | def gluechops(chops, key, n, funcref): |
|---|
| 415 | """Glues chops back together into a string. calls |
|---|
| 416 | funcref(integer, key, n) for each chop. |
|---|
| 417 | |
|---|
| 418 | Used by 'decrypt' and 'verify'. |
|---|
| 419 | """ |
|---|
| 420 | message = "" |
|---|
| 421 | |
|---|
| 422 | chops = unpicklechops(chops) |
|---|
| 423 | |
|---|
| 424 | for cpart in chops: |
|---|
| 425 | mpart = funcref(cpart, key, n) |
|---|
| 426 | message += int2bytes(mpart) |
|---|
| 427 | |
|---|
| 428 | return message |
|---|
| 429 | |
|---|
| 430 | def encrypt(message, key): |
|---|
| 431 | """Encrypts a string 'message' with the public key 'key'""" |
|---|
| 432 | |
|---|
| 433 | return chopstring(message, key['e'], key['n'], encrypt_int) |
|---|
| 434 | |
|---|
| 435 | def sign(message, key): |
|---|
| 436 | """Signs a string 'message' with the private key 'key'""" |
|---|
| 437 | |
|---|
| 438 | return chopstring(message, key['d'], key['p']*key['q'], decrypt_int) |
|---|
| 439 | |
|---|
| 440 | def decrypt(cypher, key): |
|---|
| 441 | """Decrypts a cypher with the private key 'key'""" |
|---|
| 442 | |
|---|
| 443 | return gluechops(cypher, key['d'], key['p']*key['q'], decrypt_int) |
|---|
| 444 | |
|---|
| 445 | def verify(cypher, key): |
|---|
| 446 | """Verifies a cypher with the public key 'key'""" |
|---|
| 447 | |
|---|
| 448 | return gluechops(cypher, key['e'], key['n'], encrypt_int) |
|---|
| 449 | #import math |
|---|
| 450 | |
|---|
| 451 | def bits(integer): #Gets number of bits in integer |
|---|
| 452 | result = 0 |
|---|
| 453 | while integer: |
|---|
| 454 | integer >>= 1 |
|---|
| 455 | result += 1 |
|---|
| 456 | return result |
|---|
| 457 | |
|---|
| 458 | |
|---|
| 459 | fast_exponentiation = pow |
|---|
| 460 | def fast_exponentiation2(base, exponent, modulo=None): #Allows fast exponentation with and without moduli |
|---|
| 461 | print 'in fast_expon' |
|---|
| 462 | result = 1L |
|---|
| 463 | if modulo == None: |
|---|
| 464 | iteration = bits(exponent) |
|---|
| 465 | while iteration >= 0: |
|---|
| 466 | result *= result |
|---|
| 467 | if (exponent >> iteration) & 1: |
|---|
| 468 | result *= base |
|---|
| 469 | iteration -= 1 |
|---|
| 470 | else: |
|---|
| 471 | firstModulus = base % modulo |
|---|
| 472 | iteration = bits(exponent) |
|---|
| 473 | while iteration >= 0: |
|---|
| 474 | result = (result * result) % modulo |
|---|
| 475 | if (exponent >> iteration) & 1: |
|---|
| 476 | result = (result * firstModulus) % modulo |
|---|
| 477 | iteration -= 1 |
|---|
| 478 | return result |
|---|
| 479 | |
|---|
| 480 | def fast_exponentiation1(a, p, n): |
|---|
| 481 | """Calculates r = a^p mod n |
|---|
| 482 | """ |
|---|
| 483 | |
|---|
| 484 | |
|---|
| 485 | out = a |
|---|
| 486 | while p > 1 : |
|---|
| 487 | print a,p,out |
|---|
| 488 | if p & 1 == 0: |
|---|
| 489 | out = (a ** 2) % n |
|---|
| 490 | p = p/2 |
|---|
| 491 | else: |
|---|
| 492 | out = (a * out) % n |
|---|
| 493 | p = p-1 |
|---|
| 494 | return out |
|---|
| 495 | |
|---|
| 496 | def fast_exponentiation2(a, p, n): |
|---|
| 497 | """Calculates r = a^p mod n |
|---|
| 498 | """ |
|---|
| 499 | if p == 0: |
|---|
| 500 | return 1 |
|---|
| 501 | if p & 1 == 0: # even |
|---|
| 502 | t = fast_exponentiation2(a, p/2, n) |
|---|
| 503 | up = t**2 % n |
|---|
| 504 | #print up |
|---|
| 505 | #return up |
|---|
| 506 | else: |
|---|
| 507 | t = fast_exponentiation2(a, (p-1)/2, n) |
|---|
| 508 | up = (a * (t**2 % n)) % n |
|---|
| 509 | #print up |
|---|
| 510 | #return up |
|---|
| 511 | |
|---|
| 512 | print "fast_exponentiation2", a, p, n,up |
|---|
| 513 | return up |
|---|
| 514 | |
|---|
| 515 | |
|---|
| 516 | |
|---|
| 517 | # Do doctest if we're not imported |
|---|
| 518 | if __name__ == "__main__": |
|---|
| 519 | if 1: |
|---|
| 520 | import time |
|---|
| 521 | (pub,priv) = gen_pubpriv_keys(512) |
|---|
| 522 | t = time.time() |
|---|
| 523 | print 'keys ',pub, priv |
|---|
| 524 | message = 'serial '*5 |
|---|
| 525 | print 'cleartext ', message |
|---|
| 526 | for i in range(10): |
|---|
| 527 | cypher = encrypt(message,pub) |
|---|
| 528 | print 'cyphertext: ',cypher |
|---|
| 529 | print 'decrypted', decrypt(cypher,priv) |
|---|
| 530 | print time.time() - t |
|---|
| 531 | print `fast_exponentiation` |
|---|
| 532 | #(a,p,n) = (62,65,133) |
|---|
| 533 | #print fast_exponentiation(a, p,n) |
|---|
| 534 | #print fast_exponentiation2(a, p,n) |
|---|
| 535 | #print fast_exponentiation3(a, p,n) |
|---|
| 536 | __all__ = ["gen_pubpriv_keys", "encrypt", "decrypt", "sign", "verify"] |
|---|