diff --git a/hw3/Homework 2.ipynb b/hw3/Homework 2.ipynb new file mode 100644 index 0000000..f9d2cf8 --- /dev/null +++ b/hw3/Homework 2.ipynb @@ -0,0 +1,547 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "421d5e4d-1327-449b-8aae-16cb1c99cb60", + "metadata": {}, + "source": [ + "Ondřej Hladůvka \n", + "\n", + "If you want to run code in this notebook, you can find it here: https://git.hladu.xyz/hladu357/TalTech_crypt/src/branch/master/hw2" + ] + }, + { + "cell_type": "markdown", + "id": "0ed8045c-d080-4288-909a-9190433d6a09", + "metadata": {}, + "source": [ + "## Task 1 Confusion and diffusion\n", + "From the lectures, you learned about importance of confusion and diffusion principles for the block ciphers. Let us examine them in more details. Assume you need to analyse\n", + "properties of Vigenere cipher." + ] + }, + { + "cell_type": "markdown", + "id": "c8eedd35-16bd-433d-b161-b1e9c7a26c19", + "metadata": {}, + "source": [ + "1. Encrypt message THEWANDCHOOSESTHEWIZARD with key MAGIC." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "47aba105-8f9d-40eb-a5ed-5f93bbe63b86", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ciphertext: FHKECZDIPQASKAVTECQBMRJ\n" + ] + } + ], + "source": [ + "def vigenere_enc(pt : str, key : str):\n", + " pt_int = [ord(i) - ord('A') for i in pt]\n", + " key_int = [ord(i) - ord('A') for i in key]\n", + "\n", + " ct_int = [(char + key_int[idx % len(key_int)]) % 26 for idx, char in enumerate(pt_int)]\n", + " ct = [chr(i + ord('A')) for i in ct_int]\n", + " return ct\n", + "\n", + "pt = \"THEWANDCHOOSESTHEWIZARD\"\n", + "key = \"MAGIC\"\n", + "ct = vigenere_enc(pt, key)\n", + "\n", + "print(\"ciphertext: \", \"\".join(ct))" + ] + }, + { + "cell_type": "markdown", + "id": "60d515f1-5951-4743-8286-4b41018fabc4", + "metadata": {}, + "source": [ + "2. Suppose we change one letter (W becomes L) in the plaintext to get THEWANDCHOOSESTHE L IZARD.\n", + "How may letters of the ciphertext are changed? Is the diffusion property achieved?" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "3c55e9ad-dd9f-48ee-b4fe-064dacb0706a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Witch changed plaintext at index 17\n", + "New ciphertext is: FHKECZDIPQASKAVTERQBMRJ\n", + "character changes at index 17 C -> R\n", + "diffusion is not achieved, as the plaintext's change effects the ciphertext in structured way exploitable by cryptanalysis\n" + ] + } + ], + "source": [ + "idx = 17\n", + "pt2 = pt[:idx] + \"L\" + pt[(idx + 1):]\n", + "ct2 = \"\".join(vigenere_enc(pt2, key))\n", + "\n", + "print(f\"Witch changed plaintext at index {idx}\")\n", + "print(f\"New ciphertext is: {ct2}\")\n", + "\n", + "for idx, (a, b) in enumerate(zip(ct, ct2)):\n", + " if (a != b):\n", + " print(f\"character changes at index {idx} {a} -> {b}\")\n", + "print(\"diffusion is not achieved, as the plaintext's change effects the ciphertext in structured way exploitable by cryptanalysis\")" + ] + }, + { + "cell_type": "markdown", + "id": "47b5e048-9f0a-4436-8294-fcba9fca489e", + "metadata": {}, + "source": [ + "3. Suppose we change one letter in key (G becomes N). How may letters of the ciphertext are changed?\n", + "Is confusion property achieved?" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "c89a36d4-6c24-4ca3-84c5-bafea87073c3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "it would change lower whole part n / k letters where n is length of plaintext and k is length of the key\n", + "floor(n / k) = floor(23 / 5) = 4\n", + "confusion is not achieved, as the key's effect on the ciphertext is structured and exploitable by cryptanalysis\n" + ] + } + ], + "source": [ + "import math\n", + "print(\"it would change lower whole part n / k letters where n is length of plaintext and k is length of the key\")\n", + "n = len(pt)\n", + "k = len(key)\n", + "print(f\"floor(n / k) = floor({n} / {k}) = {math.floor(n/k)}\")\n", + "print(\"confusion is not achieved, as the key's effect on the ciphertext is structured and exploitable by cryptanalysis\")" + ] + }, + { + "cell_type": "markdown", + "id": "1b4e0abb-fbcb-4019-9c4d-c8486d7c3884", + "metadata": {}, + "source": [ + "## Task 2. Pseudorandom function \n", + "Let F ∶ {0, 1}\n", + "n × {0, 1}\n", + "n → {0, 1}\n", + "n\n", + "be a secure PRF. Do the following\n", + "functions satisfy definition of pseudo-random function?" + ] + }, + { + "cell_type": "markdown", + "id": "3dc36d9b-46b1-4222-bd16-19b68356dd6a", + "metadata": {}, + "source": [ + "1. F′(k, m) = F(k, m) || 0^n, where 0^n is a zero string of length n" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "bd6cd25a-944c-4844-a82d-601c27a17a80", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Adversary with strategy that guesses its not oraculum if last n bits of the message are all zeros\n", + "can be wrong only if oraculum, was used (1/2 chance) and it generated last last n bits of the message all zeros (2^-n)\n", + "Chance of this is 2 to the power of minus (message length + 1)\n", + "With growing n, this function converges to 0 -> F' is not secure PRF\n", + "\n", + "\n", + "We can simulate this, assumming python random is close enough to random oraculum\n", + "For message 4 characters long, its only a 0.0625 chance\n", + "but only if random oracle is selected so times 0.5 -> 0.03125 chance\n", + "adverasry got response: [1, 1, 1, 1, 0, 0, 0, 0]\n", + "he guessed it is not oraculum - its False\n", + "\n", + "adverasry got response: [0, 1, 0, 0, 0, 0, 0, 0]\n", + "he guessed it is not oraculum - its True\n", + "\n", + "adverasry got response: [0, 0, 1, 0, 0, 0, 0, 0]\n", + "he guessed it is not oraculum - its True\n", + "\n", + "adverasry got response: [1, 1, 1, 0, 0, 0, 0, 0]\n", + "he guessed it is not oraculum - its True\n", + "\n", + "adverasry got response: [0, 0, 0, 1, 0, 0, 0, 0]\n", + "he guessed it is not oraculum - its True\n", + "\n", + "adverasry got response: [1, 1, 0, 0, 0, 1, 0, 0]\n", + "he guessed it is oraculum - its True\n", + "\n", + "we can meassure the prediction:\n", + "adversary passed 971 out of 1000 tests, which is 0.029 chance of failure\n" + ] + } + ], + "source": [ + "# no efficient algorithm can distinguish (with significant advantage)\n", + "# between a function chosen randomly from the PRF family and a random oracle\n", + "import random\n", + "import string\n", + "msg_len = 4\n", + "\n", + "def prf1(input):\n", + " return [random.randint(0, 1) for _ in range(len(input))] + [0] * len(input)\n", + "\n", + "def challenger1(input):\n", + " if (random.choice([True, False])): # random oracle\n", + " return [random.randint(0, 1) for _ in range(len(input) * 2)], True\n", + " else: # tested function\n", + " return prf1(input), False\n", + "\n", + "words = [\"abcd\", \"efgh\", \"ijkl\", \"mnop\", \"qrst\", \"uvwx\"]\n", + "def adversary1(w, verbose=True):\n", + " response = challenger1(w)\n", + " if verbose: print(f\"adverasry got response: {response[0]}\")\n", + " \n", + " if all(x == 0 for x in response[0][len(w):]):\n", + " if verbose: print(f\"he guessed it is not oraculum - its {response[1] == False}\\n\")\n", + " return response[1] == False\n", + " else:\n", + " if verbose: print(f\"he guessed it is oraculum - its {response[1] == True}\\n\")\n", + " return response[1] == True\n", + "\n", + "\n", + "print(\"Adversary with strategy that guesses its not oraculum if last n bits of the message are all zeros\")\n", + "print(\"can be wrong only if oraculum, was used (1/2 chance) and it generated last last n bits of the message all zeros (2^-n)\")\n", + "print(\"Chance of this is 2 to the power of minus (message length + 1)\")\n", + "print(\"With growing n, this function converges to 0 -> F' is not secure PRF\\n\\n\")\n", + "\n", + "chance = pow(2,-msg_len)\n", + "print(f\"We can simulate this, assumming python random is close enough to random oraculum\")\n", + "print(f\"For message {msg_len} characters long, its only a {chance} chance\")\n", + "print(f\"but only if random oracle is selected so times 0.5 -> {chance/2} chance\")\n", + "\n", + "for w in words:\n", + " adversary1(w)\n", + "\n", + "tests = 1000\n", + "passed = 0\n", + "print(f\"we can meassure the prediction:\")\n", + "for i in range(0, tests):\n", + " msg = ''.join(random.choices(string.ascii_lowercase, k=msg_len))\n", + " passed += adversary1(msg, False)\n", + "\n", + "print(f\"adversary passed {passed} out of {tests} tests, which is {round(1 - (passed / tests),5)} chance of failure\")" + ] + }, + { + "cell_type": "markdown", + "id": "06d4358a-0216-457a-ab08-3662f1999b89", + "metadata": {}, + "source": [ + "2. F′(k, m∣∣m′) = F(k, m)∣∣F(k, m′ ⊕ 0^n), where 0^n is a zero string of length n" + ] + }, + { + "cell_type": "markdown", + "id": "f99e71fa-a4e2-4396-8072-9621b40700fc", + "metadata": {}, + "source": [ + "Since x ⊕ 0 = x, we can simplify\n", + "F' := F(k, m∣∣m′) = F'(k, m)∣∣F'(k, m′)\n", + "\n", + "With startegy: \n", + "choose message x\n", + "x = a^n (where n is power of 2)\n", + "\n", + "get message y \n", + "if message is repeating bit => adversary guess its not oraculum \n", + "y = F'(a^(n/2) || F'(a^(n/2)) = F'(a^(n/4)) || F'(a^(n/4)) || F'(a^(n/4)) || F'(a^(n/4)) = ... = F'(a)^n\n", + "\n", + "else => guess its oraculum\n", + "\n", + "Only way adversary could be wrong if oraculum generated n repeating bits, chance of this is 2^(-n) \n", + "With growing n, this function converges to 0 -> F' is not secure PRF" + ] + }, + { + "cell_type": "markdown", + "id": "fc89bafe-990c-4a05-9bd4-1c86075f4fcd", + "metadata": {}, + "source": [ + "3. F′(k, m∣∣m′) = F(k, 0∣∣m) ⊕ F(k, m′∣∣1), where m, m′∈ {0, 1}^(n−1)" + ] + }, + { + "cell_type": "markdown", + "id": "7fccba29-9283-448a-83e5-0a9e1dca8864", + "metadata": {}, + "source": [ + "With startegy:\n", + "querying two messages x_1, x_2 \n", + "x_1 = 0^(n-1)||0^(n-1) \n", + "x_2 = 0^(n-1)||1^(n-1) \n", + " \n", + "get messages y_1, y_2 \n", + "\n", + "\n", + "if y_1 ⊕ y_2 == 0^n => adversary guess its not oraculum \n", + "y_1 ⊕ y_2 = (F(k,0||0^(n−1)) ⊕ F(k,0^(n−1)||1)) ⊕ (F(k,0||0^(n−1)) ⊕ F(k,1^(n−1||1)) \n", + "y_1 ⊕ y_2 = F(k,0||1^(n−1)) ⊕ F(k,1^(n−1||1) \n", + " \n", + "else => guess its oraculum \n", + " \n", + "chance of two random oraculum outputs being inverse (y_1 ⊕ y_2 == 0^n) is 2^(-n) \n", + "With growing n, this function converges to 0 -> F' is not secure PRF" + ] + }, + { + "cell_type": "markdown", + "id": "e62ff1ca-3ea5-4f08-9b2d-286966f45a7e", + "metadata": {}, + "source": [ + "## Task 3\n", + "Output feedback mode Consider the following permutation cipher – instead of permuting plaintext letters to get ciphertext, you are first required to convert plaintext letters to binary form and next you\n", + "permute bits according to the key. Letter H becomes encrypted to T with key (5, 1, 2, 4, 3). Let us view it as\n", + "block cipher with block length 5 bits." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "9ca5e5f2-19ae-4d1d-aad1-eecc6b9d07e3", + "metadata": {}, + "outputs": [], + "source": [ + "def perm_enc(pt: list[int], key: list[int]):\n", + " blocksize = 5\n", + " ct = [0] * blocksize\n", + " for idx in range(0, blocksize):\n", + " ct[idx] = pt[key[idx] - 1]\n", + " return ct\n", + "\n", + "def convert_str(pt: list[int]): # converts to list of binary blocks\n", + " bit_array = []\n", + " for char in pt:\n", + " bits = bin(ord(char) - ord('A'))[2:][-5:].zfill(5)\n", + " bit_array.append([int(bit) for bit in bits])\n", + " return bit_array\n", + "\n", + "def ofb(pt, key, iv, cipher):\n", + " ct = []\n", + " for block in pt:\n", + " iv = cipher(iv, key)\n", + " ct.append([x ^ y for (x,y) in zip(iv, block)]) # encrypted iv into block\n", + " return ct\n", + "\n", + "key = [5, 1, 2, 4, 3]" + ] + }, + { + "cell_type": "markdown", + "id": "95d3d5f0-26cc-4adf-ba2f-3e19aac52174", + "metadata": {}, + "source": [ + "1. Encrypt world DOG with key (4, 1, 3, 5, 2) using permutation cipher in OFB mode with iv = 01011. Leave\n", + "result as a binary string." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "63f150c4-cefc-4288-9568-6c0ed4963d7b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "plaintext: [[0, 0, 0, 1, 1], [0, 1, 1, 1, 0], [0, 0, 1, 1, 0]]\n", + "ciphertext: [[1, 0, 0, 0, 0], [1, 0, 1, 0, 0], [1, 1, 1, 1, 1]]\n" + ] + } + ], + "source": [ + "pt = convert_str(['D', 'O', 'G'])\n", + "key = [4, 1, 3, 5, 2]\n", + "iv = [0, 1, 0, 1, 1]\n", + "ct = ofb(pt, key, iv, perm_enc)\n", + "print(f\"plaintext: {pt}\")\n", + "print(f\"ciphertext: {ct}\")" + ] + }, + { + "cell_type": "markdown", + "id": "2e92ea0e-ccab-4eb7-bb0d-5f325fcd8e77", + "metadata": {}, + "source": [ + "2. Flip 5-th bit of received ciphertext (0 becomes 1 and vice versa). Now decrypt modified ciphertext. How\n", + "many bits in the plaintext get changed?" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "ae47fd93-809c-4e03-b565-3d1ebb8f4b42", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "original ciphertext: [[1, 0, 0, 0, 0], [1, 0, 1, 0, 0], [1, 1, 1, 1, 1]]\n", + "modified ciphertext: [[1, 0, 0, 0, 1], [1, 0, 1, 0, 0], [1, 1, 1, 1, 1]]\n", + "original plaintext: [[0, 0, 0, 1, 1], [0, 1, 1, 1, 0], [0, 0, 1, 1, 0]]\n", + "modified plaintext: [[0, 0, 0, 1, 0], [0, 1, 1, 1, 0], [0, 0, 1, 1, 0]]\n", + "one bit also flipped -> no diffusion\n" + ] + } + ], + "source": [ + "import copy\n", + "ct2 = copy.deepcopy(ct)\n", + "ct2[0][4] ^= 1\n", + "pt2 = ofb(ct2, key, iv, perm_enc)\n", + "\n", + "print(f\"original ciphertext: {ct}\")\n", + "print(f\"modified ciphertext: {ct2}\")\n", + "print(f\"original plaintext: {pt}\")\n", + "print(f\"modified plaintext: {pt2}\")\n", + "print(f\"one bit also flipped -> no diffusion\")" + ] + }, + { + "cell_type": "markdown", + "id": "dd8b801d-8bcc-49dc-8ad1-b0d54ce62959", + "metadata": {}, + "source": [ + "3. Flip the first bit of the IV iv′ = 11011, decrypt ciphertext from Step 1 with iv′\n", + ". How many bits in the\n", + "plaintext get changed?" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "a358aa91-7e8a-4ada-82f0-58fdb7aa30a9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "original plaintext: [[0, 0, 0, 1, 1], [0, 1, 1, 1, 0], [0, 0, 1, 1, 0]]\n", + "modified plaintext: [[0, 1, 0, 1, 1], [0, 1, 1, 1, 1], [0, 0, 1, 0, 0]]\n", + "one bit per block also flipped\n" + ] + } + ], + "source": [ + "iv[0] ^= 1\n", + "pt3 = ofb(ct, key, iv, perm_enc)\n", + "\n", + "print(f\"original plaintext: {pt}\")\n", + "print(f\"modified plaintext: {pt3}\")\n", + "print(f\"one bit per block also flipped\")" + ] + }, + { + "cell_type": "markdown", + "id": "fc3e1681-f07b-4546-bc30-688753fcbd53", + "metadata": {}, + "source": [ + "## Task 4\n", + "Consider the encryption of n−block message m = m1∣∣m2∣∣. . .∣∣m_n by some block cipher E in\n", + "CFB mode. Let use denote ciphertext produced by E as c = c1∣∣c2∣∣. . .∣∣cn. Show which information about\n", + "the plaintext can be extracted if we get a collision: ci = cj\n", + ", where i ≠ j." + ] + }, + { + "cell_type": "markdown", + "id": "7134ee9b-fcc0-4d6e-a240-208707160694", + "metadata": {}, + "source": [ + "#### In OFB mode: \n", + "Ek(iv)^n := Ek( Ek( ... Ek(iv))) n times\n", + "ct_n = pt_n ⊕ Ek(iv)^n\n", + "\n", + "ct_i == ct_j implies => \n", + "Ek(iv)^i == Ek(iv)^j => \n", + "pt_i ⊕ pt_j == Ek(iv)^(i-1) ⊕ Ek(iv)^(j-1)" + ] + }, + { + "cell_type": "markdown", + "id": "7e65fe31-62e3-4c6c-a7a8-e29ee8dc9e57", + "metadata": {}, + "source": [ + "## Task 5\n", + "Show that Pigpen cipher defined below is not IND-OT-CPA secure (where adversary is allowed to\n", + "do only one query to the challenger in the IND-CPA game).\n", + "The pigpen cipher uses graphical symbols assigned according to a key in the diagram below1\n", + "(NOTE: Positions\n", + "of the letters in the diagrams are random and not known to adversary):" + ] + }, + { + "cell_type": "markdown", + "id": "296118e7-4df4-451f-8b27-9a317c04d362", + "metadata": {}, + "source": [ + "#### Indistinguishability under One-Time Chosen Plaintext Attack definition:\n", + "1. The challenger generates a secret key K\n", + "2. The adversary submits two distinct plaintexts Pt_0, Pt_1 of equal length to the challenger\n", + "3. The challenger selects a random bit b ∈ {0,1}, resulting in ciphertext Ct = Ek(M_b) being sent to the adversary\n", + "4. Based on the Ct, the adversary guess b′ ∈ {0,1} for the value of b\n", + "5. Scheme is not secure if no adversary has a non-negligible advantage in guessing over 1/2\n", + "\n", + "#### Adversary strategy:\n", + "We can expoit Pigpen cipher being monoalphabetic\n", + "Adversary will send one message with repeating characters and another with each character unique \n", + "M_0 := \"AA\" \n", + "M_1 := \"AB\" \n", + "\n", + "If Ct is some repeating characters => choose 0 \n", + "Else => choose 1 \n", + "\n", + "This strategy will work every time thanks to monoalphabeticity" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/hw3/Screenshot_11-Apr_12-46-16_5589.png b/hw3/Screenshot_11-Apr_12-46-16_5589.png new file mode 100644 index 0000000..950e6da Binary files /dev/null and b/hw3/Screenshot_11-Apr_12-46-16_5589.png differ diff --git a/hw3/homework 3.ipynb b/hw3/homework 3.ipynb new file mode 100644 index 0000000..59528d8 --- /dev/null +++ b/hw3/homework 3.ipynb @@ -0,0 +1,435 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "04af88ae-4585-44f4-8a6b-e54ef1b369fc", + "metadata": {}, + "source": [ + "Ondřej Hladůvka" + ] + }, + { + "cell_type": "markdown", + "id": "81c9f10b-5df5-4187-9be5-913c536fdb27", + "metadata": {}, + "source": [ + "# Task 1\n", + "You are working in the company that uses RSA cryptosystem in their solutions.\n", + "You have been sent the following abstract for the scientific paper. Based on this, would your recommendation to your company and why? \n", + "" + ] + }, + { + "cell_type": "markdown", + "id": "19cec4fd-90ac-4255-9add-9a48879f5b89", + "metadata": {}, + "source": [ + "RSA key generation: \n", + "let $p,q$ be large primes \n", + "$n := p \\times q$ \n", + "let $e$ be integer $1 < e < \\text{Lcm}(\\varphi(p, q))$ \n", + "$d := e^{-1} \\pmod{\\varphi(n)}$ \n", + "\n", + "Private key := $(d, n)$ \n", + "Public key := $(e, n)$ \n", + "\n", + "------------------------------------\n", + "\n", + "It is correct that $\\varphi(n)$ for public $n$ is used to generate $d$ (using EEA), so attacker able to compute it could break an encryption.\n", + "\n", + "Another thing that attacker could do knowing $n$ and $\\varphi(n)$ is to compute primes $p, q$:\n", + "$$\n", + "\\varphi(n) = \\varphi(p \\times q) = (p-1)(q-1) = p \\times q - p - q + 1 = (n+1)-(p+q)\n", + "$$\n", + "$$\n", + "\\Rightarrow p+q = (n+1)-\\varphi(n)\n", + "\\,\\,\\,\\,\\, \\land \\,\\,\\,\\,\\,\n", + "p \\times q = n\n", + "$$\n", + "$$\n", + "\\Rightarrow p+q -(n+1)+\\varphi(n) = 0\n", + "\\,\\,\\,\\,\\, \\land \\,\\,\\,\\,\\,\n", + "p \\times q - n = 0\n", + "$$\n", + "this forms system of equations, \n", + "lets substitute $p := (n+1)-\\varphi(n) - q$:\n", + "$$\n", + "((n+1)-\\varphi(n) - q) \\times q - n = 0\n", + "$$\n", + "Solving for $q$:\n", + "$$\n", + "q = \\frac{n}{(n+1)-\\varphi(n)-q}\n", + "$$\n", + "$$\n", + "p = \\frac{n}{q} \\text{ (where } p \\text{ and } q \\text{ can be swapped)}\n", + "$$\n", + "\n", + "This proves that factorization of $n$ is trivial when $\\varphi(n)$ is known, thus computing $\\varphi(n)$ has to be at least as difficult as computing factorization of $n$\n", + "\n", + "And when we know primes $p$ and $q$, computing $\\varphi(n)$ is just $(p-1)(q-1)$ $\\Rightarrow$ computing $\\varphi(n)$ is as difficult as computing factorization of $n$ \n", + " \n", + "#### I would not make any change based on this arcicle, as RSA is based on diffclty of computing $\\varphi(n)$" + ] + }, + { + "cell_type": "markdown", + "id": "5748beac-4e59-4211-aa41-8175b332bef4", + "metadata": {}, + "source": [ + "# Task 2\n", + "Suppose you are given the following encryption scheme: \n", + "$KeyGen()∶$\n", + "1. Sample large prime number $p$\n", + "2. Compute modulus as $n := p^2$\n", + "3. Select $e$ to be integer such that \n", + "$Gcd(\\varphi(n), e) = 1 \n", + "\\,\\,\\,\\,\\, \\land \\,\\,\\,\\,\\,\n", + "2 < e < \\varphi(n)$\n", + "4. Calculate $d$ such that $e \\times d ≡ 1 \\, mod \\, \\varphi(n)$\n", + "5. Return private key $Sk := (d, n)$ and \n", + " public key $Pk = (e, n)$ \n", + "\n", + "$Enc(Pk, Pt)∶$\n", + "1. Compute ciphertext as $Ct = Pt^e \\, (mod \\,\\, n)$\n", + " \n", + "$Dec(Sk, Ct)∶$\n", + "1. Compute decryption as $Pt = Ct^d \\, (mod \\,\\, n)$\n", + "\n", + "provide an attack that shows that given encryption scheme is not secure with respect to the\n", + "IND-OT-CPA security definition." + ] + }, + { + "cell_type": "markdown", + "id": "3029803a-82e5-45a9-b5c9-a6373af60ee7", + "metadata": {}, + "source": [ + "#### Indistinguishability under One-Time Chosen Plaintext Attack:\n", + "1. Challenger generates a key $k$\n", + "1. Adversary submits two equal-length messages $m_0, m_1$\n", + "1. Challenger flips a random bit $b \\gets \\{0,1\\}$ and returns $Enc(k, m_b)$\n", + "1. Adversary guesses $b$ \n", + "The scheme is IND-OT-CPA secure if this advantage is negligible for all adversaries \n", + "-------------------------------------------\n", + "Knowing $n$ is square, adversary can calculate \n", + "$$\n", + "\\varphi(n) = n^2 - n\n", + "$$\n", + "there are $p^2$ total integers from $1$ to $p^2$ \n", + "out of these, the numbers that are not relatively prime to $p^2$ are the multiples of $p, 2p, 3p ... p^2$\n", + "and there are exactly $p$ such multiples. \n", + "\n", + "With $\\varphi(n)$ obtained, adversary can compute $d \\equiv e^{-1} (mod \\,\\, \\varphi(n))$ the same way challanger did. \n", + " \n", + "#### Attack\n", + "Adversary's strategy:\n", + "1. Adversary will sens two distinct messages $m_0, m_1$ and recieves compute $Ct$ and $Pk = (e, n)$\n", + "2. Computes $\\varphi(n) = n^2 - n$\n", + "3. Computes $d = e^{-1} \\, (mod \\,\\, \\varphi(n))$\n", + "4. Decrypts $Pt = Ct^d \\, (mod \\,\\, n)$\n", + "5. Comares $Pt$ against $m_0, m_1$ and select which plaintext was encrypted\n", + "\n", + "##### Adversary will win every time => scheme is not IND-OT-CPA secure" + ] + }, + { + "cell_type": "markdown", + "id": "b911e6e5-1a14-47d4-8322-4ee26318db8e", + "metadata": {}, + "source": [ + "# Task 3\n", + "#### Consider the ElGamal cryptosystem with a public key $h$ and a private key $x$ \n", + "\n", + "let cyclic group $G$ of order $q$, with generator $g$ and identity element $e$. And all operation on this group... \n", + "let message $m \\in G$ \n", + "public key $h := g^x$ \n", + "shared secret $s := h^y = (g^x)^y = g^{x \\times y}$ \n", + "$c_1 := g^y$ \n", + "$c_2 := m \\times s$" + ] + }, + { + "cell_type": "markdown", + "id": "f9d7ddb7-045e-434a-8af3-d3291a57e08c", + "metadata": {}, + "source": [ + "1. Assume that you are given a ciphertext $(c_1, c_2)$ encrypting an unknown message $m$. Show how you can generate a new ciphertext $(c_1', c_2')$ that encrypts the same $m$, but with different randomness $y'$ (without decrypting the ciphertext)" + ] + }, + { + "cell_type": "markdown", + "id": "d3202508-ecae-4fa8-af4f-b09b842f2bd3", + "metadata": {}, + "source": [ + "ElGamal decryption principle:\n", + "$$\n", + "s \\times c_1^{q-x} = g^{x \\times y} \\times {(g^y)}^{q-x} = g^{x \\times y} \\times g^{y(q-x)} = g^{x \\times y + y \\times q - x \\times y} = g^{y \\times q} = {(g^q)}^y = e^y = e\n", + "$$\n", + "$$\n", + "\\Rightarrow s^{-1} = c_1^{q-x}\n", + "$$\n", + "$$\n", + "m = c_2 \\times s^{-1} = m \\times s \\times s^{-1}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "dc716837-53fb-4f8c-92d5-38ccdb49d317", + "metadata": {}, + "source": [ + "to get the same message from different ct\n", + "$$\n", + "m = c_2{'} \\times s^{-1}{'} = c_2{'} \\times ({c_1'})^{q-x}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "28980583-2777-4a56-a4f4-9c251070eb80", + "metadata": {}, + "source": [ + "we can modify messages with any pair $k, l$ \n", + "$c_1{'} := c_1 \\times k$ \n", + "$c_2{'} := c_2 \\times l$\n", + "$$\n", + "m = c_2{'} \\times {(c_1{'})}^{q-x} = c_2 \\times l \\times {(c_1 \\times k)}^{q-x} = c_2 \\times l \\times {c_1}^{q-x} \\times {k}^{q-x}\n", + "$$\n", + "with relation $l \\times {k}^{q-x} = e$, but we dont know private exponent $x$\n" + ] + }, + { + "cell_type": "markdown", + "id": "c38e621f-392c-4b20-8102-8952c7fb2fc3", + "metadata": {}, + "source": [ + "this can be achived with $k := g^z$ for any choosen $z \\in G$\n", + "$$\n", + "c_1{'} = c_1 \\times g^z = g^y \\times g^z = g^{y+z}\n", + "$$ \n", + "$$\n", + "s{'} = c_1^{x} = {g}^{x(y+z)} = {g}^{xy+xz}\n", + "$$\n", + "$$\n", + "\\frac{c_2{'}}{c_2} = \\frac{m \\times s{'}}{m \\times s} = \\frac{s{'}}{s} = g^{xz} = \\frac{c_2 \\times l}{c_2} = l\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "71d98453-5695-4942-bee9-8441e95051b0", + "metadata": {}, + "source": [ + "2. Assume you are given ciphertext $c = (c1, c2)$ that you wants to decrypt, but you do not know corresponding private key $sk$. Suppose that you have a friend who provides you with the decryption of any other chosen ciphertext $c{'} \\not= c$ using private key $sk$. Show how can you decrypt $c$." + ] + }, + { + "cell_type": "markdown", + "id": "67b945b1-553a-405a-8daa-e797a3f9616f", + "metadata": {}, + "source": [ + "We can choose any $c'$ to decipher $m$\n", + "$$\n", + "\\frac{c_2}{c_2{'}} = \\frac{m \\times s}{m{'} \\times s} = \\frac{m}{m{'}}\n", + "$$\n", + "$$\n", + "\\Rightarrow m = m{'} \\times \\frac{c_2}{c_2{'}}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "cd4f9b24-52d6-407d-a9e2-769b6dba6a54", + "metadata": {}, + "source": [ + "3. Assume you are given two ciphertexts $ct_1 = (c_{11}, c_{12})$ and $ct_2 = (c_{21}, c_{22})$ that correspond to some\n", + "plaintext messages (not known to you) $m_1$ and $m_2$. What information can you learn about $m_1$ and $m_2$, if you observe that $c_{11} = c_{21}$?" + ] + }, + { + "cell_type": "markdown", + "id": "b95d2854-1d8c-40f8-a69e-eb35f5d19ee8", + "metadata": {}, + "source": [ + "$$\n", + "1 = \\frac{c_{11}}{c_{12}} = \\frac{g^{y_1}}{g^{y_2}} = g^{y_1 - y_2}\n", + "$$\n", + "$$\n", + "\\Rightarrow y_1 = y_2\n", + "$$\n", + "$$\n", + "\\Rightarrow h^{y_1} = h^{y_2}\n", + "$$\n", + "$$\n", + "\\frac{c_{12}}{c_{22}} = \\frac{m_1 \\times h^{y_1}}{m_2 \\times h^{y_2}} = \\frac{m_1}{m_2}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "id": "44a536aa-8f2a-4234-a88e-ae020f560d94", + "metadata": {}, + "source": [ + "4. Bring an example of potential application of ElGamal encryption scheme, where homomorphic property is useful and another example, where it violates the desired security of the application. Justify your answer." + ] + }, + { + "cell_type": "markdown", + "id": "1a8ce5ba-477e-4be8-b6f1-697da610487a", + "metadata": {}, + "source": [ + "- Desired application could multiply messages from multiple senders and decrypt result to protect privacy of them but get the product of all \n", + "- Undesired applicatio would be for example online auction where adversary could manipulate offers" + ] + }, + { + "cell_type": "markdown", + "id": "a2238cd4-1944-4139-909c-ae984776d407", + "metadata": {}, + "source": [ + "# Task 4\n", + "You have intercepted two RSA ciphertexts $c_1 = 7$ and $c_2 = 16$ that correspond to the same plaintext – a promo code for the video game. You know that those ciphertexts have been created using corresponding public keys $pk_1 = (e = 3, n = 57)$ and $pk_2 = (e = 5, n = 57)$. What is the promo code m from the intercepted ciphertext? \n", + "Note: for this attack, your task is not to find the private key!" + ] + }, + { + "cell_type": "markdown", + "id": "a8d3026a-1b29-4339-9548-d889871ad68e", + "metadata": {}, + "source": [ + "${\\lvert m^{3} \\rvert}_{57} \\equiv 7$ \n", + "${\\lvert m^{5} \\rvert}_{57} \\equiv 16$ " + ] + }, + { + "cell_type": "markdown", + "id": "e8358104-d161-4617-9f36-761e80cf6d63", + "metadata": {}, + "source": [ + "${\\lvert m^{3} \\rvert}_{57} \\equiv 16$ \n", + "${\\lvert 7 \\times m^{2} \\rvert}_{57} \\equiv 16$ \n", + "${\\lvert 7^{-1} \\times 7 \\times m^{2} \\rvert}_{57} \\equiv 16 \\times 7^{-1}$ \n", + "${\\lvert m^{2} \\rvert}_{57} \\equiv 43$ \n", + "${\\lvert \\sqrt{m} \\rvert}_{57} \\equiv \\{10, 28, 29, 47\\}$ " + ] + }, + { + "cell_type": "markdown", + "id": "82b4dbb3-218a-47a2-a623-8961451298cd", + "metadata": {}, + "source": [ + "${\\lvert {28}^{3} \\rvert}_{57} \\equiv 7$ \n", + "${\\lvert {28}^{5} \\rvert}_{57} \\equiv 16$ \n", + "$ m = 28$" + ] + }, + { + "cell_type": "markdown", + "id": "682d50fa-6ab4-4f8e-9c25-d11fea9f2b74", + "metadata": {}, + "source": [ + "# Task 5\n", + "Your company is building a product that heavily relies on\n", + "usage of cryptography. You receive the following list of security requirements for the system" + ] + }, + { + "cell_type": "markdown", + "id": "6fd52e32-8336-45a9-8f2b-ea7f741603e2", + "metadata": {}, + "source": [ + "1. System should ensure data confidentiality and integrity in transmission \n", + "**Scheme: TLS 1.3 with AES-256-GCM or ChaCha20-Poly1305 256-bit** \n", + " $\\to$ Both provide confidentiality and integrity in single pass \n", + " $\\to$ ChaCha20 is efficient in software and resistant to timing attacks \n", + " $\\to$ AES-256 ia accelerated on almost every CPU, AES-NI instructions mitigate side-channel risks \n", + " $\\to$ TLS 1.3 removes deprecated ciphers (RC4 etc..), but may not be supported on older platforms (typically embedded devices) \n", + " using TLS 1.2 and whitelisting only secure ciphers may be option too\n", + " \n", + "3. System should ensure data confidentiality and integrity at rest \n", + "**Scheme: AES-256-XTS with HMAC-SHA-256** \n", + " $\\to$ AES-256 is resistant to brute-force attacks (even with quantum computing, Grover's algorithm would require ~$2^128$ operations) \n", + " $\\to$ XTS Encrypts each sector independently to avoids performance penalties for random I/O operations, but keeps diffusion advantage of chaining modes \n", + " $\\to$ HMAC-SHA-256 ensures integrity and can be backupped separately to ensure backup wasnt tampered with\n", + " \n", + "3. System should enforce strong authentication mechanisms for users and services to ensure that only authorized entities can access the data \n", + "**Scheme for user authentication: pow password hashing + Ed25519** \n", + " $\\to$ Argon2id is designed to not be comutable on FPGA and can be configured (iterations, memory, parallelism) to match requrements\n", + " $\\to$ Passwords should be salted before hashing and never stored as plaintext \n", + " $\\to$ Ed25519 signature can be stored on hardware authenticator providing second factor to the password \n", + " **Scheme for service to service authentication: mTLS Ed25519 256bit** \n", + " $\\to$ Mutual certificate based authentication for every two points in infrastructure \n", + " $\\to$ Ed25519 with 256-bit key comparable secure as RSA with 3072-bit key, but much cheaper to compute - saving cost on the infrastrucure \n", + "4. System must be resistant to common attacks, including side-channel attacks and brute force attacks, using strong cryptographic primitives and practices \n", + "**Mitigation of common attacks:** \n", + " $\\to$ AES-NI instructions to resis power analysis with 256-bit key to resis brute force \n", + " $\\to$ TLS 1.3 insted of 1.2 to not even include insecure schemes in the transport protocol \n", + " $\\to$ XTS mode and HMAC to mitigate tampering with data at rest\n", + " $\\to$ Argon2id for password hashing and salting to resist dictionary and bruteforce FPGA attacks in case hashes got leaked \n", + " $\\to$ Ed25519 to resist simple RSA power analysis " + ] + }, + { + "cell_type": "markdown", + "id": "2226a20b-4e40-4f57-881f-9ba9658ce358", + "metadata": {}, + "source": [ + "## Bonus Task\n", + "Show that exponential ElGamal (where the ciphertext is constructed as $c = (c_1, c_2) = (g^y, g^m \\times s)$ is not IND-CCA2 secure. You are allowed to make single encryption query and single decryption\n", + "query to the challenger." + ] + }, + { + "cell_type": "markdown", + "id": "cc53f0ce-b56b-4560-ab2a-ead78a0f80a9", + "metadata": {}, + "source": [ + "#### Indistinguishability under adaptive chosen-ciphertext attack \n", + "1. The challenger generates a key pair $Pk, Sk$, and publishes $PK$ to the adversary\n", + "2. The adversary may perform any number of calls to the encryptions and decryption oracle based on arbitrary ciphertexts\n", + "3. Eventually, the adversary submits two distinct chosen plaintexts $m_0, m_1$ to the challenger.\n", + "4. The challenger selects a bit $b \\gets \\{0, 1\\}$ uniformly at random, and sends the ciphertext $c = E(Pk, M_b)$ back\n", + "5. The adversary is free to perform any number of additional computations or encryptions and may make further calls to the decryption oracle\n", + "7. Adversary guesses $b$\n", + " \n", + "A scheme is IND-CCA2–secure secure if this advantage is negligible for all adversaries" + ] + }, + { + "cell_type": "markdown", + "id": "b89d823e-919a-4426-a860-9474b55918a5", + "metadata": {}, + "source": [ + "#### Adversary's startegy\n", + "1. Challenger computes a public key $h := g^x$\n", + "2. Adversary selects two messages $m_0, m_1$\n", + "3. Challenger responds with $Ct = (c_0, c_1) = (g^y, g^{m_b} \\times h^y)$\n", + "4. Adversary chooses $k \\in N$ computes and submits $Ct{'} := (c_0, c_1 \\times g^k)$ for decryption\n", + "5. Oracle returns $D(Ct{'}) = \\frac{c_1 \\times g^k}{{c_0}^x} = \\frac{g^{m_b} \\times h^y \\times g^k}{g^{y \\times x}} = \\frac {g^{m_b} \\times h^y \\times g^k}{h^y} = g^{m_b + k}$\n", + "6. Adversary computes $g^{m_0 + k}$ and $g^{m_1 + k}$, compares them to decrypted $Ct{'}$\n", + "since $m_0, m_1, k$ are known to the Adversary, he will always succeed $\\Rightarrow$ exponential ElGamal is not IND-CCA2 secure" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/hw3/run.sh b/hw3/run.sh new file mode 100755 index 0000000..3e122ca --- /dev/null +++ b/hw3/run.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +docker run -p 8888:8888 \ + -v "$(pwd)":/work \ + jupyter \ No newline at end of file