|
| 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 |
0 commit comments