]>
gitweb.pimeys.fr Git - NK2015_Client_Python_Alpha.git/blob - rsa_source/rsa/_version133.py
2 pri = k[1] //Private part of keys d,p,q
4 Module for calculating large primes, and RSA encryption, decryption,
5 signing and verification. Includes generating public and private keys.
7 WARNING: this code implements the mathematics of RSA. It is not suitable for
8 real-world secure cryptography purposes. It has not been reviewed by a security
9 expert. It does not include padding of data. There are many ways in which the
10 output of this module, when used without any modification, can be sucessfully
14 __author__
= "Sybren Stuvel, Marloes de Boer and Ivo Tamboer"
15 __date__
= "2010-02-05"
18 # NOTE: Python's modulo can return negative numbers. We compensate for
19 # this behaviour using the abs() function
21 from cPickle
import dumps
, loads
30 # Display a warning that this insecure version is imported.
32 warnings
.warn('Insecure version of the RSA module is imported as %s, be careful'
36 """Returns the greatest common divisor of p and q
42 if p
<q
: return gcd(q
, p
)
44 return gcd(q
, abs(p
%q
))
47 """Converts a list of bytes or a string to an integer
49 >>> (128*256 + 64)*256 + + 15
56 if not (type(bytes
) is types
.ListType
or type(bytes
) is types
.StringType
):
57 raise TypeError("You must pass a string or a list")
59 # Convert byte stream to integer
63 if type(byte
) is types
.StringType
: byte
= ord(byte
)
68 def int2bytes(number
):
69 """Converts a number to a string of bytes
71 >>> bytes2int(int2bytes(123456789))
75 if not (type(number
) is types
.LongType
or type(number
) is types
.IntType
):
76 raise TypeError("You must pass a long or an int")
81 string
= "%s%s" % (chr(number
& 0xFF), string
)
86 def fast_exponentiation(a
, p
, n
):
87 """Calculates r = a^p mod n
92 remainders
.append(p
& 1)
95 rem
= remainders
.pop()
96 result
= ((a
** rem
) * result
** 2) % n
99 def read_random_int(nbits
):
100 """Reads a random integer of approximately nbits bits rounded up
103 nbytes
= ceil(nbits
/8.)
104 randomdata
= os
.urandom(nbytes
)
105 return bytes2int(randomdata
)
108 """ceil(x) -> int(math.ceil(x))"""
110 return int(math
.ceil(x
))
112 def randint(minvalue
, maxvalue
):
113 """Returns a random integer x with minvalue <= x <= maxvalue"""
115 # Safety - get a lot of random data even if the range is fairly
119 # The range of the random numbers we need to generate
120 range = maxvalue
- minvalue
122 # Which is this number of bytes
123 rangebytes
= ceil(math
.log(range, 2) / 8.)
125 # Convert to bits, but make sure it's always at least min_nbits*2
126 rangebits
= max(rangebytes
* 8, min_nbits
* 2)
128 # Take a random number of bits between min_nbits and rangebits
129 nbits
= random
.randint(min_nbits
, rangebits
)
131 return (read_random_int(nbits
) % range) + minvalue
133 def fermat_little_theorem(p
):
134 """Returns 1 if p may be prime, and something else if p definitely
138 return fast_exponentiation(a
, p
-1, p
)
141 """Calculates the value of the Jacobi symbol (a/b)
149 if ((a
-1)*(b
-1) >> 2) & 1:
153 if ((b
** 2 - 1) >> 3) & 1:
158 def jacobi_witness(x
, n
):
159 """Returns False if n is an Euler pseudo-prime with base x, and
164 f
= fast_exponentiation(x
, (n
-1)/2, n
)
166 if j
== f
: return False
169 def randomized_primality_testing(n
, k
):
170 """Calculates whether n is composite (which is always correct) or
171 prime (which is incorrect with error probability 2**-k)
173 Returns False if the number if composite, and True if it's
177 q
= 0.5 # Property of the jacobi_witness function
179 # t = int(math.ceil(k / math.log(1/q, 2)))
180 t
= ceil(k
/ math
.log(1/q
, 2))
183 if jacobi_witness(x
, n
): return False
187 def is_prime(number
):
188 """Returns True if the number is prime, and False otherwise.
197 if not fermat_little_theorem(number) == 1:
198 # Not prime, according to Fermat's little theorem
202 if randomized_primality_testing(number
, 5):
203 # Prime, according to Jacobi
211 """Returns a prime number of max. 'math.ceil(nbits/8)*8' bits. In
212 other words: nbits is rounded up to whole bytes.
223 nbytes
= int(math
.ceil(nbits
/8.))
226 integer
= read_random_int(nbits
)
232 if is_prime(integer
): break
238 def are_relatively_prime(a
, b
):
239 """Returns True if a and b are relatively prime, and False if they
242 >>> are_relatively_prime(2, 3)
244 >>> are_relatively_prime(2, 4)
252 """Returns a tuple of two different primes of nbits bits"""
261 def extended_euclid_gcd(a
, b
):
262 """Returns a tuple (d, i, j) such that d = gcd(a, b) = ia + jb
270 (d
, k
, l
) = extended_euclid_gcd(b
, q
)
272 return (d
, l
, k
- l
*r
)
274 # Main function: calculate encryption and decryption keys
275 def calculate_keys(p
, q
, nbits
):
276 """Calculates an encryption and a decryption key for p and q, and
277 returns them as a tuple (e, d)"""
280 phi_n
= (p
-1) * (q
-1)
283 # Make sure e has enough bits so we ensure "wrapping" through
285 e
= getprime(max(8, nbits
/2))
286 if are_relatively_prime(e
, n
) and are_relatively_prime(e
, phi_n
): break
288 (d
, i
, j
) = extended_euclid_gcd(e
, phi_n
)
291 raise Exception("e (%d) and phi_n (%d) are not relatively prime" % (e
, phi_n
))
293 if not (e
* i
) % phi_n
== 1:
294 raise Exception("e (%d) and i (%d) are not mult. inv. modulo phi_n (%d)" % (e
, i
, phi_n
))
300 """Generate RSA keys of nbits bits. Returns (p, q, e, d).
302 Note: this can take a long time, depending on the key size.
306 (p
, q
) = find_p_q(nbits
)
307 (e
, d
) = calculate_keys(p
, q
, nbits
)
309 # For some reason, d is sometimes negative. We don't know how
310 # to fix it (yet), so we keep trying until everything is shiny
315 def gen_pubpriv_keys(nbits
):
316 """Generates public and private keys, and returns them as (pub,
319 The public key consists of a dict {e: ..., , n: ....). The private
320 key consists of a dict {d: ...., p: ...., q: ....).
323 (p
, q
, e
, d
) = gen_keys(nbits
)
325 return ( {'e': e
, 'n': p
*q
}, {'d': d
, 'p': p
, 'q': q
} )
327 def encrypt_int(message
, ekey
, n
):
328 """Encrypts a message using encryption key 'ekey', working modulo
331 if type(message
) is types
.IntType
:
332 return encrypt_int(long(message
), ekey
, n
)
334 if not type(message
) is types
.LongType
:
335 raise TypeError("You must pass a long or an int")
338 math
.floor(math
.log(message
, 2)) > math
.floor(math
.log(n
, 2)):
339 raise OverflowError("The message is too long")
341 return fast_exponentiation(message
, ekey
, n
)
343 def decrypt_int(cyphertext
, dkey
, n
):
344 """Decrypts a cypher text using the decryption key 'dkey', working
347 return encrypt_int(cyphertext
, dkey
, n
)
349 def sign_int(message
, dkey
, n
):
350 """Signs 'message' using key 'dkey', working modulo n"""
352 return decrypt_int(message
, dkey
, n
)
354 def verify_int(signed
, ekey
, n
):
355 """verifies 'signed' using key 'ekey', working modulo n"""
357 return encrypt_int(signed
, ekey
, n
)
359 def picklechops(chops
):
360 """Pickles and base64encodes it's argument chops"""
362 value
= zlib
.compress(dumps(chops
))
363 encoded
= base64
.encodestring(value
)
364 return encoded
.strip()
366 def unpicklechops(string
):
367 """base64decodes and unpickes it's argument string into chops"""
369 return loads(zlib
.decompress(base64
.decodestring(string
)))
371 def chopstring(message
, key
, n
, funcref
):
372 """Splits 'message' into chops that are at most as long as n,
373 converts these into integers, and calls funcref(integer, key, n)
376 Used by 'encrypt' and 'sign'.
379 msglen
= len(message
)
381 nbits
= int(math
.floor(math
.log(n
, 2)))
383 blocks
= msglen
/ nbytes
385 if msglen
% nbytes
> 0:
390 for bindex
in range(blocks
):
391 offset
= bindex
* nbytes
392 block
= message
[offset
:offset
+nbytes
]
393 value
= bytes2int(block
)
394 cypher
.append(funcref(value
, key
, n
))
396 return picklechops(cypher
)
398 def gluechops(chops
, key
, n
, funcref
):
399 """Glues chops back together into a string. calls
400 funcref(integer, key, n) for each chop.
402 Used by 'decrypt' and 'verify'.
406 chops
= unpicklechops(chops
)
409 mpart
= funcref(cpart
, key
, n
)
410 message
+= int2bytes(mpart
)
414 def encrypt(message
, key
):
415 """Encrypts a string 'message' with the public key 'key'"""
417 return chopstring(message
, key
['e'], key
['n'], encrypt_int
)
419 def sign(message
, key
):
420 """Signs a string 'message' with the private key 'key'"""
422 return chopstring(message
, key
['d'], key
['p']*key
['q'], decrypt_int
)
424 def decrypt(cypher
, key
):
425 """Decrypts a cypher with the private key 'key'"""
427 return gluechops(cypher
, key
['d'], key
['p']*key
['q'], decrypt_int
)
429 def verify(cypher
, key
):
430 """Verifies a cypher with the public key 'key'"""
432 return gluechops(cypher
, key
['e'], key
['n'], encrypt_int
)
434 # Do doctest if we're not imported
435 if __name__
== "__main__":
439 __all__
= ["gen_pubpriv_keys", "encrypt", "decrypt", "sign", "verify"]