|
1 | 1 | # ElGamal Encryption |
2 | | - |
| 2 | + |
3 | 3 | Prerequisites: |
4 | 4 | 1. Cyclic Groups, Generators |
5 | 5 | 2. Basic Number Theory (Euler's Theorem, Fermat's Little Theorem) |
6 | | - |
7 | | - |
8 | 6 |
|
9 | | -ElGamal Encryption System is an Asymmetric Key Encryption System based on [Discrete Logarithm Problem](../Discrete-Logarithm-Problem/) (DLP) and Diffie-Hellman Key Exchange. Like every other Public Key encryption, it has a public and a private key, we will see that as we move forward. |
10 | | - |
| 7 | + |
| 8 | +ElGamal Encryption System is an Asymmetric Key Encryption System based on [Discrete Logarithm Problem](../Discrete-Logarithm-Problem/) (DLP) and Diffie-Hellman Key Exchange. |
| 9 | + |
11 | 10 | For illustrative purposes, we will consider `Alice` as the receiver and `Bob` as the sender. |
12 | | - |
13 | | -There are different steps involved while encrypting/decrypting data with ElGamal, let's list them first and then study each of them in detail: |
14 | | -1. **Key Generation**: Alice generates a pair of public and private keys. Shares the public key. |
| 11 | + |
| 12 | +There are different steps involved while encrypting or decrypting data with ElGamal, let's list them first and then study each of them in detail: |
| 13 | +1. **Key Generation**: Alice generates a public and private key and shares the public key. |
15 | 14 | 2. **Encryption**: Bob uses Alice's public to encrypt message that he wants to send to Alice, and hence generates a pair of ciphertext (c1, c2). Shares the ciphertext pair. |
16 | | -3. **Decryption**: Alice then uses his private key to decrypt the ciphertext (c1, c2). |
17 | | - |
18 | | - |
| 15 | +3. **Decryption**: Alice then uses her private key to decrypt the ciphertext (c1, c2). |
| 16 | + |
| 17 | + |
19 | 18 |
|
20 | 19 | ## Key Generation |
21 | | -This is the first step in the process of transferring a messages securely, between Alice and Bob. In this step, Alice does the following: |
22 | | -1. Selects a Cyclic Group `G` of order `q` and generator `g` |
23 | | -2. Selects a random number `x` such that `1 <= x <= q-1` |
| 20 | +This is the first step in the process of transferring a messages securely, between Alice and Bob. In this step, Alice does the following: |
| 21 | +1. Selects a Cyclic Group `G` of order `q` and generator `g`. Note that either the cyclic group should be generated over a [safe prime](https://en.wikipedia.org/wiki/Safe_prime) `p`, or the generator `g` should generate prime-order-subgroups; otherwise it is vulnerable to [Small Subgroup Attacks](https://florianjw.de/en/insecure_generators.html). |
| 22 | +2. Generates a random number `x` such that `1 <= x <= q-1` and assigns it as the private key (Note that `q` is the group order). |
24 | 23 | 3. Calculates  |
25 | 24 | 4. Shares `h`, `g`, `q` as Public Key |
26 | 25 | 5. `x` is the Private Key which only Alice should know, and that's where the security of the encryption system lies. |
27 | | - |
| 26 | + |
28 | 27 |
|
29 | 28 | Here is a python-2.7 implementation of the above step: |
30 | 29 | ```python |
31 | | -from Crypto.Util.number import * |
32 | | -import random |
33 | | - |
34 | | -def generate_key(size): |
35 | | - p = getPrime(size) |
36 | | - x = random.randint(2, p-2) |
37 | | - g = 2 |
38 | | - h = pow(g, x, q) |
39 | | - return (h, g, q) |
| 30 | +def _generate_key(): |
| 31 | + # Assigning the largest 1024-bit safe prime as p |
| 32 | + p = (1 << 1024) - 1093337 |
| 33 | + x = randint(2, p-2) |
| 34 | + g = 23 |
| 35 | + q = p - 1 |
| 36 | + h = pow(g, x, p) |
| 37 | + pubkey = PublicKey(h, p, g, q) |
| 38 | + privkey = PrivateKey(x, p, g, q) |
| 39 | + return (pubkey, privkey) |
40 | 40 | ``` |
41 | | - |
42 | | - |
| 41 | + |
43 | 42 |
|
44 | 43 | ## Encryption |
45 | 44 | Bob receives Alice's Public Key and encrypts the message that he wants to send to Alice as follows: |
46 | | -1. Selects a random number `y` --> {1, ..., q-1} |
47 | | -2. Chooses a message `m` such that `1 <= m < q-1` |
48 | | -2. Diffie Hellman Step: Calculates  |
| 45 | +1. Selects a random number `y` such that `1 <= y <= q-1`. Note that a new value of `y` is chosen for sending every message. Hence, `y` is known as ephemeral key. |
| 46 | +2. Chooses a message `m` such that `1 < m < q-1` |
| 47 | +2. Diffie Hellman Step: Calculates  |
49 | 48 | 3. Diffie Hellman Step, also `s` is known as the shared secret: Calculates  |
50 | 49 | 4. Calculates  |
51 | | -5. Shares (c1, c2) as the ciphertext |
52 | | - |
| 50 | +5. Shares (c<sub>1</sub>, c<sub>2</sub>) as the ciphertext |
| 51 | + |
53 | 52 |
|
54 | 53 | Here is a python-2.7 implementation of the above step: |
55 | 54 | ```python |
56 | | -from Crypto.Util.number import * |
57 | | -import random |
58 | | - |
59 | | -def encrypt(message, h, g, q): |
60 | | - message = bytes_to_long(message) |
61 | | - y = random.randint(2, p-2) |
62 | | - c1 = pow(g, y, q) |
63 | | - s = pow(h, y, q) |
64 | | - c2 = (m*s) % q |
| 55 | +def _encrypt(message, pubkey): |
| 56 | + h = pubkey.h |
| 57 | + p = pubkey.p |
| 58 | + g = pubkey.g |
| 59 | + q = pubkey.q |
| 60 | + m = bytes_to_long(message) |
| 61 | + # Generating ephemeral key: `y` |
| 62 | + y = randint(2, p-2) |
| 63 | + c1 = pow(g, y, p) |
| 64 | + # Computing the shared secret: `s` |
| 65 | + s = pow(h, y, p) |
| 66 | + c2 = (m*s) % p |
65 | 67 | return (c1, c2) |
| 68 | + |
66 | 69 | ``` |
67 | 70 |
|
68 | | - |
69 | | - |
70 | 71 |
|
71 | 72 | ## Decryption |
72 | | -Alice receives (c1, c2), we can write them as: |
73 | | - |
74 | | - |
75 | | -Alice then calculates the following to get the shared secret `s`:  |
76 | | -To get back the message `m` from c<sub>2</sub>, Alice does the following: |
77 | | - |
78 | | - |
| 73 | +Alice receives (c<sub>1</sub>, c<sub>2</sub>), we can write them as: |
| 74 | + |
| 75 | + |
| 76 | +1. Alice then calculates the following to get the shared secret `s`:  |
| 77 | +2. To get back the message `m` from c<sub>2</sub>, Alice does the following: |
| 78 | + |
79 | 79 |
|
80 | | -Here is a python-2.7 implementation of the above step: |
81 | | -```python |
82 | | -from Crypto.Util.number import * |
83 | | -import random |
84 | 80 |
|
85 | | -def decrypt(c1, c2, g, q, x): |
86 | | - s = pow(c1, x, q) |
87 | | - m = (c2*inverse(s, q)) % q |
| 81 | +Here is a python-2.7 implementation of the above step: |
| 82 | +```python |
| 83 | +def _decrypt(ciphertext, privkey): |
| 84 | + c1, c2 = ciphertext |
| 85 | + g = privkey.g |
| 86 | + p = privkey.p |
| 87 | + x = privkey.x |
| 88 | + s = pow(c1, x, p) |
| 89 | + m = (c2*inverse(s, p)) % p |
88 | 90 | return m |
89 | 91 | ``` |
90 | | - |
91 | | -Check out a trivial implementation/example of ElGamal encryption/decryption [here](example.py) |
| 92 | + |
| 93 | +Check out the full implementation/example of ElGamal encryption/decryption [here](example.py) |
92 | 94 |
|
93 | 95 | ## References |
94 | | -1. [Wikipedia- ElGamal Encryption](https://en.wikipedia.org/wiki/ElGamal_encryption) |
| 96 | +1. [Wikipedia- ElGamal Encryption](https://en.wikipedia.org/wiki/ElGamal_encryption) |
| 97 | +2. [Small Subgroup Attacks- Florianjw's blog](https://florianjw.de/en/insecure_generators.html) |
0 commit comments