175 lines
4.8 KiB
Python
175 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
|
|
from Cryptotools.Numbers.coprime import phi
|
|
from Cryptotools.Numbers.carmi import carmichael_lambda
|
|
from Cryptotools.Utils.utils import gcd
|
|
from Cryptotools.Numbers.primeNumber import getPrimeNumber
|
|
from sys import getsizeof
|
|
|
|
class RSAKey:
|
|
"""
|
|
This class store the RSA key with the modulus associated
|
|
The key is a tuple of the key and the modulus n
|
|
|
|
Attributes:
|
|
key: It's the exponent key, can be public or private
|
|
modulus: It's the public modulus
|
|
length: It's the key length
|
|
"""
|
|
def __init__(self, key, modulus, length):
|
|
"""
|
|
Contain the RSA Key. An object of RSAKey can be a public key or a private key
|
|
|
|
Args:
|
|
key (Integer): it's the exponent of the key
|
|
modulus (Integer): it's the public modulus of the key
|
|
length (Integer): length of the key
|
|
"""
|
|
|
|
self._key = key
|
|
self._modulus = modulus
|
|
self._length = length
|
|
|
|
@property
|
|
def key(self):
|
|
return self._key
|
|
|
|
@property
|
|
def modulus(self):
|
|
return self._modulus
|
|
|
|
@property
|
|
def length(self):
|
|
return self.length
|
|
|
|
class RSA:
|
|
"""
|
|
This class generate public key based on RSA algorithm
|
|
|
|
Attributes:
|
|
p: it's the prime number for generating the modulus
|
|
q: it's the second prime number for the modulus
|
|
public: Object of the RSAKey which is the public key
|
|
private: Object of the RSAKey for the private key
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""
|
|
Build a RSA Key
|
|
"""
|
|
self._p = None
|
|
self._q = None
|
|
self._public = None
|
|
self._private = None
|
|
|
|
def generateKeys(self, size=512):
|
|
"""
|
|
This function generate both public and private keys
|
|
Args:
|
|
size: It's the size of the key and must be multiple of 64
|
|
"""
|
|
# p and q must be coprime
|
|
self._p = getPrimeNumber(size)
|
|
self._q = getPrimeNumber(size)
|
|
|
|
# compute n = pq
|
|
n = self._p * self._q
|
|
|
|
phin = (self._p - 1) * (self._q - 1)
|
|
|
|
# e must be coprime with phi(n)
|
|
# According to the FIPS 186-5, the public key exponent must be odd
|
|
# and the minimum size is 65536 (Cf. Section 5.4 PKCS #1)
|
|
# https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
|
|
e = 65535 # Works
|
|
for i in range(2, phin - 1):
|
|
if gcd(phin, e) == 1:
|
|
break
|
|
e += 1
|
|
# print(gcd(phin, e))
|
|
self._public = RSAKey(e, n, getsizeof(e))
|
|
|
|
# d is the reverse modulo of phi(n)
|
|
# d = self._inverseModular(e, phin)
|
|
d = pow(e, -1, phin) # Works in python 3.8
|
|
self._private = RSAKey(d, n, getsizeof(d))
|
|
|
|
@property
|
|
def e(self):
|
|
return self._public.key
|
|
|
|
@property
|
|
def d(self):
|
|
return self._private.key
|
|
|
|
@property
|
|
def n(self):
|
|
return self._public.modulus
|
|
|
|
@property
|
|
def p(self):
|
|
return self._p
|
|
|
|
@property
|
|
def q(self):
|
|
return self._q
|
|
|
|
def encrypt(self, data) -> list:
|
|
"""
|
|
This function return a list of data encrypted with the public key
|
|
|
|
Args:
|
|
data (str): it's the plaintext which need to be encrypted
|
|
|
|
Returns:
|
|
return a list of the data encrypted, each entries contains the value encoded
|
|
"""
|
|
dataEncoded = self._str2bin(data)
|
|
return list(
|
|
pow(int(x), self._public.key, self._public.modulus)
|
|
for x in dataEncoded
|
|
)
|
|
|
|
def decrypt(self, data) -> list:
|
|
"""
|
|
This function return a list decrypted with the private key
|
|
|
|
Args:
|
|
data (str): It's the encrypted data which need to be decrypted
|
|
|
|
Returns:
|
|
Return the list of data uncrypted into plaintext
|
|
"""
|
|
decrypted = list()
|
|
for x in data:
|
|
d = pow(x, self._private.key, self._private.modulus)
|
|
decrypted.append(chr(d))
|
|
return ''.join(decrypted)
|
|
|
|
def _str2bin(self, data) -> list:
|
|
"""
|
|
This function convert a string into the unicode value
|
|
|
|
Args:
|
|
data: the string which need to be converted
|
|
|
|
Returns:
|
|
Return a list of unicode values of data
|
|
"""
|
|
return list(ord(x) for x in data)
|
|
|
|
def _inverseModular(self, a, n):
|
|
"""
|
|
This function compute the modular inverse for finding d, the decryption key
|
|
|
|
Args:
|
|
a (Integer): the base of the exponent
|
|
n (Integer): the modulus
|
|
"""
|
|
for b in range(1, n):
|
|
#if pow(a, b, n) == 1:
|
|
if (a * b) % n == 1:
|
|
inv = b
|
|
break
|
|
return inv
|