Fiestel cipher
{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "Feistel.ipynb", "provenance": [], "collapsed_sections": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "oYa8VRxRkulW" }, "source": [ "" ] }, { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "1heHIn1ulCYQ", "outputId": "3447c46c-4b2f-4c03-f693-a4959c5c4b55" }, "source": [ "# we can define byte sequences and variables in Python using the b prefix\r\n", "# For example a byte value of 00111010 canb be shown in hex digits as 3A and in python as\r\n", "byte1 = b'\\x9a\\x79\\x45'\r\n", "byte2 = b'\\x8c'\r\n", "print(byte1,byte2)" ], "execution_count": null, "outputs": [ { "output_type": "stream", "text": [ "b'\\x9ayE' b'\\x8c'\n" ], "name": "stdout" } ] }, { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "CHnM9lbNmIvg", "outputId": "079c2bbd-9fb5-429a-cce8-51a14dfda626" }, "source": [ "# another helpful list operation in python:\r\n", "# You can construct lists with short hand notations involving for loops. For example if I want to convert a string to a list, I can construct a list\r\n", "# with each of its elements taken from one character in the input string, all in one line\r\n", "inputstr = \"my string\"\r\n", "# I want ot construct ['m', 'y', ' ', 's', ..., 'g']\r\n", "# instead of \r\n", "#mylist = []\r\n", "#for c in inputstr:\r\n", "# mylist.append(c)\r\n", "# I can have\r\n", "mylist = [a for a in inputstr]\r\n", "print(mylist)\r\n" ], "execution_count": null, "outputs": [ { "output_type": "stream", "text": [ "['m', 'y', ' ', 's', 't', 'r', 'i', 'n', 'g']\n" ], "name": "stdout" } ] }, { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "GUmroY2ioD1f", "outputId": "a7b79ad4-abea-46fd-f73d-a0da18c7ce40" }, "source": [ "# Now we can define a simple function to perform bitwise XOR on two byte sequences\r\n", "b1 = b'\\xaa\\x33'\r\n", "b2 = b'\\xcc\\x55'\r\n", "# 1010101000110011\r\n", "# 1100110001010101\r\n", "# 0110011001100110\r\n", "# \\x66\\x66\r\n", "def xor(byteseq1, byteseq2):\r\n", " #print(byteseq1)\r\n", " #print(byteseq2)\r\n", " # Python already provides the ^ operator to do xor on interger values\r\n", " # but first we need to break our input byte sequences into bye size integers\r\n", " l1 = [b for b in byteseq1]\r\n", " l2 = [b for b in byteseq2]\r\n", " l1attachl2 = zip(l1,l2)\r\n", " # zip(l1,l2) is actually a list as [(b'\\xaa',b'\\xcc), (b'\\x33', b'\\x55')]\r\n", " #print(l1)\r\n", " #print(l2)\r\n", " #print(l1attachl2)\r\n", "\r\n", " l1xorl2 = [bytes([elem1^elem2]) for elem1,elem2 in l1attachl2]\r\n", " #print(l1xorl2)\r\n", "\r\n", " result = b''.join(l1xorl2)\r\n", " #print(result)\r\n", "\r\n", " return result\r\n", "\r\n", "xor(b1,b2)" ], "execution_count": null, "outputs": [ { "output_type": "stream", "text": [ "b'\\xaa3'\n", "b'\\xccU'\n", "[170, 51]\n", "[204, 85]\n", "<zip object at 0x7f92c9b11948>\n", "[b'f', b'f']\n", "b'ff'\n" ], "name": "stdout" } ] }, { "cell_type": "markdown", "metadata": { "id": "V3HPgLuFsjb_" }, "source": [ "" ] }, { "cell_type": "code", "metadata": { "id": "659iGv9Jsn-8", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "ffb373c0-7faf-4015-def5-e4f2ceb650ea" }, "source": [ "# we want to define the main building block of the feistel cipher as a function with 3 inputs and 2 outputs\r\n", "def feistel_block(LE_inp, RE_inp, k):\r\n", " # Does the necessary operations\r\n", "\r\n", "\r\n", " return LE_out, RE_out\r\n", "\r\n", "# As we discussed, feistel operation doesn't depend on the choice of the F function (its encryption strength does)\r\n", "# Let's all use the same function that uses a good mixing operation using hash functions that we will learn later\r\n", "import hmac\r\n", "import hashlib\r\n", "import random\r\n", "\r\n", "def F(byteseq, k):\r\n", " # we use the hmac hash (don't worry about the meaning for now)\r\n", " h = hmac.new(k, byteseq, hashlib.sha1)\r\n", " # return the first 8 bytes of the hash value\r\n", " return h.digest()[:8]\r\n", "\r\n", "#foutput = F(b'\\x23', b'\\x45')\r\n", "#print(foutput)\r\n", "\r\n", "# In a real Feistel implementation, different keys are used in different rounds. Here\r\n", "# we use 64bit keys so for 16 rounds, we need 16 random 8byte keys. We can just generate\r\n", "# 16 random 8 byte numbers we use the random.randint() function to be able to set the seed\r\n", "# value and create the same keys for both the encoder and the decoder\r\n", "def gen_keylist(keylenbytes, numkeys, seed):\r\n", " # We need to generate numkeys keys each being keylen bytes long\r\n", " keylist = []\r\n", " random.seed(seed)\r\n", " \r\n", " # Use the random.randint(min,max) function to generate individual\r\n", " # random integers in range [min, max]. Generate a list of numkeys\r\n", " # random byte sequences each of them keylenbytes bytes long to be used as \r\n", " # keys for numkeys stages of the feistel encoder. To make sure we have control over\r\n", " # the generated random numbers meaning that the same sequence is \r\n", " # generated in different runs of our program, \r\n", " \r\n", " # keylist = [numkeys elements of 'bytes' type and keylenbytes bytes long each]\r\n", " keylist = []\r\n", " for i in range(numkeys):\r\n", " bytelist = b''.join([bytes([random.randint(0,255)]) for x in range(keylenbytes)])\r\n", " keylist.append(bytelist)\r\n", "\r\n", " return keylist\r\n", "\r\n", "# Now the actual encoder\r\n", "def feistel_enc(inputbyteseq, num_rounds, seed):\r\n", " # This is the function that accepts one bloc of plaintext\r\n", " # and applies all rounds of the feistel cipher and returns the\r\n", " # cipher text block. \r\n", " # Inputs:\r\n", " # inputblock: byte sequence representing input block\r\n", " # num_rounds: integer representing number of rounds in the feistel \r\n", " # seed: integer to set the random number generator to defined state\r\n", " # Output:\r\n", " # cipherblock: byte sequence\r\n", " \r\n", " # first generate the required keys\r\n", " keylist = gen_keylist(8, num_rounds, seed)\r\n", "\r\n", " # implement num_rounds of calling the block function\r\n", "\r\n", " \r\n", " return cipherblock\r\n", "\r\n", "def feistel_dec(inputbytteseq, num_rounds, seed):\r\n", "\r\n", " # Make sure you use the keys in reverse order during decryption\r\n", " keylist = gen_keylist(8, num_rounds, seed)\r\n", "\r\n", " # apply the num_rounds times of the block funciton\r\n", "\r\n", " return plaintextblock" ], "execution_count": 8, "outputs": [ { "output_type": "stream", "text": [ "[b'\\xfe\\x88\\xba|\\xf2\\xa8+\\xa2', b'r+N\\xb12\\xb1\\xa3q', b'`#\\xa8\\xdb- \\xab\\xdc', b'\\x02t\\xac\\x88\\xde6f\\xe2', b'\\x8a\\xeb@\\x8ak>\\xd2<', b'\\xfe\\xda@\\xff\\x99/\\xbcL', b'\\x03\\xb7\\x04\\xd2\\xf2rS2', b'F\\x83\\xc0}\\xac\\x11\\x18(', b'y\\x86\\xd7\\xee\\xd6\\xc8\\xf0-', b'\\xce>\\xb9\\x1a\\t\"\\xe3\\x04', b'\\x9d\\xa2\\xb1\\xfe-\\x9aQ\\xdc', b'd9-\\x05QC\\x19I', b'\\x0f\\x9f\\xb6\\x08[\\x1b{\\x9d', b'\\rL\\xfc\\xce\\xdd\\xb2Nr', b'\\r\\x90\\xab\\xc1\\xa6\\x16J\\xf5', b'\\x91@:\\xa1\\xc2\\x82>2']\n" ], "name": "stdout" } ] } ] }