diff --git a/sbox.ipynb b/sbox.ipynb new file mode 100644 index 0000000..2a0da39 --- /dev/null +++ b/sbox.ipynb @@ -0,0 +1,472 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sbox avalanche effect" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of bits that are different: 65\n" + ] + } + ], + "source": [ + "from Crypto.Cipher import AES\n", + "import numpy as np\n", + "\n", + "# Create an AES cipher object\n", + "cipher = AES.new(bytes(16), AES.MODE_ECB)\n", + "\n", + "# Create two inputs that differ by one bit\n", + "input1 = bytes([0x00]*16)\n", + "input2 = bytes([0x01] + [0x00]*15)\n", + "\n", + "# Apply the S-box to both inputs\n", + "output1 = cipher.encrypt(input1)\n", + "output2 = cipher.encrypt(input2)\n", + "\n", + "# Convert the outputs to numpy arrays for easy manipulation\n", + "output1_array = np.array(list(output1))\n", + "output2_array = np.array(list(output2))\n", + "\n", + "# Calculate the number of bits that are different\n", + "diff = np.sum([bin(x).count(\"1\") for x in (output1_array ^ output2_array)])\n", + "\n", + "print(f'Number of bits that are different: {diff}')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3.875" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "aes_sbox = [\n", + " 0x63,\n", + " 0x7C,\n", + " 0x77,\n", + " 0x7B,\n", + " 0xF2,\n", + " 0x6B,\n", + " 0x6F,\n", + " 0xC5,\n", + " 0x30,\n", + " 0x01,\n", + " 0x67,\n", + " 0x2B,\n", + " 0xFE,\n", + " 0xD7,\n", + " 0xAB,\n", + " 0x76,\n", + " 0xCA,\n", + " 0x82,\n", + " 0xC9,\n", + " 0x7D,\n", + " 0xFA,\n", + " 0x59,\n", + " 0x47,\n", + " 0xF0,\n", + " 0xAD,\n", + " 0xD4,\n", + " 0xA2,\n", + " 0xAF,\n", + " 0x9C,\n", + " 0xA4,\n", + " 0x72,\n", + " 0xC0,\n", + " 0xB7,\n", + " 0xFD,\n", + " 0x93,\n", + " 0x26,\n", + " 0x36,\n", + " 0x3F,\n", + " 0xF7,\n", + " 0xCC,\n", + " 0x34,\n", + " 0xA5,\n", + " 0xE5,\n", + " 0xF1,\n", + " 0x71,\n", + " 0xD8,\n", + " 0x31,\n", + " 0x15,\n", + " 0x04,\n", + " 0xC7,\n", + " 0x23,\n", + " 0xC3,\n", + " 0x18,\n", + " 0x96,\n", + " 0x05,\n", + " 0x9A,\n", + " 0x07,\n", + " 0x12,\n", + " 0x80,\n", + " 0xE2,\n", + " 0xEB,\n", + " 0x27,\n", + " 0xB2,\n", + " 0x75,\n", + " 0x09,\n", + " 0x83,\n", + " 0x2C,\n", + " 0x1A,\n", + " 0x1B,\n", + " 0x6E,\n", + " 0x5A,\n", + " 0xA0,\n", + " 0x52,\n", + " 0x3B,\n", + " 0xD6,\n", + " 0xB3,\n", + " 0x29,\n", + " 0xE3,\n", + " 0x2F,\n", + " 0x84,\n", + " 0x53,\n", + " 0xD1,\n", + " 0x00,\n", + " 0xED,\n", + " 0x20,\n", + " 0xFC,\n", + " 0xB1,\n", + " 0x5B,\n", + " 0x6A,\n", + " 0xCB,\n", + " 0xBE,\n", + " 0x39,\n", + " 0x4A,\n", + " 0x4C,\n", + " 0x58,\n", + " 0xCF,\n", + " 0xD0,\n", + " 0xEF,\n", + " 0xAA,\n", + " 0xFB,\n", + " 0x43,\n", + " 0x4D,\n", + " 0x33,\n", + " 0x85,\n", + " 0x45,\n", + " 0xF9,\n", + " 0x02,\n", + " 0x7F,\n", + " 0x50,\n", + " 0x3C,\n", + " 0x9F,\n", + " 0xA8,\n", + " 0x51,\n", + " 0xA3,\n", + " 0x40,\n", + " 0x8F,\n", + " 0x92,\n", + " 0x9D,\n", + " 0x38,\n", + " 0xF5,\n", + " 0xBC,\n", + " 0xB6,\n", + " 0xDA,\n", + " 0x21,\n", + " 0x10,\n", + " 0xFF,\n", + " 0xF3,\n", + " 0xD2,\n", + " 0xCD,\n", + " 0x0C,\n", + " 0x13,\n", + " 0xEC,\n", + " 0x5F,\n", + " 0x97,\n", + " 0x44,\n", + " 0x17,\n", + " 0xC4,\n", + " 0xA7,\n", + " 0x7E,\n", + " 0x3D,\n", + " 0x64,\n", + " 0x5D,\n", + " 0x19,\n", + " 0x73,\n", + " 0x60,\n", + " 0x81,\n", + " 0x4F,\n", + " 0xDC,\n", + " 0x22,\n", + " 0x2A,\n", + " 0x90,\n", + " 0x88,\n", + " 0x46,\n", + " 0xEE,\n", + " 0xB8,\n", + " 0x14,\n", + " 0xDE,\n", + " 0x5E,\n", + " 0x0B,\n", + " 0xDB,\n", + " 0xE0,\n", + " 0x32,\n", + " 0x3A,\n", + " 0x0A,\n", + " 0x49,\n", + " 0x06,\n", + " 0x24,\n", + " 0x5C,\n", + " 0xC2,\n", + " 0xD3,\n", + " 0xAC,\n", + " 0x62,\n", + " 0x91,\n", + " 0x95,\n", + " 0xE4,\n", + " 0x79,\n", + " 0xE7,\n", + " 0xC8,\n", + " 0x37,\n", + " 0x6D,\n", + " 0x8D,\n", + " 0xD5,\n", + " 0x4E,\n", + " 0xA9,\n", + " 0x6C,\n", + " 0x56,\n", + " 0xF4,\n", + " 0xEA,\n", + " 0x65,\n", + " 0x7A,\n", + " 0xAE,\n", + " 0x08,\n", + " 0xBA,\n", + " 0x78,\n", + " 0x25,\n", + " 0x2E,\n", + " 0x1C,\n", + " 0xA6,\n", + " 0xB4,\n", + " 0xC6,\n", + " 0xE8,\n", + " 0xDD,\n", + " 0x74,\n", + " 0x1F,\n", + " 0x4B,\n", + " 0xBD,\n", + " 0x8B,\n", + " 0x8A,\n", + " 0x70,\n", + " 0x3E,\n", + " 0xB5,\n", + " 0x66,\n", + " 0x48,\n", + " 0x03,\n", + " 0xF6,\n", + " 0x0E,\n", + " 0x61,\n", + " 0x35,\n", + " 0x57,\n", + " 0xB9,\n", + " 0x86,\n", + " 0xC1,\n", + " 0x1D,\n", + " 0x9E,\n", + " 0xE1,\n", + " 0xF8,\n", + " 0x98,\n", + " 0x11,\n", + " 0x69,\n", + " 0xD9,\n", + " 0x8E,\n", + " 0x94,\n", + " 0x9B,\n", + " 0x1E,\n", + " 0x87,\n", + " 0xE9,\n", + " 0xCE,\n", + " 0x55,\n", + " 0x28,\n", + " 0xDF,\n", + " 0x8C,\n", + " 0xA1,\n", + " 0x89,\n", + " 0x0D,\n", + " 0xBF,\n", + " 0xE6,\n", + " 0x42,\n", + " 0x68,\n", + " 0x41,\n", + " 0x99,\n", + " 0x2D,\n", + " 0x0F,\n", + " 0xB0,\n", + " 0x54,\n", + " 0xBB,\n", + " 0x16,\n", + "]\n", + "\n", + "\n", + "def sbox_avalanche_one_bit(input_value: int, sbox: list = aes_sbox):\n", + " count = 0\n", + " for i in range(8):\n", + " count += bin(sbox[input_value] ^ sbox[input_value ^ (1 << i)]).count(\n", + " \"1\"\n", + " )\n", + " return count / 8\n", + "\n", + "\n", + "sbox_avalanche_one_bit(0x00)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4.0390625" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def sbox_avalanche(sbox: list = aes_sbox):\n", + " avalanche_one_bit = np.array([sbox_avalanche_one_bit(i, sbox) for i in range(256)])\n", + " average = sum(avalanche_one_bit[i] for i in range(256)) / 256\n", + " return average\n", + "\n", + "sbox_avalanche()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we can get the avalanche effect of sbox, change 1 bit will affect 4.03 bit on average.\n", + "\n", + "let us random creat a sbox." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4.033203125" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import random\n", + "\n", + "# Create a list of all possible 8-bit values\n", + "random_sbox = list(range(256))\n", + "\n", + "# Shuffle the list to create a random S-box\n", + "random.shuffle(random_sbox)\n", + "\n", + "# Now sbox is a random 8-bit S-box\n", + "sbox_avalanche(random_sbox)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "let us try 1000 time random sbox, see the avalanche for avarage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4.0161890625" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "avarage_avalanche = 0\n", + "try_times = 10000\n", + "for i in range(try_times):\n", + " # Create a list of all possible 8-bit values\n", + " random_sbox = list(range(256))\n", + "\n", + " # Shuffle the list to create a random S-box\n", + " random.shuffle(random_sbox)\n", + "\n", + " # Now sbox is a random 8-bit S-box\n", + " avarage_avalanche += sbox_avalanche(random_sbox)\n", + "\n", + "avarage_avalanche / try_times" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we get the table of avalanche for avarage one bit\n", + "\n", + "| aes_sbox | random_sbox |\n", + "|----------|----------|\n", + "| 4.03 | 4.01 |\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "attack", + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}