Skip to content

Commit f3da19e

Browse files
author
Lukas Zorn
committed
Release 0.1.1
1 parent 4cf9fe5 commit f3da19e

13 files changed

+1016
-2
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ target/
7777
# Jupyter Notebook
7878
.ipynb_checkpoints
7979

80+
# Integrated Development Environments
81+
.idea/
82+
.vscode/
83+
8084
# IPython
8185
profile_default/
8286
ipython_config.py

README.md

100644100755
+21-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,21 @@
1-
# simple-cryptographic-functions
2-
Python library for demonstrating the functionality of common cryptographic functions
1+
# Simple Cryptographic Functions
2+
3+
Python library for demonstrating the functionality of common cryptographic functions.
4+
5+
## Requirements
6+
7+
Python 3.7.9 or later including pip for installing the following dependencies:
8+
9+
```shell
10+
pip install -r requirements.txt
11+
```
12+
13+
# Usage
14+
15+
To use, simply uncomment the corresponding function in `main.py` and adjust the sample values if necessary.
16+
17+
## To Do
18+
19+
- Include a brute force function for flexible cracking of all included algorithms in the lower prime range
20+
- Unify output of mathematical conditions
21+
- Add an English translation
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python
2+
3+
from cryptographic_functions import shared_functions
4+
from tabulate import tabulate
5+
import random
6+
7+
__author__ = "Lukas Zorn"
8+
__copyright__ = "Copyright 2021 Lukas Zorn"
9+
__license__ = " GNU GPLv3"
10+
__version__ = "0.1.1"
11+
__maintainer__ = "Lukas Zorn"
12+
__status__ = "Development"
13+
14+
15+
# Diffie–Hellman key exchange
16+
def key_exchange(p, g, a=None, b=None):
17+
print(tabulate([['Diffie-Hellman-Schlüsselaustausch']], tablefmt='fancy_grid'))
18+
19+
# Choose an integer p that is a prime number
20+
if not shared_functions.is_prime(p):
21+
print(f'Die Variable p = {p} muss eine Primzahl sein.')
22+
return -1
23+
24+
# Choose an integer g such that 1 < g < p
25+
if g not in range(2, p):
26+
print(f'Für die Variable g = {g} muss gelten 1 < {g} < {p}.')
27+
return -1
28+
29+
# Choose an integer a such that 1 < a < p
30+
if a is None:
31+
a = random.randrange(2, p)
32+
33+
# Choose an integer b such that 1 < b < p and a != b
34+
if b is None:
35+
b = a
36+
while b == a:
37+
b = random.randrange(2, p)
38+
39+
# Choose an integer b such that a != b
40+
if a == b:
41+
print(f'Die Variablen a = {a} und b = {b} dürfen nicht identisch sein.')
42+
return -1
43+
44+
# Choose an integer a such that 1 < a < p
45+
if a not in range(2, p):
46+
print(f'Für die Variable a = {a} muss gelten 1 < {a} < {p}.')
47+
return -1
48+
49+
# Choose an integer b such that 1 < b < p
50+
if b not in range(2, p):
51+
print(f'Für die Variable b = {b} muss gelten 1 < {b} < {p}.')
52+
return -1
53+
54+
# Secret generation
55+
a_secret = (g ** a) % p
56+
b_secret = (g ** b) % p
57+
a_shared_key = (b_secret ** a) % p
58+
b_shared_key = (a_secret ** b) % p
59+
60+
if not a_shared_key == b_shared_key:
61+
print(f'Bei der Generierung des gemeinsamen Schlüssels ist ein Fehler aufgetreten, da das Ergebnis für '
62+
f'K_A = {a_shared_key} und K_B = {b_shared_key} nicht identisch ist.')
63+
return -1
64+
65+
# Calculation path output
66+
print(
67+
f'A und B vereinbaren öffentlich für den Schlüsselaustausch eine Primzahl p = {p} und eine Basis '
68+
f'g = {g} aus dem Galois-Körper GF({p}).', end='\n\n')
69+
print(
70+
f'(A) Wähle: a = {a} ist gültig, da gilt:\n'
71+
f'1 < {a} < {p}\n'
72+
f'(B) Wähle: b = {b} ist gültig, da gilt:\n'
73+
f'1 < {b} < {p}', end='\n\n')
74+
print(
75+
f'(A) Berechne: α = g^a mod p = {g}^{a} mod {p} = {a_secret}\n'
76+
f'(B) Berechne: β = g^b mod p = {g}^{b} mod {p} = {b_secret}', end='\n\n')
77+
print(
78+
f'A und B teilen sich öffentlich gegenseitig die Werte von α = {a_secret} und β = {b_secret} mit.', end='\n\n')
79+
print(
80+
f'(A) Berechne: K = β^a mod p = {b_secret}^{a} mod {p} = {a_shared_key}\n'
81+
f'(B) Berechne: K = α^b mod p = {a_secret}^{b} mod {p} = {b_shared_key}', end='\n\n')
82+
print(
83+
f'Verifikation: K = g^(a * b) mod p = {g}^({a} * {b}) mod {p} = {g ** (a * b) % p}', end='\n\n')
84+
return a_shared_key
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env python
2+
3+
from cryptographic_functions import modulo_inverse_multiplicative
4+
from cryptographic_functions import shared_functions
5+
from tabulate import tabulate
6+
import random
7+
8+
__author__ = "Lukas Zorn"
9+
__copyright__ = "Copyright 2021 Lukas Zorn"
10+
__license__ = " GNU GPLv3"
11+
__version__ = "0.1.1"
12+
__maintainer__ = "Lukas Zorn"
13+
__status__ = "Development"
14+
15+
16+
# ElGamal keypair generation
17+
def keypair_generation(p, g, d=None):
18+
print(tabulate([['ElGamal Schlüsselerzeugung']], tablefmt='fancy_grid'))
19+
20+
# Choose an integer p that is a prime number
21+
if not shared_functions.is_prime(p):
22+
print(f'Die Variable p = {p} muss eine Primzahl sein.')
23+
return -1
24+
25+
# Choose an integer g such that 1 ≤ g < p
26+
if g not in range(1, p):
27+
print(f'Für die Variable g = {g} muss gelten 1 ≤ {g} < {p}.')
28+
return -1
29+
30+
# Choose an integer d such that 1 ≤ d < (p - 1)
31+
if d is None:
32+
a = random.randrange(1, p - 1)
33+
34+
if d not in range(1, p - 1):
35+
print(f'Für die Variable d = {d} muss gelten 1 ≤ {d} < {p - 1}.')
36+
return -1
37+
38+
# Secret generation
39+
e = (g ** d) % p
40+
41+
# Calculation path output
42+
print(
43+
f'Es wird öffentlich für die Schlüsselerzeugung eine Primzahl p = {p} und eine Basis g = {g} aus dem '
44+
f'Galois-Körper GF({p}) vereinbart.', end='\n\n')
45+
print(
46+
f'Wähle: d = {d} ist gültig, da gilt:\n'
47+
f'1 ≤ {d} < {p - 1}', end='\n\n')
48+
print(
49+
f'(A) Berechne: e = g^d mod p = {g}^{d} mod {p} = {e}', end='\n\n')
50+
print(
51+
f'Der öffentliche Schlüssel K(pub) = {{p, g, e}} entspricht somit K(pub) = {{{p}, {g}, {e}}} und der private '
52+
f'Schlüssel K(priv) = {{p, d}} folglich K(priv) = {{{p}, {d}}}.', end='\n\n')
53+
return (p, g, e), (p, d)
54+
55+
56+
# ElGamal encryption
57+
def encryption(public_key, m, k=None):
58+
print(tabulate([['ElGamal Verschlüsselung']], tablefmt='fancy_grid'))
59+
60+
# Unpack the private key into its components
61+
p, g, e = public_key
62+
63+
# Choose an integer m such that 1 ≤ m < p
64+
if m not in range(1, p):
65+
print(f'Für die Variable m = {m} muss gelten 1 ≤ {m} < {p}.')
66+
return -1
67+
68+
# Choose an integer k such that 1 ≤ k < p - 1 and such that k and p - 1 are coprime
69+
if k is None:
70+
k = random.randrange(1, p - 1)
71+
while shared_functions.gcd(k, p - 1) != 1:
72+
k = random.randrange(1, p - 1)
73+
else:
74+
if shared_functions.gcd(k, p - 1) != 1:
75+
print(f'Das selbstgewählte k = {k} ist nicht teilerfremd zu (p - 1) = {p - 1}, da ggT({k},{p - 1}) = '
76+
f'{shared_functions.gcd(k, p - 1)}.', end='\n\n')
77+
return -1
78+
79+
# Choose an integer k such that 1 ≤ k < p - 1
80+
if k not in range(1, p - 1):
81+
print(f'Für die Variable k = {k} muss gelten 1 ≤ {k} < {p - 1}.')
82+
return -1
83+
84+
# Encryption
85+
a = (g ** k) % p
86+
b = ((e ** k) * m) % p
87+
88+
# Calculation path output
89+
print(
90+
f'Wähle: k = {k} ist gültig, da gilt:\n'
91+
f'1 ≤ {k} < {p - 1} und ggT({k},{p - 1}) = {shared_functions.gcd(k, p - 1)}', end='\n\n')
92+
print(
93+
f'Die Verschlüsselung am Beispiel von K(pub) = {{{p}, {g}, {e}}} für den Klartext m = {m} ergibt den '
94+
f'Geheimtext a = {a} sowie b = {b}, da gilt:\n'
95+
f'a = g^k mod p\n'
96+
f'a = {g}^{k} mod {p}\n'
97+
f'a = {a}\n'
98+
f'b = e^k ⊙ m mod p\n'
99+
f'b = {e}^{k}{m} mod {p}\n'
100+
f'b = {b}', end='\n\n')
101+
print(
102+
f'K = e^k = {e}^{k} = {(e ** k) % p} mod {p}', end='\n\n')
103+
return a, b
104+
105+
106+
# ElGamal decryption
107+
def decryption(private_key, c, print_matrix=False, print_linear_factorization=True):
108+
print(tabulate([['ElGamal Entschlüsselung']], tablefmt='fancy_grid'))
109+
110+
# Unpack the private key into its components
111+
p, d = private_key
112+
113+
# Unpack the ciphertext into its components
114+
a, b = c
115+
116+
# Choose an integer a such that 1 ≤ a < p
117+
if a not in range(1, p):
118+
print(f'Für die Variable a = {a} muss gelten 1 ≤ {a} < {p}.')
119+
return -1
120+
121+
# Choose an integer b such that 1 ≤ b < p
122+
if b not in range(1, p):
123+
print(f'Für die Variable b = {b} muss gelten 1 ≤ {b} < {p}.')
124+
return -1
125+
126+
# Decryption
127+
a_d = (a ** d) % p
128+
a_i = modulo_inverse_multiplicative.mim(p, a_d, print_matrix, print_linear_factorization, 1)
129+
m = (a_i * b) % p
130+
131+
# Calculation path output
132+
print(
133+
f'Die Entschlüsselung am Beispiel von K(priv) = {{{p}, {d}}} für den Geheimtext a = {a} und b = {b} '
134+
f'ergibt den Klartext m = {m}, da gilt:\n'
135+
f'a^d ⊙ m = b mod p\n'
136+
f'{a}^{d} ⊙ m = {b} mod {p}\n'
137+
f'{a ** d} ⊙ m = {b} mod {p}\n'
138+
f'{a_d} ⊙ m = {b} mod {p}', end='\n\n')
139+
print(
140+
f'K = a^d = {a}^{d} = {a_d} mod {p}', end='\n\n')
141+
print(
142+
f'Daraus folgt:\n'
143+
f'm = {a_d}^-1 ⊙ {b} mod {p}\n'
144+
f'<AUXILIARY 1>Achtung: Die Namen der Variablen können abweichen!</AUXILIARY 1>\n'
145+
f'm = {a_i}{b} mod {p}\n'
146+
f'm = {a_i * b} mod {p}\n'
147+
f'm = {m}', end='\n\n')
148+
return m
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env python
2+
3+
from cryptographic_functions import modulo_inverse_additive
4+
from cryptographic_functions import modulo_inverse_multiplicative
5+
from tabulate import tabulate
6+
7+
__author__ = "Lukas Zorn"
8+
__copyright__ = "Copyright 2021 Lukas Zorn"
9+
__license__ = " GNU GPLv3"
10+
__version__ = "0.1.1"
11+
__maintainer__ = "Lukas Zorn"
12+
__status__ = "Development"
13+
14+
15+
# Addition in finite sets
16+
def addition(m, a, b):
17+
print(tabulate([['Addition in endlichen Mengen']], tablefmt='fancy_grid'))
18+
19+
# Checking whether requirements are met
20+
if m < 2:
21+
print(f'Die Variable m = {m} muss größer gleich 2 sein.')
22+
return -1
23+
24+
if a not in range(m):
25+
print(f'Die Variable a = {a} muss zwischen 0 und {m - 1} liegen.')
26+
return -1
27+
28+
if b not in range(m):
29+
print(f'Die Variable b = {b} muss zwischen 0 und {m - 1} liegen.')
30+
return -1
31+
32+
q = (a + b) // m
33+
r = (a + b) % m
34+
35+
# Calculation path output
36+
print(f'Die modulo m = {m} Addition von {a}{b} = {r}, da gilt:\n'
37+
f'({a} + {b}) / {m} = {q} + ({r} / {m})\n'
38+
f'{a} + {b} = {q} * {m} + {r}\n'
39+
f'Daraus folgt: {a}{b} = {r}', end='\n\n')
40+
41+
return r
42+
43+
44+
# Subtraction in finite sets
45+
def subtraction(m, a, b, print_matrix=False):
46+
print(tabulate([['Subtraktion in endlichen Mengen']], tablefmt='fancy_grid'))
47+
48+
# Checking whether requirements are met
49+
i = modulo_inverse_additive.mia(m, b, print_matrix, 1)
50+
51+
q = (a + i) // m
52+
r = (a + i) % m
53+
54+
# Calculation path output
55+
if i != -1:
56+
print(f'Die modulo m = {m} Subtraktion von {a}{b} = {r}, da gilt:\n'
57+
f'<AUXILIARY 1>Achtung: Die Namen der Variablen können abweichen!</AUXILIARY 1>\n'
58+
f'({a} + {i}) / {m} = {q} + ({r} / {m})\n'
59+
f'{a} + {i} = {q} * {m} + {r}\n'
60+
f'Daraus folgt: {a}{b} = {a} ⊕ ({-a}) = {a}{i} = {r}', end='\n\n')
61+
return r
62+
else:
63+
print(
64+
f'Die modulo m = {m} Subtraktion von {a}{b} kann nicht durchgeführt werden, da das additiv inverse '
65+
f'Element für m und b nicht definiert ist.', end='\n\n')
66+
return -1
67+
68+
69+
# Multiplication in finite sets
70+
def multiplication(m, a, b):
71+
print(tabulate([['Multiplikation in endlichen Mengen']], tablefmt='fancy_grid'))
72+
73+
# Checking whether requirements are met
74+
if m < 2:
75+
print(f'Die Variable m = {m} muss größer gleich 2 sein.')
76+
return -1
77+
78+
if a not in range(1, m):
79+
print(f'Die Variable a = {a} muss zwischen 1 und {m - 1} liegen.')
80+
return -1
81+
82+
if b not in range(1, m):
83+
print(f'Die Variable b = {b} muss zwischen 1 und {m - 1} liegen.')
84+
return -1
85+
86+
q = (a * b) // m
87+
r = (a * b) % m
88+
89+
# Calculation path output
90+
print(f'Die modulo m = {m} Multiplikation von {a}{b} = {r}, da gilt:\n'
91+
f'({a} * {b}) / {m} = {q} + ({r} / {m})\n'
92+
f'{a} * {b} = {q} * {m} + {r}\n'
93+
f'Daraus folgt: {a}{b} = {r}', end='\n\n')
94+
95+
return r
96+
97+
98+
# Division in finite sets
99+
def division(m, a, b, print_matrix=False, print_linear_factorization=True):
100+
print(tabulate([['Division in endlichen Mengen']], tablefmt='fancy_grid'))
101+
102+
# Checking whether requirements are met
103+
i = modulo_inverse_multiplicative.mim(m, b, print_matrix, print_linear_factorization, 1)
104+
105+
q = (a * i) // m
106+
r = (a * i) % m
107+
108+
# Calculation path output
109+
if i != -1:
110+
print(f'Die modulo m = {m} Division von {a}{b} = {r}, da gilt:\n'
111+
f'<AUXILIARY 1>Achtung: Die Namen der Variablen können abweichen!</AUXILIARY 1>\n'
112+
f'({a} * {i}) / {m} = {q} + ({r} / {m})\n'
113+
f'{a} * {i} = {q} * {m} + {r}\n'
114+
f'Daraus folgt: {a}{b} = {a}{b}^-1 = {a}{i} = {r}', end='\n\n')
115+
return r
116+
else:
117+
print(
118+
f'Die modulo m = {m} Division von {a}{b} kann nicht durchgeführt werden, da m und b nicht teilerfremd '
119+
f'sind und folglich das multiplikativ inverse Element nicht definiert ist.', end='\n\n')
120+
return -1

0 commit comments

Comments
 (0)