diff --git a/TTM4135.ipynb b/TTM4135.ipynb index 401bc1f..fa460e6 100644 --- a/TTM4135.ipynb +++ b/TTM4135.ipynb @@ -1,5 +1,12 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -223,9 +230,7 @@ "metadata": {}, "source": [ "# Euler function Ļ† and Z*n\n", - "From slides 2020-4135-l07 - Number Theory for Public Key Cryptography\n", - "\n", - "> $\\phi(16) = \\phi(2^{4}) = 16*\\left(1-\\frac{1}{2}\\right)$" + "From slides 2020-4135-l07 - Number Theory for Public Key Cryptography\n" ] }, { @@ -593,14 +598,13 @@ "# Square and multiply\n", "from math import log, floor\n", "\n", - "def square_and_multiply(y,e,n, verbose=True):\n", + "def square_and_multiply(y,e,n, verbose=False):\n", " # prep\n", " e_bin = bin(e)[:1:-1] # e0, e1, e2, e3, ... , ek\n", " k = len(e_bin)\n", " z = 1\n", " yi = y\n", " indices = []\n", - " # -------------\n", "\n", " for i in range(k):\n", " ei = int(e_bin[i])\n", @@ -611,12 +615,10 @@ " if ei:\n", " indices.append(i)\n", "\n", - " # post calc\n", - " mults = str(e_bin).count(\"1\") - 1\n", - " squarings = floor( log(e, 2) )\n", - " # -------------\n", - "\n", " if verbose:\n", + " mults = str(e_bin).count(\"1\") - 1\n", + " squarings = floor( log(e, 2) )\n", + "\n", " print(f\"{' * '.join([f'{y}^({2**i})' for i in indices])}\")\n", " print(f\"squarings: {squarings}\")\n", " print(f\"mults: {mults}\")\n", @@ -630,7 +632,7 @@ "e = 102900819\n", "n = 604604729\n", "\n", - "z = square_and_multiply(y,e,n, True)\n", + "z = square_and_multiply(y,e,n, verbose=True)\n", "\n", "print(f\"{y}^{e} mod({n}) = {z}\")" ] @@ -702,16 +704,144 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Block ciphers\n", + "# RSA\n", "\n", - "Notation:\n", + "### Key generation\n", "\n", - "- `P`: Plaintext block (length n bits) \n", - "- `C`: Ciphertext block (length n bits) \n", - "- `K` : Key (length k bits)\n", - "- `C = E(P, K)`: Encryption function \n", - "- `P = D(C, K)`: Decryption function\n", - "- `IV`: Initialisation vector" + "1. Let $p$ and $q$ be distinct prime numbers, randomly chosen from the set of all prime numbers of a certain size.\n", + "2. Compute $n = pq$.\n", + "3. Select $e$ randomly with $gcd(e, \\varphi(n)) = 1$.\n", + "4. Compute $d = eāˆ’1 \\mod \\varphi(n)$.\n", + "5. The public key is the pair $n$ and $e$.\n", + "6. The private key consists of the values $p$, $q$ and $d$.\n", + "\n", + "### Encryption\n", + "\n", + "The public key for encryption is $KE = (n, e)$\n", + "1. Input is any value $M$ where $0 < M < n$. \n", + "2. Compute $C = E(M,KE) = Me mod n$.\n", + "\n", + "### Decryption\n", + "\n", + "The private key for decryption is KD = d (values p and q are not used here).\n", + "1. Compute D(C,KD) = Cd mod n = M." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "p=43, q=59, n=2537, šœ‘(n)=2436, e=5, d=1949\n", + "\n", + "Public key: n=2537, e=5\n", + "Private key: p=43, q=59, d=1949\n", + "\n", + "{'n': 2537, 'e': 5, 'p': 43, 'q': 59, 'd': 1949}\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "def rsa_keygen(p=None, q=None, e=None, prime_range=1000, verbose=False):\n", + " # Generate a set of primes. In practice, this should be\n", + " # a large number of large primes.\n", + " primes = [i for i in range(0,prime_range) if is_prime(i)]\n", + "\n", + " if not p: p = random.choice(primes)\n", + " if not q: q = random.choice(primes)\n", + " n = p*q\n", + "\n", + " # Euler function šœ‘(n) \n", + " phi_n = totient(n)\n", + "\n", + " # Select e randomly with gcd(e, Ļ†(n)) = 1.\n", + " if not e: e = random.randint(1, phi_n)\n", + " while not gcd(e, phi_n) == 1:\n", + " e = random.randint(1,phi_n)\n", + "\n", + " # Compute d = eāˆ’1 mod Ļ†(n).\n", + " d = inverse(e, phi_n)\n", + " \n", + " if verbose:\n", + " print(f\"p={p}, q={q}, n={n}, šœ‘(n)={phi_n}, e={e}, d={d}\\n\")\n", + " print(f\"Public key: n={n}, e={e}\")\n", + " print(f\"Private key: p={p}, q={q}, d={d}\\n\")\n", + "\n", + " return {\"n\":n, \"e\":e, \"p\":p, \"q\":q, \"d\":d}\n", + "\n", + "# Example from slides\n", + "rsa_keys = rsa_keygen(p=43, q=59, e=5, verbose=True)\n", + "\n", + "# Random keys\n", + "#rsa_keys = rsa_keygen(verbose=True)\n", + "print(rsa_keys)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "C = M^e (mod n) = 50^102900819 (mod 604604729) = 2488\n", + "\n", + "Ciphertext: 2488\n" + ] + } + ], + "source": [ + "def rsa_encrypt(M, rsa_keys):\n", + " # e and n are the public key\n", + " e = rsa_keys['e']\n", + " n = rsa_keys['n']\n", + "\n", + " # C = M^e (mod n)\n", + " return square_and_multiply(M,e,n)\n", + "\n", + "M = 50\n", + "C = rsa_encrypt(M, rsa_keys)\n", + "print(f\"C = M^e (mod n) = {M}^{e} (mod {n}) = {C}\\n\")\n", + "print(f\"Ciphertext: {C}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "M = C^d (mod n) = 2488^1 (mod 604604729) = 50\n", + "\n", + "Message: 50\n" + ] + } + ], + "source": [ + "def rsa_decrypt(C, rsa_keys):\n", + " # private key\n", + " p = rsa_keys['p']\n", + " q = rsa_keys['q']\n", + " d = rsa_keys['d']\n", + " n = p*q\n", + "\n", + " # M = C^d (mod n)\n", + " return square_and_multiply(C,d,n)\n", + "\n", + "M = rsa_decrypt(C, rsa_keys)\n", + "print(f\"M = C^d (mod n) = {C}^{d} (mod {n}) = {M}\\n\")\n", + "print(f\"Message: {M}\")" ] } ],