First commit

This commit is contained in:
geoffrey 2026-01-11 09:19:22 +01:00
commit 50f7b1159e
108 changed files with 11791 additions and 0 deletions

5
.gitignore vendored Normal file

@ -0,0 +1,5 @@
__pycache__/
build/**
Cryptotools.egg-info/**
dist/**
**.swp

@ -0,0 +1,6 @@
Metadata-Version: 2.1
Name: Cryptotools
Version: 1.0
Summary: Cryptography library
Author: Geoffrey Bucchino
Author-email: contact@bucchino.org

@ -0,0 +1,13 @@
README.md
setup.py
Cryptotools/Cryptotools.egg-info/PKG-INFO
Cryptotools/Cryptotools.egg-info/SOURCES.txt
Cryptotools/Cryptotools.egg-info/dependency_links.txt
Cryptotools/Cryptotools.egg-info/top_level.txt
Cryptotools/Numbers/__init__.py
Cryptotools/Numbers/carmi.py
Cryptotools/Numbers/numbers.py
Cryptotools/Numbers/primeNumber.py
tests/test_carmi.py
tests/test_numbers.py
tests/test_phi.py

@ -0,0 +1 @@

@ -0,0 +1 @@
Numbers

@ -0,0 +1,174 @@
#!/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

@ -0,0 +1 @@
#!/usr/bin/env python3

@ -0,0 +1 @@
#!/usr/bin/env python3

@ -0,0 +1,91 @@
#!/usr/bin/env python3
from Cryptotools.Groups.group import Group
class Cyclic(Group):
"""
This object contain a list of the Group for a cyclic group. This class find all generator of the group.
This class is inherited from Group object
Attributes:
G (list): list of all elements in the group
n (Integer): it's the value where the group has been generated
operation (Function): it's the operation generating the group
generators (list): contain all generators of the group
generatorChecked (boolean): Check if generators has been found
"""
def __init__(self, G:list, n, ope):
super().__init__(n, G, ope) # Call the Group's constructor
self._G = G
self._n = n
self._operation = ope
self._generators = list()
self._generatorChecked = False
def generator(self):
"""
This function find all generators in the group G
"""
index = 1
G = sorted(self._g)
for g in range(2, self._n):
z = list()
for entry in range(1, self._n):
res = self._operation(g, index, self._n)
if res not in z:
z.append(res)
index = index + 1
# We check if that match with G
# If yes, we find a generator
if sorted(z) == G:
self._generators.append(g)
self._generatorChecked = True
def getPrimitiveRoot(self):
"""
This function return the primitive root modulo of n
Returns:
Return the primitive root of the group. None if no primitive has been found
"""
index = 1
G = sorted(self._g)
for g in range(2, self._n):
z = list()
for entry in range(1, self._n):
res = self._operation(g, index, self._n)
if res not in z:
z.append(res)
index += 1
# If the group is the same has G, we found a generator
if sorted(z) == G:
return g
return None
def getGenerators(self) -> list:
"""
This function return all generators of that group
Returns:
Return the list of generators found. The function generators() must be called before to call this function
"""
if not self._generatorChecked:
self.generator()
self._generatorChecked = True
return self._generators
def isCyclic(self) -> bool:
"""
Check if the group is a cyclic group, means we have at least one generator
Returns:
REturn a boolean, False if the group is not Cyclic otherwise return True
"""
if len(self.getGenerators()) == 0:
return False
return True

@ -0,0 +1,227 @@
#!/usr/bin/env python3
from Cryptotools.Groups.group import Group
class Galois:
"""
This class contain the Galois Field (Finite Field)
Attributes:
q (Integer): it's the number of the GF
operation (Function): Function for generating the group
identityAdd (Integer): it's the identity element in the GF(n) for the addition operation
identityMul (Integer): it's the identity element in the GF(n) for the multiplicative operation
"""
def __init__(self, q, operation):
self._q = q
self._operation = operation
self._identityAdd = 0
self._identityMul = 1
self._F = [x for x in range(q)]
self._add = [[0 for x in range(q)] for y in range(q)]
# TODO: May do we do a deep copy between all groups ?
self._div = [[0 for x in range(q)] for y in range(q)]
self._mul = [[0 for x in range(q)] for y in range(q)]
self._sub = [[0 for x in range(q)] for y in range(q)]
self._primitiveRoot = list()
def primitiveRoot(self):
"""
In this function, we going to find the primitive root modulo n of the galois field
Returns:
Return the list of primitive root of the GF(q)
"""
for x in range(2, self._q):
z = list()
for entry in range(1, self._q):
res = self._operation(x, entry, self._q)
if res not in z:
z.append(res)
if self.isPrimitiveRoot(z, self._q - 1):
if x not in self._primitiveRoot: # It's dirty, need to find why we have duplicate entry
self._primitiveRoot.append(x)
return z
def getPrimitiveRoot(self):
"""
Return the list of primitives root
Returns:
Return the primitive root
"""
return self._primitiveRoot
def isPrimitiveRoot(self, z, length):
"""
Check if z is a primitive root
Args:
z (list): check if z is a primitive root
length (Integer): Length of the GF(q)
"""
if len(z) == length:
return True
return False
def add(self):
"""
This function do the operation + on the Galois Field
Returns:
Return a list of the group with the addition operation
"""
for x in range(0, self._q):
for y in range(0, self._q):
self._add[x][y] = (x + y) % self._q
return self._add
def _inverseModular(self, a, n):
"""
This function find the reverse modular of a by n
Returns:
Return the reverse modular
"""
for b in range(1, n):
if (a * b) % n == 1:
inv = b
break
return inv
def div(self):
"""
This function do the operation / on the Galois Field
Returns:
Return a list of the group with the division operation
"""
for x in range(1, self._q):
for y in range(1, self._q):
inv = self._inverseModular(y, self._q)
self._div[x][y] = (x * inv) % self._q
return self._div
def mul(self):
"""
This function do the operation * on the Galois Field
Returns:
Return a list of the group with the multiplication operation
"""
for x in range(0, self._q):
for y in range(0, self._q):
self._mul[x][y] = (x * y) % self._q
return self._mul
def sub(self):
"""
This function do the operation - on the Galois Field
Returns:
Return a list of the group with the subtraction operation
"""
for x in range(0, self._q):
for y in range(0, self._q):
self._sub[x][y] = (x - y) % self._q
return self._sub
def check_closure_law(self, arithmetic):
"""
This function check the closure law.
By definition, every element in the GF is an abelian group, which respect the closure law: for a and b belongs to G, a + b belongs to G, the operation is a binary operation
Args:
Arithmetics (str): contain the operation to be made, must be '+', '*', '/' or /-'
"""
if arithmetic not in ['+', '*', '/', '-']:
raise Exception("The arithmetic need to be '+', '*', '/' or '-'")
if arithmetic == '+':
G = self._add
elif arithmetic == '*':
G = self._mul
elif arithmetic == '/':
G = self._div
else:
G = self._sub
start = 0
"""
In case of multiplicative, we bypass the first line, because all elements are zero, otherwise the test fail
"""
if arithmetic == '*' or arithmetic == '/':
start = 1
isClosure = True
for x in range(start, self._q):
gr = Group(self._q, G[x], self._operation)
if not gr.closure():
isClosure = False
del gr
if isClosure:
print(f"The group {arithmetic} respect closure law")
else:
print(f"The group {arithmetic} does not respect closure law")
def check_identity_add(self):
"""
This function check the identity element and must satisfy this condition: $a + 0 = a$ for each element in the GF(n)
In Group Theory, an identity element is an element in the group which do not change the value every element in the group
Returns:
"""
for x in self._F:
if not self._identityAdd + x == x:
raise Exception(
f"The identity element {self._identityAdd} "\
"do not satisfy $a + element = a$"
)
def check_identity_mul(self):
"""
This function check the identity element and must satisfy this condition: $a * 1 = a$ for each element in the GF(n)
In Group Theory, an identity element is an element in the group which do not change the value every element in the group
Returns:
"""
for x in self._F:
if not self._identityMul * x == x:
raise Exception(
f"The identity element {self._identityAdd} "\
"do not satisfy $a * element = a$"
)
def printMatrice(self, m):
"""
This function print the GF(m)
Args:
m (list): Matrix of the GF
"""
header = str()
header = " "
for x in range(0, self._q):
header += f"{x} "
header += "\n--|" + "-" * (len(header)- 3) +"\n"
s = str()
for x in range(0, self._q):
s += f"{x} | "
for y in range(0, self._q):
s += f"{m[x][y]} "
s += "\n"
s = header + s
print(s)

124
Cryptotools/Groups/group.py Normal file

@ -0,0 +1,124 @@
#!/usr/bin/env python3
class Group:
"""
This class generate a group self._g based on the operation (here denoted +)
with the function ope: (a ** b) % n
In group theory, any group has an identity element (e), which with the binary operation, do not change the value and must satisfy the condition: $a + e = 0$
Attributes:
n (Integer): It's the G_n elements in the Group
g (List): The set of the Group
operation (Function): Function for generating the Group
identity (Integer): The identity of the group.
reverse (Dict): For each elements of the Group of n, we have the reverse value
"""
def __init__(self, n, g, ope):
self._n = n
self._g = g
self._operation = ope
self._identity = 0
self._reverse = dict()
def getG(self) -> list():
"""
This function return the Group
Returns:
List of all elements in the Group
"""
return self._g
def closure(self) -> bool:
"""
Check the closure law
In a group, each element a, b belongs to G, such as a + b belongs to G
Returns:
Return a Boolean if the closure law is respected. True if yes otherwise it's False
"""
for e1 in self._g:
for e2 in self._g:
res = self._operation(e1, e2, self._n)
if not res in self._g:
# raise Exception(f"{res} not in g. g is not a group")
return False
return True
def associative(self) -> bool:
"""
Check the associative law.
In a group, for any a, b and c belongs to G,
they must respect this condition: (a + b) + c = a + (a + b)
Returns:
Return a boolean if the Associative law is respected. True if yes otherwise it's False
"""
a = self._g[0]
b = self._g[1]
c = self._g[2]
res_ope = self._operation(a, b, self._n)
res1 = self._operation(res_ope, c, self._n)
res_ope = self._operation(b, c, self._n)
res2 = self._operation(a, res_ope, self._n)
if res1 != res2:
# raise Exception(f"{res1} is different from {res2}. g is not a group")
return False
return True
def identity(self) -> bool:
"""
Check the identity law.
In a group, an identity element exist and must be uniq
Returns:
Return a Boolean if the identity elements has been found. True if found otherwise it's False
"""
for a in self._g:
for b in self._g:
if not self._operation(a, b, self._n) == b:
break
self._identity = a
return True
return False
def getIdentity(self) -> int:
"""
Return the identity element. The function identitu() must be called before.
Returns:
Return the identity element if it has been found
"""
return self._identity
def reverse(self) -> bool:
"""
Check the inverse law
In a group, for each element belongs to G
they must have an inverse a ^ (-1) = e (identity)
Returns:
Return a Boolean if the all elements ha a reverse element. True if yes otherwise it's False
"""
reverse = False
for a in self._g:
for b in self._g:
if self._operation(a, b, self._n) == self._identity:
self._reverse[a] = b
reverse = True
break
return reverse
def getReverses(self) -> dict:
"""
This function return the dictionary of all reverses elements. The key is the element in G and the value is the reverse element
Returns:
Return the reverse dictionary
"""
return self._reverse

@ -0,0 +1 @@
#!/usr/bin/env python3

Binary file not shown.

Binary file not shown.

@ -0,0 +1,177 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import gcd, isPrimeNumber
from Cryptotools.lcm import lcm
from Cryptotools.Numbers.coprime import phi
from Cryptotools.Utils.utils import gcd
from sympy import factorint
from functools import reduce
def carmichael_lambda(n: int) -> int:
"""
This function is a carmichael lambda for identifying the smallest integer m
and saisfy this condition: a ** m congrue 1 modulo n
This function is relatively closed with the euler's totient (phi of n)
Args:
n (Integer): found the smallest integer of n
Returns:
REturn the smallest integer of n
"""
# First, factorizing n number
# factorint return a list of prime factors of n
# Base on that theorem:
# https://en.wikipedia.org/wiki/Fundamental_theorem_of_arithmetic
factorsN = factorint(n)
"""
The result of the factorint, we have the following:
n = p ** e1, p ** e2, ..., p ** ek
"""
factors = list()
for p, e in factorsN.items():
# Base on the theorem of arithmetic, p is always prime
if isPrimeNumber(p):
if p == 2 and e >= 3:
factors.append(phi(pow(p, e)) // 2)
elif p >= 2 and e > 0:
factors.append(phi(pow(p, e)))
elif p > 2:
factors.append(phi(pow(p, e)))
# Now, we can compute lcm
result = reduce(lcm, factors)
return result
def carmichael_lambda2(n):
"""
Deprecated function
"""
# Get all coprimes with n
coprimes = list()
for a in range(1, n):
if gcd(a, n) == 1:
coprimes.append(a)
# Need to find the smallest value
"""
Need to find the smallest value m. Must to satisfy this condition:
a ** m congrus 1 mod n
"""
for m in range(1, n):
print(f"{m} {a ** m % n}")
print(coprimes)
def carmi_numbers(n):
"""
This function get all GCD of the number if these number are prime or not
Args:
n (Integer): Iterate to n elements
Returns:
Return a list of prime numbers
"""
# https://kconrad.math.uconn.edu/blurbs/ugradnumthy/carmichaelkorselt.pdf
primes = list()
for i in range(2, n - 1):
if gcd(n, i) == i:
if isPrimeNumber(i):
primes.append(i)
return primes
def is_carmichael(n, primes):
"""
This function check if the n number is a carmichael number. The arguments primes at least 3 prime numbers
As it's said in the Carmichael theorem, a carmichael number has three factors and they are all primes: https://en.wikipedia.org/wiki/Carmichael_number
With the Korselt's criterion, to check if the number is a carmichael number p - 1 / n - 1.
Args:
n (Integer): the carmichael number
primes (list): list of prime numbers
Returns:
Boolean of the carmichael's number result
"""
r = True
n = n - 1
if len(primes) < 3:
return False
# Korselt's criterion
for p in primes:
p = p - 1
if n % p != 0:
r = False
break
return r
def is_carmi_number(n) -> bool:
"""
This function check if the number n is a carmichael number (pseudoprime)
Args:
n (Integer): Iterate to n elements
Returns:
Return a Boolean if n is a carmichael number or not. True if yes
"""
j = 0
for i in range(n):
if i ** n % n == i:
j += 1
if j == n:
return True
return False
def generate_carmi_numbers(nbr) -> list:
"""
This function generate carmichael numbers, they are called pseudoprimes
For instance: a = 545, n = 561
gcd(a, n) = 1
pow(a, n - 1) % n = 1
Args:
nbr (Integer): Find all pseudoprimes until nbr is achieves
Returns:
Return the list of pseudoprimes
"""
carmi = list()
count = 0
n = 2
while count < nbr:
# First, we need to find a, coprime with n
for a in range(1, n):
# We check if n is coprime with a
# All integers must be coprime with n, a belong to n
if gcd(a, n) == 1:
# Check if is a carmichael number
# Fermat's little theorem, a ** (n - 1) % n, must be congruent to 1
if pow(a, (n - 1)) % n == 1:
#if (a ** (n - 1)) % n == 1:
#print(f"{gcd(a, n)} {a} {n}")
if n not in carmi:
count += 1
carmi.append(n)
else:
print(f"{gcd(a, n)} {a} {n}")
break
n += 1
print(carmi)
#for cop in range(2, n):
# if gcd(cop, n) == 1:
# coprimes.append(cop)
return carmi

@ -0,0 +1,22 @@
#!/usr/bin/env python3
from Cryptotools.Utils.utils import gcd
# https://oeis.org/A000010
def phi(n):
"""
This function count all phi(n)
Args:
n (integer): it's the phi(n) value
Returns:
Return the phi(n)
"""
y = 1
for i in range(2, n):
if gcd(n, i) == 1:
y += 1
return y

@ -0,0 +1,56 @@
#!/usr/bin/env python3
from random import randint
from Cryptotools.Numbers.primeNumber import _millerRabinTest, isPrimeNumber
from Cryptotools.Utils.utils import gcd
from Cryptotools.lcm import lcm
from math import floor, log
def pollard_p_minus_1(n, B=None) -> int:
"""
This function factorize the number n into factor based on the Pollard's p - 1 algorithm
The first is to choose B, which is a positive integer and B < n
In the second step, we need to define $M=\prod _{primes~q\leq B}q^{\lfloor \log_{q}{B}\rfloor }$
Args:
n (Integer): The number n to factorize
Returns:
Return the factorize of the number n or None
"""
if B is None:
B = randint(1, n - 1)
# B = randint(1, n - 1)
#### We define M
# Select all prime numbers 1 < B
q = list()
for x in range(2, B):
# with the _millerRabinTest, the program crash, because the randint() is empty
# because, both min value and max value are 2
# if _millerRabinTest(x):
if isPrimeNumber(x):
q.append(x)
M = 1
for prime in q:
e = floor(log(B, prime))
# print(prime, e)
M *= pow(prime, e)
# We choose a and coprime with n
a = 2
while True:
if gcd(a, n) == 1:
break
a += 1
# We can compute g = gcd((a ** M) - 1, n)
g = gcd(pow(a, M, n) - 1, n)
if g > 1:
return g
return None

@ -0,0 +1,19 @@
#!/usr/bin/env python3
def fibonacci(n) -> list:
"""
This function generate the list of Fibonacci
Args:
n (integer): it's maximum value of Fibonacci sequence
Returns:
Return a list of n element in the Fibonacci sequence
"""
fibo = [0, 1]
fibo.append(fibo[0] + fibo[1])
for i in range(2, n):
fibo.append(fibo[i - 1] + fibo[i])
return fibo

@ -0,0 +1,288 @@
#!/usr/bin/env python3
from random import randint, seed, getrandbits
from math import log2
from Cryptotools.Utils.utils import gcd
def isPrimeNumber(p):
"""
Check if the number p is a prime number or not. The function iterate until p is achieve.
This function is not the efficient way to determine if p is prime or a composite.
To identify if p is prime or not, the function check the result of the Euclidean Division has a remainder. If yes, it's means it's not a prime number
Args:
p (Integer): number if possible prime or not
Returns:
Return a boolean if the number p is a prime number or not. True if yes
"""
for i in range(2, p):
if p % i == 0:
return False
return True
# https://people.csail.mit.edu/rivest/Rsapaper.pdf
# https://arxiv.org/pdf/1912.11546
# https://link.springer.com/content/pdf/10.1007/3-540-44499-8_27.pdf
# https://link.springer.com/article/10.1007/BF00202269
# https://www.geeksforgeeks.org/dsa/how-to-generate-large-prime-numbers-for-rsa-algorithm/
# https://crypto.stackexchange.com/questions/20548/generation-of-strong-primes
# https://crypto.stackexchange.com/questions/71/how-can-i-generate-large-prime-numbers-for-rsa
def getPrimeNumber(n, safe=True):
"""
This function generate a large prime number
based on "A method for Obtaining Digital Signatures
and Public-Key Cryptosystems"
Section B. How to Find Large Prime Numbers
https://dl.acm.org/doi/pdf/10.1145/359340.359342
Args:
n (Integer): The size of the prime number. Must be a multiple of 64
safe (Boolean): When generating the prime number, the function must find a safe prime number, based on the Germain primes (2p + 1 is also a prime number)
Returns:
Return the prime number
"""
if n % 64 != 0:
print("Must be multiple of 64")
return
# from sys import getsizeof
upper = getrandbits(n)
lower = upper >> 7
r = randint(lower, upper)
while r % 2 == 0:
r += 1
# Now, we are going to compute r as prime number
i = 100
while 1:
# Check if it's a prime number
if _millerRabinTest(r):
break
# TODO: it's dirty, need to change that
# i = int(log2(r))
# i *= randint(2, 50)
r += i
# print(f"{i} {r}")
i += 1
# print(_fermatLittleTheorem(r))
# print(getsizeof(r))
return r
def getSmallPrimeNumber(n) -> int:
"""
This function is deprecated
Args:
n (Integer): Get the small prime number until n
Returns:
Return the first prime number found
"""
is_prime = True
while True:
for i in range(2, n):
# If n is divisible by i, it's not a prime, we break the loop
if n % i == 0:
is_prime = False
break
if is_prime:
break
is_prime = True
n = n + 1
p = n
return p
def get_prime_numbers(n) -> list:
"""
This function get all prime number of the n
Args:
n (Integer): find all prime number until n is achieves
Returns:
Return a list of prime numbers
"""
l = list()
for i in range(2, n):
if n % i == 0:
l.append(i)
return l
def get_n_prime_numbers(n) -> list:
"""
This function return a list of n prime numbers
Args:
n (Integer): the range, must be an integer
Returns:
Return a list of n prime numbers
"""
l = list()
count = 2
index = 0
while index < n:
is_prime = True
for x in range(2, count):
if count % x == 0:
is_prime = False
break
if is_prime:
l.append(count)
index += 1
count += 1
return l
def are_coprime(p1, p2):
"""
This function check if p1 and p2 are coprime
Args:
p1 (list): list of prime numbers of the first number
p2 (list): list of prime number of the second number
Returns:
Return a boolean result
"""
r = True
for entry in p1:
if entry in p2:
r = False
break
return r
def sieveOfEratosthenes(n) -> list:
"""
This function build a list of prime number based on the Sieve of Erastosthenes
Args:
n (Integer): Interate until n is achives
Returns:
Return a list of all prime numbers to n
"""
if n < 1:
return list()
eratost = dict()
for i in range(2, n):
eratost[i] = True
for i in range(2, n):
if eratost[i]:
for j in range(i*i, n, i):
eratost[j] = False
sieve = list()
for i in range(2, n):
if eratost[i]:
sieve.append(i)
return sieve
def _fermatLittleTheorem(n) -> bool:
"""
The Fermat's little theorem. if n is a prime number, any number from 0 to n- 1 is a multiple of n
Args:
n (Integer): Check if n is prime or not
Returns:
Return True if the number a is a multiple of n, otherwise it's False
"""
a = randint(1, n - 1)
# We compute a ** (n - 1) % n
if pow(a, n - 1, n) == 1:
return True
return False
def _millerRabinTest(n) -> bool:
"""
This function execute a Miller Rabin test
For the algorithm, it's based on the pseudo-algo provided by this document:
* https://www.cs.cornell.edu/courses/cs4820/2010sp/handouts/MillerRabin.pdf
The Mille-Rabin test is an efficient way to determine if n is prime or not
Args:
n (Integer): Check if n is a prime number
Returns:
Return a boolean. True for a prime otherwise, it's a composite number
"""
if n < 2 or (n > 2 and n % 2 == 0): # If n is even, it's a composite
return False
k = 0
q = n - 1
#while (q & 1) == 0:
# k += 1
# q >>= 1
while q % 2 == 0:
k += 1
q //= 2
# We choose a: a < n - 1
for _ in range(40):
a = randint(2, n - 1)
# We compute a ** q % n
x = pow(a, q, n)
# If it's a composite number
if x == 1 or x == n - 1:
continue
for _ in range(k):
z = pow(x, 2, n)
if z == 1 or z == n - 1:
return False
else:
return False
return True
def sophieGermainPrime(p) -> bool:
"""
Check if the number p is a safe prime number: 2p + 1 is also a prime
Args:
p (Integer): Possible prime number
Returns:
Return True if p is a safe prime number, otherwise it's False
"""
pp = 2 * p + 1
return _millerRabinTest(pp)
def isSafePrime(n) -> bool:
"""
This function has not been implemented yet, but check if the number n is a safe prime number. This function will test different properties of the possible prime number n
Args:
n (Integer): the prime number to check
Returns:
Return a Boolean if the prime number n is safe or not. True if yes, otherwise it's False
"""
if n.bit_length() >= 256:
return True
# Do Sophie Germain's test
return False

@ -0,0 +1 @@
#!/usr/bin/env python3

@ -0,0 +1,9 @@
#!/usr/bin/env python3
COMPOSITE = 0
PRIME = 1
class Number:
def __init__(self):
self._int = int()
self._kind = COMPOSITE

@ -0,0 +1,34 @@
#!/usr/bin/env python3
def gcd(a, b):
"""
This function calculate the GCD (Greatest Common Divisor of the number a of b
Args:
a (Integer): the number a
b (integer): the number b
Return:
the GCD
"""
if b == 0:
return a
return gcd(b, a%b)
def egcd(a, b):
"""
This function compute the Extended Euclidean algorithm
https://user.eng.umd.edu/~danadach/Cryptography_20/ExtEuclAlg.pdf
https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
Args:
a (Integer): the number a
b (Integer): the number b
"""
if a == 0:
return b, 0, 1
gcd, x1, y1 = egcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return gcd, x, y

3
Cryptotools/__init__.py Normal file

@ -0,0 +1,3 @@
#!/usr/bin/env python3
__all__ = ["Numbers", "Groups"]

33
Cryptotools/lcm.py Normal file

@ -0,0 +1,33 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import gcd
def compute_multiple(a):
"""
This function compute the 20 first multiples of the number a
Args:
a (Integer): the number
Return:
list of multiple of a
"""
r = list()
for i in range(1, 20):
r.append(a * i)
return r
def lcm(a, b):
"""
This function get the LCM (Least Common Multiple) a of b
Args:
a (Integer): the number
b (Integer): the number
Return:
the LCM
"""
return (b // gcd(a, b)) * a

31
README.md Normal file

@ -0,0 +1,31 @@
# Introduction
This project contains the module *cryptotools* which can used for cryptography
# Install the program
```
$ virtualenv ~/venv/myenv
$ source ~/venv/myenv/bin/activate
$ python3 setup.py install
```
## Examples
In the directory *examples/*, you have different python files for using the module
## Unitests
### Test phi
```
$ python3 tests/test_phi.py -v
```
### Test Fibonacci
For testing Fibonacci sequence, I generate a list from OEIS wich contains 40 first numbers of Fibonacci. The `test_numbers.py` test the Fibonacci sequence generated from the functions `fibonacci` in `utils/numbers.py`:
```
$ python3 tests/test_numbers.py -v
```
# Build the doc
```
$ mkdocs build
```

27
docs/examples-rsa-keys.md Normal file

@ -0,0 +1,27 @@
# Generating RSA Keys
In the following section, we are going to see how to generate RSA Keys and how to encrypt data with these keys.
```
#!/usr/bin/env python3
from Cryptotools.Encryptions.RSA import RSA
rsa = RSA()
rsa.generateKeys(size=512)
e = rsa.e
d = rsa.d
n = rsa.n
s = "I am encrypted with RSA"
print(f"plaintext: {s}")
encrypted = rsa.encrypt(s)
# Encrypt data
print(f"ciphertext: {encrypted}")
# We decrypt
plaintext = rsa.decrypt(encrypted)
print(f"Plaintext: {plaintext}")
```

9
docs/group-theory.md Normal file

@ -0,0 +1,9 @@
# Group Theory
## Group
::: Cryptotools.Groups.group
## Cyclic group
::: Cryptotools.Groups.cyclic
## Galois Field (Finite Field)
::: Cryptotools.Groups.galois

13
docs/index.md Normal file

@ -0,0 +1,13 @@
# Welcome to CryptoTools
* [Introduction](/introduction)
* [Installation](/installation)
* Low-Level Cryptographic
* [Number Theory](/number-theory)
* [Group Theory](/group-theory)
* Public Keys:
* [RSA](/rsa)
* Examples:
* [Generating RSA keys](/examples-rsa-keys)

18
docs/installation.md Normal file

@ -0,0 +1,18 @@
# Installation
To install the project, you should install from my own Python repository but, you first need to deploy your virtual enviroment.
## Installation from source
You can install from the source. Download the [project](https://gitea.bucchino.org/gbucchino/cryptotools.git) and install it in your virtual environment:
```
$ virtualenv ~/venv/cryptotools
$ source ~/venv/cryptotools/bin/activate
```
```
$ git clone https://gitea.bucchino.org/gbucchino/cryptotools.git
$ cd cryptotools
$ python3 setup.py install
```
The installation is completed. You can know use Cryptotools package into your project. In the directory `examples` you may find some examples scripts

5
docs/introduction.md Normal file

@ -0,0 +1,5 @@
# CryptoTools
CryptoTools is a Python package that provides low-level cryptographic primitives for generating strong numbers. With this project, it's possible to generate public key cryptosystems such as RSA.
This project has a academic purpose and can not be used in production enviroment yet.
So far, my cryptographic modules are not compliant with [FIPS 140-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-3.pdf) but in the future, that will be.

9
docs/number-theory.md Normal file

@ -0,0 +1,9 @@
# Number Theory
For generating keys, we need strong prime number, they are the basis. CryptoTools provides functions for generating these numbers.
## prime numbers
::: Cryptotools.Numbers.primeNumber
## Fibonacci sequence
::: Cryptotools.Numbers.numbers

3
docs/rsa.md Normal file

@ -0,0 +1,3 @@
CryptoTools provides several functions for generating a RSA Keys
::: Cryptotools.Encryptions.RSA

32
examples/carmi.py Normal file

@ -0,0 +1,32 @@
#!/usr/bin/env python3
from Cryptotools.Utils.utils import gcd
def carmi_first_method(n) -> int:
coprimes = list()
for i in range(1, n):
if gcd(i, n) == 1:
coprimes.append(i)
print(coprimes)
smallest = list()
for m in range(1, n):
l = 0
for a in coprimes:
if a ** m % n == 1:
l += 1
if l == len(coprimes):
smallest.append(m)
#print(smallest)
return min(smallest)
print(f"lambda(12) = {carmi_first_method(12)}")
print(f"lambda(19) = {carmi_first_method(19)}")
#print(f"lambda(28) = {carmi_first_method(28)}")
#print(f"lambda(32) = {carmi_first_method(32)}")
#print(f"lambda(33) = {carmi_first_method(33)}")
#print(f"lambda(35) = {carmi_first_method(35)}")
#print(f"lambda(36) = {carmi_first_method(36)}")
#print(f"lambda(135) = {carmi_first_method(135)}")
#print(f"lambda(1200) = {carmi_first_method(1200)}")

23
examples/coprime.py Normal file

@ -0,0 +1,23 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.coprime import phi
from Cryptotools.lcm import lcm
from Cryptotools.Numbers.carmi import carmi_numbers, is_carmichael, carmichael_lambda
print(f"phi(19) = {phi(19)}")
print("Carmichael's number")
l = carmi_numbers(561)
print(is_carmichael(561, l))
# Test Carmichael lambda
print("Carmichael")
print(f"12 {carmichael_lambda(12)}")
print(f"19 {carmichael_lambda(19)}")
print(f"28 {carmichael_lambda(28)}")
print(f"32 {carmichael_lambda(32)}")
print(f"33 {carmichael_lambda(33)}")
print(f"35 {carmichael_lambda(35)}")
print(f"36 {carmichael_lambda(36)}")
print(f"135 {carmichael_lambda(135)}")
print(f"1200 {carmichael_lambda(1200)}")

41
examples/cyclic.py Normal file

@ -0,0 +1,41 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import isPrimeNumber
from random import choice
def operation(a, b, n):
return (a ** b) % n
n = 19
g = list()
for i in range(1, n):
g.append(i)
print(f"n = {n}")
print(f"G = {g}")
cyclic = Cyclic(g, n, operation)
order = len(g) # Length of the group
print(f"len: {order}")
print(f"prime: {isPrimeNumber(order)}")
cyclic.generator()
print(f"All generators: {cyclic.getGenerators()}")
print(f"Is cyclic: {cyclic.isCyclic()}")
# Check if the abelian group is respected
print(f"It is an abelian group: {cyclic.closure()}\n")
e = choice(cyclic.getGenerators())
z = list()
for a in range(1, n):
res = operation(e, a, n)
z.append(res)
print(z)
if z == g:
print(f"The group generated with the generator {e} works")

64
examples/cyclic_dlp.py Normal file

@ -0,0 +1,64 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import getPrimeNumber
from random import randint, choice
from math import log, log10, log2
"""
Here, we will try to understand why we need to have a generator when we encrypt data for Diffie-Hellman
https://crypto.stackexchange.com/questions/25489/why-does-diffie-hellman-need-be-a-cyclic-group
"""
def operation(a, b, n):
return (a ** b) % n
def getGenerator(gr, p):
index = 1
for g in range(2, p):
z = list()
for entry in range(1, p):
res = operation(g, index, p)
#if res not in z:
z.append(res)
index = index + 1
print(f"{g}: {sorted(z)}")
def generateGroupByG(gr, p, g):
index = 1
z = list()
for entry in range(1, p):
res = operation(g, index, p)
#if res not in z:
z.append(res)
index = index + 1
return z
def computePublicKey(key, p, g):
return (g ** key) % p
gr = list()
# Public value
p = 5
g = 0
for i in range(1, p):
gr.append(i)
print(f"p = {p}")
print(f"G = {gr}")
# We try with a generator which is not in list
cyclic = Cyclic(gr, p, operation)
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
# Generate group with g = 2
grWithG = generateGroupByG(gr, p, 2)
print(f"Group generated with g = 2: {grWithG}")
for a in grWithG:
# print(f"log2({a}) = {log(a, 2)}") # Same as below
print(f"log2({a}) = {log2(a)}")
print()
for a in range(1, len(grWithG) + 1):
print(f"log2({a}) = {log2(a)}")

@ -0,0 +1,32 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from random import choice
def operation(a, b, n):
return (a ** b) % n
n = 19
g = list()
for i in range(1, n):
g.append(i)
print(f"n = {n}")
print(f"G = {g}")
cyclic = Cyclic(g, n, operation)
cyclic.generator()
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
e = choice(generators)
z = list()
for a in range(1, n):
res = operation(e, a, n)
z.append(res)
z = sorted(z)
if z == g:
print(f"Working with the generator {e}")

@ -0,0 +1,49 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import getPrimeNumber
from random import randint, choice
from math import log, log10
"""
Here, we will try to understand why we need to have a generator when we encrypt data for Diffie-Hellman
https://crypto.stackexchange.com/questions/25489/why-does-diffie-hellman-need-be-a-cyclic-group
"""
def operation(a, b, n):
return (a ** b) % n
def getGenerator(gr, p):
cyclic = Cyclic(gr, p, operation)
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
cyclic.identity()
print(f"Identity: {cyclic.getIdentity()}")
return generators
gr = list()
# Public value
p = 13
g = 0
for i in range(1, p):
gr.append(i)
print(f"p = {p}")
print(f"G = {gr}")
# We try with a generator which is not in list
generators = getGenerator(gr, p)
g = 3 # In the group
#g = # Not in the group
#print(f"g = {g}")
# Try to compute the cyclic subgroup
for G in range(p + 1):
res = 0
for a in range(G):
r = operation(G, a, p)
res = res + r
if res == p:
print(f"G = {G}; res = {res}")

73
examples/cyclic_test.py Normal file

@ -0,0 +1,73 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Utils.utils import gcd
from Cryptotools.Numbers.primeNumber import isPrimeNumber
from random import choice
def operation(a, b, n):
return (a ** b) % n
def test1(n):
"""
We test with n is not prime but the order of the group is a prime number
"""
g = list()
g2 = list()
for i in range(1, n):
#if gcd(i, n) == 1:
g.append(i)
print(f"n = {n}")
print(f"G = {g}")
Gsorted = sorted(g)
cyclic = Cyclic(g, n, operation)
order = len(g) # https://en.wikipedia.org/wiki/Order_(group_theory)
print(f"len: {order}")
print(f"prime: {isPrimeNumber(order)}")
g2 = list()
for i in range(1, order):
if gcd(i, order) == 1:
g2.append(i)
pass
print(g2)
# Pick a number in the previous list and check if we can generate all number with it
item = choice(g2)
print()
# if the order is prime, the group is cyclic ?
# Check if we have all items
g3 = list()
for i in range(1, n):
res = operation(i, item, n)
if gcd(res, item) == 1:
g3.append(res)
#print(res)
pass
G2sorted = sorted(g2)
G3sorted = sorted(g3)
print()
# print(f"{g} = {cyclic.generator(g)}")
gen = cyclic.generator()
print(f"All generators: {cyclic.getGenerators()}")
print(f"Is cyclic: {cyclic.isCyclic()}")
print()
print(G2sorted)
print(G3sorted)
if G3sorted == Gsorted:
print(f"Matching with item {item}") # Always match with item 1
# Check if the abelian group is respected
print(f"It is an abelian group: {cyclic.closure()}\n")
test1(19)
test1(12)

74
examples/dh_cyclic.py Normal file

@ -0,0 +1,74 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import getPrimeNumber
from random import randint, choice
from math import log, log10
"""
Here, we will try to understand why we need to have a generator when we encrypt data for Diffie-Hellman
https://crypto.stackexchange.com/questions/25489/why-does-diffie-hellman-need-be-a-cyclic-group
"""
def operation(a, b, n):
return (a ** b) % n
def getGenerator(gr, p):
cyclic = Cyclic(gr, p, operation)
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
# Test with a no generator
item = 2
while item in generators: # we loop until we found an item which is not a generators of the group
item = randint(1, p)
return item
def computePublicKey(key, p, g):
return (g ** key) % p
def computeEphemeralKey(public, secret, p):
return (public ** secret) % p
gr = list()
# Public value
#p = getPrimeNumber(n = 8)
#p = 257
p = 19
g = 0
for i in range(1, p):
gr.append(i)
print(f"p = {p}")
print(f"G = {gr}")
# We try with a generator which is not in list
g = getGenerator(gr, p)
#g = [3, 5, 6, 7, 10, 12, 14, 19, 20, 24, 27, 28, 33, 37, 38, 39, 40, 41, 43, 45, 47, 48, 51, 53, 54, 55, 56, 63, 65, 66, 69, 71, 74, 75, 76, 77, 78, 80, 82, 83, 85, 86, 87, 90, 91, 93, 94, 96, 97, 101, 102, 103, 105, 106, 107, 108, 109, 110, 112, 115, 119, 125, 126, 127, 130, 131, 132, 138, 142, 145, 147, 148, 149, 150, 151, 152, 154, 155, 156, 160, 161, 163, 164, 166, 167, 170, 171, 172, 174, 175, 177, 179, 180, 181, 182, 183, 186, 188, 191, 192, 194, 201, 202, 203, 204, 206, 209, 210, 212, 214, 216, 217, 218, 219, 220, 224, 229, 230, 233, 237, 238, 243, 245, 247, 250, 251, 252, 254]
g = 29 # Not in the group
print(f"g = {g}")
# We can compute with the secret key
secretKeyA = 5
secretKeyB = 10
publicKeyA = computePublicKey(secretKeyA, p, g)
publicKeyB = computePublicKey(secretKeyB, p, g)
print(f"Public key A: {publicKeyA}")
print(f"Public key B: {publicKeyB}")
# Eve sniff the traffic and knows p, g and publicKeyA and B
# Generator need to be use, because that avoid to Eve to try to find a secret key of Alice or Bob ???
# Utiliser un generateur qui genere la tout le groupe, va permettre d'éviter à Eve de trouver la secret key de Alice ou Bob ????
# https://eitca.org/cybersecurity/eitc-is-acc-advanced-classical-cryptography/diffie-hellman-cryptosystem/diffie-hellman-key-exchange-and-the-discrete-log-problem/examination-review-diffie-hellman-key-exchange-and-the-discrete-log-problem/what-are-the-roles-of-the-prime-number-p-and-the-generator-alpha-in-the-diffie-hellman-key-exchange-process/
# https://www.perplexity.ai/search/why-generator-in-cyclic-group-QRYR6.rxSI218hs_x5CvnQ#0
# They exchange their public keys
ephemeralKeyA = computeEphemeralKey(publicKeyB, secretKeyA, p)
ephemeralKeyB = computeEphemeralKey(publicKeyA, secretKeyB, p)
print(f"Ephemeral key A: {ephemeralKeyA}")
print(f"Ephemeral key B: {ephemeralKeyB}")
# Test log10
#for i in range(1, 1000):
# r = log10(i)
# if isinstance(r, int):
# print(f"{i} = {r}")

116
examples/dh_no_generator.py Normal file

@ -0,0 +1,116 @@
#!/usr/bin/env python3
from Cryptotools.Groups.cyclic import Cyclic
from Cryptotools.Numbers.primeNumber import getPrimeNumber
from random import randint, choice
from math import log, log10
"""
Here, we will try to understand why we need to have a generator when we encrypt data for Diffie-Hellman
https://crypto.stackexchange.com/questions/25489/why-does-diffie-hellman-need-be-a-cyclic-group
"""
def operation(a, b, n):
return (a ** b) % n
def getGenerator(gr, p):
index = 1
for g in range(2, p):
z = list()
for entry in range(1, p):
res = operation(g, index, p)
#if res not in z:
z.append(res)
index = index + 1
print(f"{g}: {sorted(z)}")
def getGenerator2(gr, p, g):
index = 1
z = list()
for entry in range(1, p):
res = operation(g, index, p)
if res not in z:
z.append(res)
index = index + 1
return z
def computePublicKey(key, p, g):
return (g ** key) % p
def computeEphemeralKey(public, secret, p):
return (public ** secret) % p
gr = list()
# Public value
p = 43
g = 0
for i in range(1, p):
gr.append(i)
print(f"p = {p}")
print(f"G = {gr}")
# We try with a generator which is not in list
cyclic = Cyclic(gr, p, operation)
generators = cyclic.getGenerators()
print(f"All generators: {generators}")
g = 3 # In the group
print(f"g = {g}")
# We can compute with the secret key
secretKeyA = 5
secretKeyB = 10
publicKeyA = computePublicKey(secretKeyA, p, g)
publicKeyB = computePublicKey(secretKeyB, p, g)
print(f"Public key A: {publicKeyA}")
print(f"Public key B: {publicKeyB}\n")
# Here, g is in the generator, we need to compute all values until that match with publicKeyA
for a in range(1, p):
res = operation(g, a, p)
if res == publicKeyA:
print(f"Brute forced secret key of A: {a}")
for a in range(1, p):
res = operation(g, a, p)
if res == publicKeyB:
print(f"Brute forced secret key of B: {a}")
print()
#for a in generators:
# print(a)
#
#print()
# Here, we generate all key withthe same generator
keys = list()
for a in range(1, p):
keys.append(operation(g, a, p))
print((keys))
print(sorted(keys))
print()
print(f"Keys with g = 4: {sorted(getGenerator2(gr, p, 4))}")
# Do the same, but g is not a generator
g = 4 # Not in the generator group
publicKeyA = computePublicKey(secretKeyA, p, g)
publicKeyB = computePublicKey(secretKeyB, p, g)
print(f"Public key A: {publicKeyA}")
print(f"Public key B: {publicKeyB}")
keys = list()
for a in range(1, p):
keys.append(operation(g, a, p))
print(keys)
# Eve sniff the traffic and knows p, g and publicKeyA and B
# Eve, knows p and g, because it's public
# Eve need to guess the secretKey of A.
# For doing that, we iterate all posibility until that match with the publicKeyA
#for a in range(1, 4):
# res = operation(g, a, p)
# print(res)

@ -0,0 +1,80 @@
#!/usr/bin/env python3
import unittest
from Cryptotools.Numbers.primeNumber import isPrimeNumber, _millerRabinTest, getPrimeNumber
from math import sqrt, isqrt, ceil
from sympy import sqrt as sq
def get_closest_prime(p):
q = p + 1
l = list()
while True:
if _millerRabinTest(q):
l.append(q)
if len(l) == 20:
break
q += 1
return l
def test():
while True:
p = getPrimeNumber(64)
b = sqrt(p)
if b % 2 == 0.0:
break
print(p)
#test()
#exit(1)
p = 7901
q = 7817
#p = getPrimeNumber(64)
#q = get_closest_prime(p)[1]
p = 7943202761666983 # Works
q = 7943202761667119
#p = 314159200000000028138418196395985880850000485810513
#q = 314159200000000028138415196395985880850000485810479
print(f"p = {p}")
print(f"q = {q}")
n = p * q
print(f"n = {n}")
a = ceil(sqrt(n))
#print(a)
#print(sqrt(n))
#print(sqrt(n) < n) # True
#print(a * a)
#print(a * a < n)
#print()
#a = isqrt(n) + 1
iteration = 0
while True:
# b2 = (a ** 2) - n
iteration += 1
b2 = pow(a, 2) - n
#b2 = ceil(a*a) - n
# print(b2)
sqb2 = ceil(sqrt(b2))
# print(b2, isqrt(pow(b2, 2)))
if b2 % 2 == 0.0:
#if isqrt(pow(b2, 2)) == b2:
b = isqrt(b2)
break
a = a + 1
print(f"Iteration: {iteration}")
print(f"a = {a}")
print(f"b2 = {b2}")
print(f"b = {b}")
p = int((a + b))
q = int((a - b))
print(p)
print(q)
#N = (a + b) * (a - b)
N = p * q
print(_millerRabinTest(p))
print(_millerRabinTest(q))
print(f"N = {N}")
print(n == N)
print()

5
examples/fibonacci.py Normal file

@ -0,0 +1,5 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.numbers import fibonacci
print(fibonacci(40))

36
examples/galois.py Normal file

@ -0,0 +1,36 @@
#!/usr/bin/env python3
from Cryptotools.Groups.galois import Galois
import matplotlib.pyplot as plt # pip install numpy==1.26.4
def operation(a, b, n):
return (a ** b) % n
q = 13
g = Galois(q, operation)
add = g.add()
div = g.div()
mul = g.mul()
sub = g.sub()
g.check_closure_law('+')
g.check_closure_law('*')
g.check_closure_law('-')
g.check_closure_law('/')
print("Addition")
g.printMatrice(add)
print("Division")
g.printMatrice(div)
print("Multiplication")
g.printMatrice(mul)
print("Substraction")
g.printMatrice(sub)
print("Primitives root")
print(g.primitiveRoot(), end="\n\n")
#print("Identity elements")
g.check_identity_add()
g.check_identity_mul()

55
examples/group.py Normal file

@ -0,0 +1,55 @@
#!/usr/bin/env python3
from Cryptotools.Groups.group import Group
from Cryptotools.Utils.utils import gcd
import matplotlib.pyplot as plt
n = 18
def operation(e1, e2, n) -> int:
return e1 * e2 % n
# Generate the group G
g = list()
for i in range(1, n):
#if gcd(i, n) == 1:
g.append(i)
G = Group(n = n, g = g, ope=operation)
print(f"n = {n}")
print(f"G = {G.getG()}")
if G.closure() is False:
print("The closure law is not respected. It's not an abelian (commutative) group")
else:
print("It is a closure group")
if G.associative() is False:
print("The associative law is not respected. It's not a group")
else:
print("It is an associative group")
if G.identity() is False:
print("The group hasn't an identity element")
else:
print(f"Identity: {G.getIdentity()}")
if G.reverse() is False:
print(f"The group hasn't a reverse")
else:
print(f"Reverses: {G.getReverses()}")
#reverses = G.getReverses()
#plt.rcParams["figure.figsize"] = [7.00, 3.50]
#plt.rcParams["figure.autolayout"] = True
#for key, value in reverses.items():
# x = key
# y = value
# plt.plot(x, y, marker="o", markersize=2, markeredgecolor="blue")
# #plt.Circle((0, n), 0.2, color='r')
#
#plt.xlim(0, n)
#plt.ylim(0, n)
#plt.grid()
#plt.show()

6
examples/main.py Normal file

@ -0,0 +1,6 @@
#!/usr/bin/env python3
from utils.primeNumber import primeNumber
print(primeNumber(19))
print(primeNumber(20))

25
examples/plotlib.py Normal file

@ -0,0 +1,25 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import get_n_prime_numbers
import matplotlib.pyplot as plt
#import numpy as np
# Get list of n prime numbers
n = 100
primes = get_n_prime_numbers(n)
print(primes)
# With matplotlib, show into a graphics and try to explain that
plt.rcParams["figure.figsize"] = [7.00, 3.50]
plt.rcParams["figure.autolayout"] = True
for i in range(0, n):
x = primes[i]
y = primes[i]
plt.plot(x, y, marker="o", markersize=2, markeredgecolor="blue")
plt.xlim(0, n)
plt.ylim(0, n)
plt.grid()
plt.show()

53
examples/pollard.py Normal file

@ -0,0 +1,53 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.factorization import pollard_p_minus_1
from Cryptotools.Numbers.primeNumber import _millerRabinTest, getPrimeNumber
from sympy.ntheory.factor_ import pollard_pm1
from sympy import factorint
def pollard(n):
p = pollard_p_minus_1(n, B=10)
if p is not None:
print(p, n / p)
print(pollard_pm1(n, B=10))
print()
return True
return False
def safePrime(p):
nP = 2 * p + 1
return _millerRabinTest(nP)
#pollard(299)
#pollard(257 * 1009)
#pollard(1684) # Doesn't works
# Test for RSA
#p = 281
while True:
while True:
p = getPrimeNumber(64)
if ((p - 1) / 2520) % 2 == 0.0:
#print(p)
break
#p = 322506219347091343
#q = 13953581789873249851
# n = p * q
while True:
q = getPrimeNumber(64)
if int(((q - 1) / 2520) % 2) == 1:
#print(q)
break
#q = 223
n = p * q
##print(n)
#print(pollard(n))
#break
if pollard(n): # We can factorize n
break
print(safePrime(p))
#print(safePrime(q))

8
examples/prime.py Normal file

@ -0,0 +1,8 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import getPrimeNumber, sophieGermainPrime
p = getPrimeNumber(512)
print(p)
if sophieGermainPrime(p):
print("It's a safe prime")

17
examples/pseudoprimes.py Normal file

@ -0,0 +1,17 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import _millerRabinTest, _fermatLittleTheorem
from Cryptotools.Numbers.carmi import carmi_numbers, is_carmi_number, generate_carmi_numbers
print(_fermatLittleTheorem(1729))
print(_fermatLittleTheorem(1105))
print(_fermatLittleTheorem(6601))
print(_millerRabinTest(1729))
print(f"1729: {is_carmi_number(1729)}")
print(f"1105: {is_carmi_number(1105)}")
print(f"110: {is_carmi_number(110)}")
print(f"2465: {is_carmi_number(2465)}")
print(f"6601: {is_carmi_number(6601)}")
#print(carmi_numbers(1729))
print(generate_carmi_numbers(10))

22
examples/rsa.py Normal file

@ -0,0 +1,22 @@
#!/usr/bin/env python3
from Cryptotools.Encryptions.RSA import RSA
rsa = RSA()
rsa.generateKeys(size=512)
e = rsa.e
d = rsa.d
n = rsa.n
s = "I am encrypted with RSA"
print(f"plaintext: {s}")
encrypted = rsa.encrypt(s)
# Encrypt data
# print(f"ciphertext: {encrypted}")
# We decrypt
plaintext = rsa.decrypt(encrypted)
print(f"Plaintext: {plaintext}")

52
examples/rsa_problem.py Normal file

@ -0,0 +1,52 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.coprime import phi
from Cryptotools.Utils.utils import gcd
def generate_keys():
p = 7853
q = 7919
n = p * q
e = 65536 # It's public value, must be coprime with phi n
print(n)
#phin = phi(n)
phin = (p - 1) * (q - 1)
print(phin)
for _ in range(2, phin):
if gcd(phin, e) == 1:
break
e += 1
print(e)
plaintext = 'A'
ciphertext = pow(ord(plaintext), e, n)
print(f"Ciphertext: {ciphertext}")
# Now, we can test
# To resolve that formula: C = x ** e mod n
# Where C is the ciphertext, and C, e and n are known (public values)
# First, we need to find the reverse modular of phi(n) or carmi(n)
# z = e -1 mod phi(n)
# After that, we have our decryption key, we can resolve x
# x = C ** z mod n
# The RSA Problem is to decrypt with the public-key
# We just need to find the decryption key with the public-key and the modulus
# First, we need to find phi(n)
# phin = phi(n) # I computed here, result = 62172136
n = 62187907
phin = 62172136
e = 65537
ciphertext = 38605768
# print(phin)
# Find the reverse modular
d = pow(e, -1, phin)
# print(d)
plaintext = pow(ciphertext, d, n)
print(chr(plaintext))

@ -0,0 +1,6 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import sieveOfEratosthenes
print(sieveOfEratosthenes(100))
print()

15
examples/test_gcd.py Normal file

@ -0,0 +1,15 @@
from Cryptotools.Utils.utils import gcd
for i in range(1, 30):
if 30 % i == 0:
print(i)
print()
for i in range(1, 40):
if 40 % i == 0:
print(i)
print(gcd(30, 40))

17
mkdocs.yml Normal file

@ -0,0 +1,17 @@
site_name: CryptoTools documentation
theme:
name: "readthedocs"
plugins:
- mkdocstrings
nav:
- Introduction: introduction.md
- Installation: installation.md
- Low-level cryptographic:
- Number theory: number-theory.md
- Group theory: group-theory.md
- Public Keys:
- RSA: rsa.md
- Examples:
- Generating RSA Keys: examples-rsa-keys.md

16
pyproject.toml Normal file

@ -0,0 +1,16 @@
[project]
name = "Cryptotools"
version = "0.1.0"
description = ""
authors = [
{name = "gbucchino",email = "gbucchino@fortinet-us.com"}
]
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
]
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"

5
requirements.txt Normal file

@ -0,0 +1,5 @@
sympy
mkdocs
mkdocstrings[python]
mkdocs-readthedocs
mkdocs-material

22
setup.py Normal file

@ -0,0 +1,22 @@
from setuptools import setup, find_packages
_version = "1.0"
_project_name = "Cryptotools"
_packages = [
"Numbers",
"Groups",
"Utils",
]
setup(
name=_project_name,
version=_version,
description="Cryptography library",
author="Geoffrey Bucchino",
author_email="contact@bucchino.org",
packages=find_packages(),
#packages=_packages,
#package_dir={"": "Cryptotools"}
)

29
sieves_base.py Normal file

@ -0,0 +1,29 @@
#!/usr/bin/env python3
from Cryptotools.Numbers.primeNumber import isPrimeNumber
def get_bases(n):
# Generate the n first prime numbers
bases = list()
i = 2
while (len(bases) < n):
if isPrimeNumber(i):
bases.append(i)
i = i + 1
return bases
bases = get_bases(1000)
print("(")
index = 0
for i in range(0, len(bases)):
if index == 10:
index = 0
print(f"\n", end="")
else:
print(f"{bases[i]}", end=",")
index = index + 1
print(")")

122
site/404.html Normal file

@ -0,0 +1,122 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="/img/favicon.ico" />
<title>CryptoTools documentation</title>
<link rel="stylesheet" href="/css/theme.css" />
<link rel="stylesheet" href="/css/theme_extra.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" />
<link href="/assets/_mkdocstrings.css" rel="stylesheet" />
<!--[if lt IE 9]>
<script src="/js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-scroll">
<div class="wy-side-nav-search">
<a href="/." class="icon icon-home"> CryptoTools documentation
</a>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<ul>
<li class="toctree-l1"><a class="reference internal" href="/introduction/">Introduction</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="/installation/">Installation</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Low-level cryptographic</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="/number-theory/">Number theory</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="/group-theory/">Group theory</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Public Keys</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="/rsa/">RSA</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Examples</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="/examples-rsa-keys/">Generating RSA Keys</a>
</li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="Mobile navigation menu">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="/.">CryptoTools documentation</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content"><div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="/." class="icon icon-home" aria-label="Docs"></a></li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div class="section" itemprop="articleBody">
<h1 id="404-page-not-found">404</h1>
<p><strong>Page not found</strong></p>
</div>
</div><footer>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" aria-label="Versions">
<span class="rst-current-version" data-toggle="rst-current-version">
</span>
</div>
<script src="/js/jquery-3.6.0.min.js"></script>
<script>var base_url = "/";</script>
<script src="/js/theme_extra.js"></script>
<script src="/js/theme.js"></script>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

@ -0,0 +1,57 @@
/* Avoid breaking parameters name, etc. in table cells. */
.doc-contents td code {
word-break: normal !important;
}
/* No line break before first paragraph of descriptions. */
.doc-md-description,
.doc-md-description>p:first-child {
display: inline;
}
/* Avoid breaking code headings. */
.doc-heading code {
white-space: normal;
}
/* Improve rendering of parameters, returns and exceptions. */
.doc-contents .field-name {
min-width: 100px;
}
/* Other curious-spacing fixes. */
.doc-contents .field-name,
.doc-contents .field-body {
border: none !important;
padding: 0 !important;
}
.doc-contents p {
margin: 1em 0 1em;
}
.doc-contents .field-list {
margin: 0 !important;
}
.doc-contents pre {
padding: 0 !important;
}
.doc-contents .wy-table-responsive {
margin-bottom: 0 !important;
}
.doc-contents td.code {
padding: 0 !important;
}
.doc-contents td.linenos {
padding: 0 8px !important;
}
.doc-children,
footer {
margin-top: 20px;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

13
site/css/theme.css Normal file

File diff suppressed because one or more lines are too long

197
site/css/theme_extra.css Normal file

@ -0,0 +1,197 @@
/*
* Wrap inline code samples otherwise they shoot of the side and
* can't be read at all.
*
* https://github.com/mkdocs/mkdocs/issues/313
* https://github.com/mkdocs/mkdocs/issues/233
* https://github.com/mkdocs/mkdocs/issues/834
*/
.rst-content code {
white-space: pre-wrap;
word-wrap: break-word;
padding: 2px 5px;
}
/**
* Make code blocks display as blocks and give them the appropriate
* font size and padding.
*
* https://github.com/mkdocs/mkdocs/issues/855
* https://github.com/mkdocs/mkdocs/issues/834
* https://github.com/mkdocs/mkdocs/issues/233
*/
.rst-content pre code {
white-space: pre;
word-wrap: normal;
display: block;
padding: 12px;
font-size: 12px;
}
/**
* Fix code colors
*
* https://github.com/mkdocs/mkdocs/issues/2027
*/
.rst-content code {
color: #E74C3C;
}
.rst-content pre code {
color: #000;
background: #f8f8f8;
}
/*
* Fix link colors when the link text is inline code.
*
* https://github.com/mkdocs/mkdocs/issues/718
*/
a code {
color: #2980B9;
}
a:hover code {
color: #3091d1;
}
a:visited code {
color: #9B59B6;
}
/*
* The CSS classes from highlight.js seem to clash with the
* ReadTheDocs theme causing some code to be incorrectly made
* bold and italic.
*
* https://github.com/mkdocs/mkdocs/issues/411
*/
pre .cs, pre .c {
font-weight: inherit;
font-style: inherit;
}
/*
* Fix some issues with the theme and non-highlighted code
* samples. Without and highlighting styles attached the
* formatting is broken.
*
* https://github.com/mkdocs/mkdocs/issues/319
*/
.rst-content .no-highlight {
display: block;
padding: 0.5em;
color: #333;
}
/*
* Additions specific to the search functionality provided by MkDocs
*/
.search-results {
margin-top: 23px;
}
.search-results article {
border-top: 1px solid #E1E4E5;
padding-top: 24px;
}
.search-results article:first-child {
border-top: none;
}
form .search-query {
width: 100%;
border-radius: 50px;
padding: 6px 12px;
border-color: #D1D4D5;
}
/*
* Improve inline code blocks within admonitions.
*
* https://github.com/mkdocs/mkdocs/issues/656
*/
.rst-content .admonition code {
color: #404040;
border: 1px solid #c7c9cb;
border: 1px solid rgba(0, 0, 0, 0.2);
background: #f8fbfd;
background: rgba(255, 255, 255, 0.7);
}
/*
* Account for wide tables which go off the side.
* Override borders to avoid weirdness on narrow tables.
*
* https://github.com/mkdocs/mkdocs/issues/834
* https://github.com/mkdocs/mkdocs/pull/1034
*/
.rst-content .section .docutils {
width: 100%;
overflow: auto;
display: block;
border: none;
}
td, th {
border: 1px solid #e1e4e5 !important;
border-collapse: collapse;
}
/*
* Without the following amendments, the navigation in the theme will be
* slightly cut off. This is due to the fact that the .wy-nav-side has a
* padding-bottom of 2em, which must not necessarily align with the font-size of
* 90 % on the .rst-current-version container, combined with the padding of 12px
* above and below. These amendments fix this in two steps: First, make sure the
* .rst-current-version container has a fixed height of 40px, achieved using
* line-height, and then applying a padding-bottom of 40px to this container. In
* a second step, the items within that container are re-aligned using flexbox.
*
* https://github.com/mkdocs/mkdocs/issues/2012
*/
.wy-nav-side {
padding-bottom: 40px;
}
/* For section-index only */
.wy-menu-vertical .current-section p {
background-color: #e3e3e3;
color: #404040;
}
/*
* The second step of above amendment: Here we make sure the items are aligned
* correctly within the .rst-current-version container. Using flexbox, we
* achieve it in such a way that it will look like the following:
*
* [No repo_name]
* Next >> // On the first page
* << Previous Next >> // On all subsequent pages
*
* [With repo_name]
* <repo_name> Next >> // On the first page
* <repo_name> << Previous Next >> // On all subsequent pages
*
* https://github.com/mkdocs/mkdocs/issues/2012
*/
.rst-versions .rst-current-version {
padding: 0 12px;
display: flex;
font-size: initial;
justify-content: space-between;
align-items: center;
line-height: 40px;
}
/*
* Please note that this amendment also involves removing certain inline-styles
* from the file ./mkdocs/themes/readthedocs/versions.html.
*
* https://github.com/mkdocs/mkdocs/issues/2012
*/
.rst-current-version span {
flex: 1;
text-align: center;
}

@ -0,0 +1,158 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="../img/favicon.ico" />
<title>Generating RSA Keys - CryptoTools documentation</title>
<link rel="stylesheet" href="../css/theme.css" />
<link rel="stylesheet" href="../css/theme_extra.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" />
<link href="../assets/_mkdocstrings.css" rel="stylesheet" />
<script>
// Current page data
var mkdocs_page_name = "Generating RSA Keys";
var mkdocs_page_input_path = "examples-rsa-keys.md";
var mkdocs_page_url = null;
</script>
<!--[if lt IE 9]>
<script src="../js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-scroll">
<div class="wy-side-nav-search">
<a href=".." class="icon icon-home"> CryptoTools documentation
</a>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<ul>
<li class="toctree-l1"><a class="reference internal" href="../introduction/">Introduction</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../installation/">Installation</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Low-level cryptographic</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../number-theory/">Number theory</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../group-theory/">Group theory</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Public Keys</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../rsa/">RSA</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Examples</span></p>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal current" href="#">Generating RSA Keys</a>
<ul class="current">
</ul>
</li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="Mobile navigation menu">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="..">CryptoTools documentation</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content"><div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href=".." class="icon icon-home" aria-label="Docs"></a></li>
<li class="breadcrumb-item">Examples</li>
<li class="breadcrumb-item active">Generating RSA Keys</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div class="section" itemprop="articleBody">
<h1 id="generating-rsa-keys">Generating RSA Keys</h1>
<p>In the following section, we are going to see how to generate RSA Keys and how to encrypt data with these keys.</p>
<pre><code>#!/usr/bin/env python3
from Cryptotools.Encryptions.RSA import RSA
rsa = RSA()
rsa.generateKeys(size=512)
e = rsa.e
d = rsa.d
n = rsa.n
s = &quot;I am encrypted with RSA&quot;
print(f&quot;plaintext: {s}&quot;)
encrypted = rsa.encrypt(s)
# Encrypt data
print(f&quot;ciphertext: {encrypted}&quot;)
# We decrypt
plaintext = rsa.decrypt(encrypted)
print(f&quot;Plaintext: {plaintext}&quot;)
</code></pre>
</div>
</div><footer>
<div class="rst-footer-buttons" role="navigation" aria-label="Footer Navigation">
<a href="../rsa/" class="btn btn-neutral float-left" title="RSA"><span class="icon icon-circle-arrow-left"></span> Previous</a>
</div>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" aria-label="Versions">
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../rsa/" style="color: #fcfcfc">&laquo; Previous</a></span>
</span>
</div>
<script src="../js/jquery-3.6.0.min.js"></script>
<script>var base_url = "..";</script>
<script src="../js/theme_extra.js"></script>
<script src="../js/theme.js"></script>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

3059
site/group-theory/index.html Normal file

File diff suppressed because it is too large Load Diff

BIN
site/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

148
site/index.html Normal file

@ -0,0 +1,148 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="description" content="None" />
<link rel="shortcut icon" href="img/favicon.ico" />
<title>CryptoTools documentation</title>
<link rel="stylesheet" href="css/theme.css" />
<link rel="stylesheet" href="css/theme_extra.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" />
<link href="assets/_mkdocstrings.css" rel="stylesheet" />
<script>
// Current page data
var mkdocs_page_name = "Welcome to CryptoTools";
var mkdocs_page_input_path = "index.md";
var mkdocs_page_url = null;
</script>
<!--[if lt IE 9]>
<script src="js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-scroll">
<div class="wy-side-nav-search">
<a href="." class="icon icon-home"> CryptoTools documentation
</a>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<ul>
<li class="toctree-l1"><a class="reference internal" href="introduction/">Introduction</a>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="installation/">Installation</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Low-level cryptographic</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="number-theory/">Number theory</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="group-theory/">Group theory</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Public Keys</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="rsa/">RSA</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Examples</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="examples-rsa-keys/">Generating RSA Keys</a>
</li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="Mobile navigation menu">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href=".">CryptoTools documentation</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content"><div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="." class="icon icon-home" aria-label="Docs"></a></li>
<li class="breadcrumb-item active">Welcome to CryptoTools</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div class="section" itemprop="articleBody">
<h1 id="welcome-to-cryptotools">Welcome to CryptoTools</h1>
<ul>
<li><a href="/introduction">Introduction</a></li>
<li><a href="/installation">Installation</a></li>
<li>Low-Level Cryptographic<ul>
<li><a href="/number-theory">Number Theory</a></li>
<li><a href="/group-theory">Group Theory</a></li>
</ul>
</li>
<li>Public Keys:<ul>
<li><a href="/rsa">RSA</a></li>
</ul>
</li>
<li>Examples:<ul>
<li><a href="/examples-rsa-keys">Generating RSA keys</a></li>
</ul>
</li>
</ul>
</div>
</div><footer>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" aria-label="Versions">
<span class="rst-current-version" data-toggle="rst-current-version">
</span>
</div>
<script src="js/jquery-3.6.0.min.js"></script>
<script>var base_url = ".";</script>
<script src="js/theme_extra.js"></script>
<script src="js/theme.js"></script>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>
<!--
MkDocs version : 1.6.1
Build Date UTC : 2026-01-06 07:48:31.465035+00:00
-->

@ -0,0 +1,149 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="../img/favicon.ico" />
<title>Installation - CryptoTools documentation</title>
<link rel="stylesheet" href="../css/theme.css" />
<link rel="stylesheet" href="../css/theme_extra.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" />
<link href="../assets/_mkdocstrings.css" rel="stylesheet" />
<script>
// Current page data
var mkdocs_page_name = "Installation";
var mkdocs_page_input_path = "installation.md";
var mkdocs_page_url = null;
</script>
<!--[if lt IE 9]>
<script src="../js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-scroll">
<div class="wy-side-nav-search">
<a href=".." class="icon icon-home"> CryptoTools documentation
</a>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<ul>
<li class="toctree-l1"><a class="reference internal" href="../introduction/">Introduction</a>
</li>
</ul>
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal current" href="#">Installation</a>
<ul class="current">
<li class="toctree-l2"><a class="reference internal" href="#installation-from-source">Installation from source</a>
</li>
</ul>
</li>
</ul>
<p class="caption"><span class="caption-text">Low-level cryptographic</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../number-theory/">Number theory</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../group-theory/">Group theory</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Public Keys</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../rsa/">RSA</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Examples</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../examples-rsa-keys/">Generating RSA Keys</a>
</li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="Mobile navigation menu">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="..">CryptoTools documentation</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content"><div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href=".." class="icon icon-home" aria-label="Docs"></a></li>
<li class="breadcrumb-item active">Installation</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div class="section" itemprop="articleBody">
<h1 id="installation">Installation</h1>
<p>To install the project, you should install from my own Python repository but, you first need to deploy your virtual enviroment.</p>
<h2 id="installation-from-source">Installation from source</h2>
<p>You can install from the source. Download the <a href="https://gitea.bucchino.org/gbucchino/cryptotools.git">project</a> and install it in your virtual environment:</p>
<pre><code>$ virtualenv ~/venv/cryptotools
$ source ~/venv/cryptotools/bin/activate
</code></pre>
<pre><code>$ git clone https://gitea.bucchino.org/gbucchino/cryptotools.git
$ cd cryptotools
$ python3 setup.py install
</code></pre>
<p>The installation is completed. You can know use Cryptotools package into your project. In the directory <code>examples</code> you may find some examples scripts</p>
</div>
</div><footer>
<div class="rst-footer-buttons" role="navigation" aria-label="Footer Navigation">
<a href="../introduction/" class="btn btn-neutral float-left" title="Introduction"><span class="icon icon-circle-arrow-left"></span> Previous</a>
<a href="../number-theory/" class="btn btn-neutral float-right" title="Number theory">Next <span class="icon icon-circle-arrow-right"></span></a>
</div>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" aria-label="Versions">
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../introduction/" style="color: #fcfcfc">&laquo; Previous</a></span>
<span><a href="../number-theory/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>
<script src="../js/jquery-3.6.0.min.js"></script>
<script>var base_url = "..";</script>
<script src="../js/theme_extra.js"></script>
<script src="../js/theme.js"></script>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

@ -0,0 +1,136 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="../img/favicon.ico" />
<title>Introduction - CryptoTools documentation</title>
<link rel="stylesheet" href="../css/theme.css" />
<link rel="stylesheet" href="../css/theme_extra.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" />
<link href="../assets/_mkdocstrings.css" rel="stylesheet" />
<script>
// Current page data
var mkdocs_page_name = "Introduction";
var mkdocs_page_input_path = "introduction.md";
var mkdocs_page_url = null;
</script>
<!--[if lt IE 9]>
<script src="../js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-scroll">
<div class="wy-side-nav-search">
<a href=".." class="icon icon-home"> CryptoTools documentation
</a>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<ul class="current">
<li class="toctree-l1 current"><a class="reference internal current" href="#">Introduction</a>
<ul class="current">
</ul>
</li>
</ul>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../installation/">Installation</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Low-level cryptographic</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../number-theory/">Number theory</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../group-theory/">Group theory</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Public Keys</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../rsa/">RSA</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Examples</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../examples-rsa-keys/">Generating RSA Keys</a>
</li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="Mobile navigation menu">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="..">CryptoTools documentation</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content"><div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href=".." class="icon icon-home" aria-label="Docs"></a></li>
<li class="breadcrumb-item active">Introduction</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div class="section" itemprop="articleBody">
<h1 id="cryptotools">CryptoTools</h1>
<p>CryptoTools is a Python package that provides low-level cryptographic primitives for generating strong numbers. With this project, it's possible to generate public key cryptosystems such as RSA.
This project has a academic purpose and can not be used in production enviroment yet.</p>
<p>So far, my cryptographic modules are not compliant with <a href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-3.pdf">FIPS 140-3</a> but in the future, that will be.</p>
</div>
</div><footer>
<div class="rst-footer-buttons" role="navigation" aria-label="Footer Navigation">
<a href="../installation/" class="btn btn-neutral float-right" title="Installation">Next <span class="icon icon-circle-arrow-right"></span></a>
</div>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" aria-label="Versions">
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../installation/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>
<script src="../js/jquery-3.6.0.min.js"></script>
<script>var base_url = "..";</script>
<script src="../js/theme_extra.js"></script>
<script src="../js/theme.js"></script>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

4
site/js/html5shiv.min.js vendored Normal file

@ -0,0 +1,4 @@
/**
* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);

2
site/js/jquery-3.6.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
site/js/theme.js Normal file

File diff suppressed because one or more lines are too long

8
site/js/theme_extra.js Normal file

@ -0,0 +1,8 @@
/*
* Assign 'docutils' class to tables so styling and
* JavaScript behavior is applied.
*
* https://github.com/mkdocs/mkdocs/issues/2028
*/
$('div.rst-content table').addClass('docutils');

File diff suppressed because it is too large Load Diff

BIN
site/objects.inv Normal file

Binary file not shown.

1086
site/rsa/index.html Normal file

File diff suppressed because it is too large Load Diff

3
site/sitemap.xml Normal file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
</urlset>

BIN
site/sitemap.xml.gz Normal file

Binary file not shown.

@ -0,0 +1 @@
1, 1, 2, 2, 4, 2, 6, 2, 6, 4, 10, 2, 12, 6, 4, 4, 16, 6, 18, 4, 6, 10, 22, 2, 20, 12, 18, 6, 28, 4, 30, 8, 10, 16, 12, 6, 36, 18, 12, 4, 40, 6, 42, 10, 12, 22, 46, 4, 42, 20, 16, 12, 52, 18, 20, 6, 18, 28, 58, 4, 60, 30, 6, 16, 12, 10, 66, 16, 22, 12, 70, 6, 72, 36, 20, 18, 30, 12, 78, 4, 54

1
tests/carmi_numbers_oeis Normal file

@ -0,0 +1 @@
561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841, 29341, 41041, 46657, 52633, 62745, 63973, 75361, 101101, 115921, 126217, 162401, 172081, 188461, 252601, 278545, 294409, 314821, 334153, 340561, 399001, 410041, 449065, 488881, 512461, 530881, 552721

8
tests/execute_tests.py Executable file

@ -0,0 +1,8 @@
#!/usr/bin/bash
set -e
source /home/geoffrey/venv/forensic/bin/activate;
for test in `ls tests/test_*.py`; do
echo $test;
python3 $test -v;
done

Some files were not shown because too many files have changed in this diff Show More