Labs
1
encrypted.bin
Normal file
@@ -0,0 +1 @@
|
||||
U2FsdGVkX1+SsKEug91LbdSIWzu7KyjBo9/7v4btDVY=
|
||||
1
myfile.txt
Normal file
@@ -0,0 +1 @@
|
||||
Hello World!
|
||||
978
z_jupyter/01_fundamentals.ipynb
Normal file
@@ -0,0 +1,978 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "509b908c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Fundamentals\n",
|
||||
"Within cryptography our aim is often to secure a message between Bob and Alice, and so that Eve - the adversory - cannot view or change a message that is passed between them. Along with Bob and Alice, we have other cybersecurity actors, such as Peggy (the prover) and Victor (the verifier):\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"This workbook outlines of the key fundamentals that are used in cryptography, including the usage of binary operators, ciphertext representation, Boolean operators and prime numbers. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e8a9af38",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Introduction\n",
|
||||
"\n",
|
||||
"In order to implement security, we often take plaintext and convert it into ciphertext:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"With a program, we often have numerical values (integers or floating point) or characters and strings. So, while the plaintext can contain characters that can be viewable, with binary we often have to represent the byte values with Base64 or in a hexadecimal form.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "37c0d953",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Hex, binary, decimal and Base64\n",
|
||||
"The conversion of byte values into a hexademical form involves us breaking the byte vakues into 4 bit nibbles, and then representing each of these values with a hexadecimal value. For example, if we have a byte pattern of\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"01111111 01010001\n",
|
||||
"```\n",
|
||||
"We can then split up the byte values to give:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"0111 1111 0101 0001\n",
|
||||
"7 F 5 1\n",
|
||||
"```\n",
|
||||
"An example of this is:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Another typical format is Base64, and where we take 6 bits at a time and represent it with a Base64 character:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"For a pattern of:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"01000001 01000010 \n",
|
||||
"```\n",
|
||||
"We can then split up the byte values to give:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"010000 010100 0010 [00] \n",
|
||||
"Q U I =\n",
|
||||
"```\n",
|
||||
"This gives us \"QUI=\", and where we pad with zeros to fill up slots of six bits, and then pad with \"=\" characters to give a multiple of four characters within the Base64 string. In Python, we can represent a hex, octal and binary value with 0x, 0o and 0b at the start of the value. We can then convert into decimal, hex, octal and binary with the int(), hex(), oct() and bin() methods:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "8c8fae3f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"21 Int=21, Hex=0x15, Oct=0o25\n",
|
||||
"34 Bin=0b100010, Hex=0x22, Oct=0o42, Dec=34\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"val1=0b10101\n",
|
||||
"val2=int(val1)\n",
|
||||
"val3=hex(val1)\n",
|
||||
"val4=oct(val1)\n",
|
||||
"\n",
|
||||
"print(f\"{val1} Int={val2}, Hex={val3}, Oct={val4}\")\n",
|
||||
"\n",
|
||||
"val1=0o42\n",
|
||||
"val2=bin(val1)\n",
|
||||
"val3=hex(val1)\n",
|
||||
"val4=oct(val1)\n",
|
||||
"val5=int(val1)\n",
|
||||
"\n",
|
||||
"print(f\"{val1} Bin={val2}, Hex={val3}, Oct={val4}, Dec={val5}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5f33519c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Modify the program so that you can determine the hex, octal and binary value for the decimal value of 42.\n",
|
||||
"\n",
|
||||
"> Modify the program so that you can determine the decimal, octal and binary value for the hex value of 0x42.\n",
|
||||
"\n",
|
||||
"> Modify the program so that you can determine the hex, decimal, and binary value for the octal value of 0o42.\n",
|
||||
"\n",
|
||||
"> Modify the program so that is shows the following table (note: use for \"i in range()\"):\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"Val Hex Oct Binary\n",
|
||||
"0 0x0 0o0 0b0\n",
|
||||
"1 0x1 0o1 0b1\n",
|
||||
"2 0x2 0o2 0b10\n",
|
||||
"3 0x3 0o3 0b11\n",
|
||||
"4 0x4 0o4 0b100\n",
|
||||
"5 0x5 0o5 0b101\n",
|
||||
"6 0x6 0o6 0b110\n",
|
||||
"7 0x7 0o7 0b111\n",
|
||||
"8 0x8 0o10 0b1000\n",
|
||||
"9 0x9 0o11 0b1001\n",
|
||||
"10 0xa 0o12 0b1010\n",
|
||||
"11 0xb 0o13 0b1011\n",
|
||||
"12 0xc 0o14 0b1100\n",
|
||||
"13 0xd 0o15 0b1101\n",
|
||||
"14 0xe 0o16 0b1110\n",
|
||||
"15 0xf 0o17 0b1111 \n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "73426b52",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Byte conversions\n",
|
||||
"In cryptography, we often operate on byte arrays and need to convert from byte array formats into other formats, such as for ASCII string values. For this, we can use the binascii library, such as using hexlify() to convert a hex string into a into a byte array, and with b2a_hex() to perform the reverse operation: "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 49,
|
||||
"id": "9129b9e6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"String abcdefg is b'61626364656667' in bytes\n",
|
||||
"Bytes b'3631363236333634363536363637' is 3631363236333634363536363637 as a string\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"a=\"abcdefg\"\n",
|
||||
"b=binascii.hexlify(a.encode())\n",
|
||||
"\n",
|
||||
"print(f\"String {a} is {b} in bytes\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"c=binascii.b2a_hex(b)\n",
|
||||
"\n",
|
||||
"print(f\"Bytes {c} is {c.decode()} as a string\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b72f269f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Bit operations\n",
|
||||
"While we mostly deal with bytes in cryptography, we might also modify bit values. For this we can use the bitwise AND, OR and XOR operations. For this we get:\n",
|
||||
"```\n",
|
||||
"a b AND(a,b) OR(a,b) XOR(a,b)\n",
|
||||
"0 0 0 0 0\n",
|
||||
"0 1 0 1 1\n",
|
||||
"1 0 0 1 1\n",
|
||||
"1 1 1 1 0\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"We can then use the bitwise operations of & (AND), | (OR) and ^ (XOR). For example we can specify in binary, and then perform bitwise operations. In this case we will display the results in a binary format:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 55,
|
||||
"id": "8eaccf0e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"0x32 AND 0b1000011 = 0b10\n",
|
||||
"0b110010 OR 0b1000011 = 0b1110011\n",
|
||||
"0b110010 XOR 0b1000011 = 0b1110001\n",
|
||||
"0 0b0 0b10101010 0b10101010\n",
|
||||
"1 0b0 0b10101011 0b10101011\n",
|
||||
"2 0b10 0b10101010 0b10101000\n",
|
||||
"3 0b10 0b10101011 0b10101001\n",
|
||||
"4 0b0 0b10101110 0b10101110\n",
|
||||
"5 0b0 0b10101111 0b10101111\n",
|
||||
"6 0b10 0b10101110 0b10101100\n",
|
||||
"7 0b10 0b10101111 0b10101101\n",
|
||||
"8 0b1000 0b10101010 0b10100010\n",
|
||||
"9 0b1000 0b10101011 0b10100011\n",
|
||||
"10 0b1010 0b10101010 0b10100000\n",
|
||||
"11 0b1010 0b10101011 0b10100001\n",
|
||||
"12 0b1000 0b10101110 0b10100110\n",
|
||||
"13 0b1000 0b10101111 0b10100111\n",
|
||||
"14 0b1010 0b10101110 0b10100100\n",
|
||||
"15 0b1010 0b10101111 0b10100101\n",
|
||||
"16 0b0 0b10111010 0b10111010\n",
|
||||
"17 0b0 0b10111011 0b10111011\n",
|
||||
"18 0b10 0b10111010 0b10111000\n",
|
||||
"19 0b10 0b10111011 0b10111001\n",
|
||||
"20 0b0 0b10111110 0b10111110\n",
|
||||
"21 0b0 0b10111111 0b10111111\n",
|
||||
"22 0b10 0b10111110 0b10111100\n",
|
||||
"23 0b10 0b10111111 0b10111101\n",
|
||||
"24 0b1000 0b10111010 0b10110010\n",
|
||||
"25 0b1000 0b10111011 0b10110011\n",
|
||||
"26 0b1010 0b10111010 0b10110000\n",
|
||||
"27 0b1010 0b10111011 0b10110001\n",
|
||||
"28 0b1000 0b10111110 0b10110110\n",
|
||||
"29 0b1000 0b10111111 0b10110111\n",
|
||||
"30 0b1010 0b10111110 0b10110100\n",
|
||||
"31 0b1010 0b10111111 0b10110101\n",
|
||||
"32 0b100000 0b10101010 0b10001010\n",
|
||||
"33 0b100000 0b10101011 0b10001011\n",
|
||||
"34 0b100010 0b10101010 0b10001000\n",
|
||||
"35 0b100010 0b10101011 0b10001001\n",
|
||||
"36 0b100000 0b10101110 0b10001110\n",
|
||||
"37 0b100000 0b10101111 0b10001111\n",
|
||||
"38 0b100010 0b10101110 0b10001100\n",
|
||||
"39 0b100010 0b10101111 0b10001101\n",
|
||||
"40 0b101000 0b10101010 0b10000010\n",
|
||||
"41 0b101000 0b10101011 0b10000011\n",
|
||||
"42 0b101010 0b10101010 0b10000000\n",
|
||||
"43 0b101010 0b10101011 0b10000001\n",
|
||||
"44 0b101000 0b10101110 0b10000110\n",
|
||||
"45 0b101000 0b10101111 0b10000111\n",
|
||||
"46 0b101010 0b10101110 0b10000100\n",
|
||||
"47 0b101010 0b10101111 0b10000101\n",
|
||||
"48 0b100000 0b10111010 0b10011010\n",
|
||||
"49 0b100000 0b10111011 0b10011011\n",
|
||||
"50 0b100010 0b10111010 0b10011000\n",
|
||||
"51 0b100010 0b10111011 0b10011001\n",
|
||||
"52 0b100000 0b10111110 0b10011110\n",
|
||||
"53 0b100000 0b10111111 0b10011111\n",
|
||||
"54 0b100010 0b10111110 0b10011100\n",
|
||||
"55 0b100010 0b10111111 0b10011101\n",
|
||||
"56 0b101000 0b10111010 0b10010010\n",
|
||||
"57 0b101000 0b10111011 0b10010011\n",
|
||||
"58 0b101010 0b10111010 0b10010000\n",
|
||||
"59 0b101010 0b10111011 0b10010001\n",
|
||||
"60 0b101000 0b10111110 0b10010110\n",
|
||||
"61 0b101000 0b10111111 0b10010111\n",
|
||||
"62 0b101010 0b10111110 0b10010100\n",
|
||||
"63 0b101010 0b10111111 0b10010101\n",
|
||||
"64 0b0 0b11101010 0b11101010\n",
|
||||
"65 0b0 0b11101011 0b11101011\n",
|
||||
"66 0b10 0b11101010 0b11101000\n",
|
||||
"67 0b10 0b11101011 0b11101001\n",
|
||||
"68 0b0 0b11101110 0b11101110\n",
|
||||
"69 0b0 0b11101111 0b11101111\n",
|
||||
"70 0b10 0b11101110 0b11101100\n",
|
||||
"71 0b10 0b11101111 0b11101101\n",
|
||||
"72 0b1000 0b11101010 0b11100010\n",
|
||||
"73 0b1000 0b11101011 0b11100011\n",
|
||||
"74 0b1010 0b11101010 0b11100000\n",
|
||||
"75 0b1010 0b11101011 0b11100001\n",
|
||||
"76 0b1000 0b11101110 0b11100110\n",
|
||||
"77 0b1000 0b11101111 0b11100111\n",
|
||||
"78 0b1010 0b11101110 0b11100100\n",
|
||||
"79 0b1010 0b11101111 0b11100101\n",
|
||||
"80 0b0 0b11111010 0b11111010\n",
|
||||
"81 0b0 0b11111011 0b11111011\n",
|
||||
"82 0b10 0b11111010 0b11111000\n",
|
||||
"83 0b10 0b11111011 0b11111001\n",
|
||||
"84 0b0 0b11111110 0b11111110\n",
|
||||
"85 0b0 0b11111111 0b11111111\n",
|
||||
"86 0b10 0b11111110 0b11111100\n",
|
||||
"87 0b10 0b11111111 0b11111101\n",
|
||||
"88 0b1000 0b11111010 0b11110010\n",
|
||||
"89 0b1000 0b11111011 0b11110011\n",
|
||||
"90 0b1010 0b11111010 0b11110000\n",
|
||||
"91 0b1010 0b11111011 0b11110001\n",
|
||||
"92 0b1000 0b11111110 0b11110110\n",
|
||||
"93 0b1000 0b11111111 0b11110111\n",
|
||||
"94 0b1010 0b11111110 0b11110100\n",
|
||||
"95 0b1010 0b11111111 0b11110101\n",
|
||||
"96 0b100000 0b11101010 0b11001010\n",
|
||||
"97 0b100000 0b11101011 0b11001011\n",
|
||||
"98 0b100010 0b11101010 0b11001000\n",
|
||||
"99 0b100010 0b11101011 0b11001001\n",
|
||||
"100 0b100000 0b11101110 0b11001110\n",
|
||||
"101 0b100000 0b11101111 0b11001111\n",
|
||||
"102 0b100010 0b11101110 0b11001100\n",
|
||||
"103 0b100010 0b11101111 0b11001101\n",
|
||||
"104 0b101000 0b11101010 0b11000010\n",
|
||||
"105 0b101000 0b11101011 0b11000011\n",
|
||||
"106 0b101010 0b11101010 0b11000000\n",
|
||||
"107 0b101010 0b11101011 0b11000001\n",
|
||||
"108 0b101000 0b11101110 0b11000110\n",
|
||||
"109 0b101000 0b11101111 0b11000111\n",
|
||||
"110 0b101010 0b11101110 0b11000100\n",
|
||||
"111 0b101010 0b11101111 0b11000101\n",
|
||||
"112 0b100000 0b11111010 0b11011010\n",
|
||||
"113 0b100000 0b11111011 0b11011011\n",
|
||||
"114 0b100010 0b11111010 0b11011000\n",
|
||||
"115 0b100010 0b11111011 0b11011001\n",
|
||||
"116 0b100000 0b11111110 0b11011110\n",
|
||||
"117 0b100000 0b11111111 0b11011111\n",
|
||||
"118 0b100010 0b11111110 0b11011100\n",
|
||||
"119 0b100010 0b11111111 0b11011101\n",
|
||||
"120 0b101000 0b11111010 0b11010010\n",
|
||||
"121 0b101000 0b11111011 0b11010011\n",
|
||||
"122 0b101010 0b11111010 0b11010000\n",
|
||||
"123 0b101010 0b11111011 0b11010001\n",
|
||||
"124 0b101000 0b11111110 0b11010110\n",
|
||||
"125 0b101000 0b11111111 0b11010111\n",
|
||||
"126 0b101010 0b11111110 0b11010100\n",
|
||||
"127 0b101010 0b11111111 0b11010101\n",
|
||||
"128 0b10000000 0b10101010 0b101010\n",
|
||||
"129 0b10000000 0b10101011 0b101011\n",
|
||||
"130 0b10000010 0b10101010 0b101000\n",
|
||||
"131 0b10000010 0b10101011 0b101001\n",
|
||||
"132 0b10000000 0b10101110 0b101110\n",
|
||||
"133 0b10000000 0b10101111 0b101111\n",
|
||||
"134 0b10000010 0b10101110 0b101100\n",
|
||||
"135 0b10000010 0b10101111 0b101101\n",
|
||||
"136 0b10001000 0b10101010 0b100010\n",
|
||||
"137 0b10001000 0b10101011 0b100011\n",
|
||||
"138 0b10001010 0b10101010 0b100000\n",
|
||||
"139 0b10001010 0b10101011 0b100001\n",
|
||||
"140 0b10001000 0b10101110 0b100110\n",
|
||||
"141 0b10001000 0b10101111 0b100111\n",
|
||||
"142 0b10001010 0b10101110 0b100100\n",
|
||||
"143 0b10001010 0b10101111 0b100101\n",
|
||||
"144 0b10000000 0b10111010 0b111010\n",
|
||||
"145 0b10000000 0b10111011 0b111011\n",
|
||||
"146 0b10000010 0b10111010 0b111000\n",
|
||||
"147 0b10000010 0b10111011 0b111001\n",
|
||||
"148 0b10000000 0b10111110 0b111110\n",
|
||||
"149 0b10000000 0b10111111 0b111111\n",
|
||||
"150 0b10000010 0b10111110 0b111100\n",
|
||||
"151 0b10000010 0b10111111 0b111101\n",
|
||||
"152 0b10001000 0b10111010 0b110010\n",
|
||||
"153 0b10001000 0b10111011 0b110011\n",
|
||||
"154 0b10001010 0b10111010 0b110000\n",
|
||||
"155 0b10001010 0b10111011 0b110001\n",
|
||||
"156 0b10001000 0b10111110 0b110110\n",
|
||||
"157 0b10001000 0b10111111 0b110111\n",
|
||||
"158 0b10001010 0b10111110 0b110100\n",
|
||||
"159 0b10001010 0b10111111 0b110101\n",
|
||||
"160 0b10100000 0b10101010 0b1010\n",
|
||||
"161 0b10100000 0b10101011 0b1011\n",
|
||||
"162 0b10100010 0b10101010 0b1000\n",
|
||||
"163 0b10100010 0b10101011 0b1001\n",
|
||||
"164 0b10100000 0b10101110 0b1110\n",
|
||||
"165 0b10100000 0b10101111 0b1111\n",
|
||||
"166 0b10100010 0b10101110 0b1100\n",
|
||||
"167 0b10100010 0b10101111 0b1101\n",
|
||||
"168 0b10101000 0b10101010 0b10\n",
|
||||
"169 0b10101000 0b10101011 0b11\n",
|
||||
"170 0b10101010 0b10101010 0b0\n",
|
||||
"171 0b10101010 0b10101011 0b1\n",
|
||||
"172 0b10101000 0b10101110 0b110\n",
|
||||
"173 0b10101000 0b10101111 0b111\n",
|
||||
"174 0b10101010 0b10101110 0b100\n",
|
||||
"175 0b10101010 0b10101111 0b101\n",
|
||||
"176 0b10100000 0b10111010 0b11010\n",
|
||||
"177 0b10100000 0b10111011 0b11011\n",
|
||||
"178 0b10100010 0b10111010 0b11000\n",
|
||||
"179 0b10100010 0b10111011 0b11001\n",
|
||||
"180 0b10100000 0b10111110 0b11110\n",
|
||||
"181 0b10100000 0b10111111 0b11111\n",
|
||||
"182 0b10100010 0b10111110 0b11100\n",
|
||||
"183 0b10100010 0b10111111 0b11101\n",
|
||||
"184 0b10101000 0b10111010 0b10010\n",
|
||||
"185 0b10101000 0b10111011 0b10011\n",
|
||||
"186 0b10101010 0b10111010 0b10000\n",
|
||||
"187 0b10101010 0b10111011 0b10001\n",
|
||||
"188 0b10101000 0b10111110 0b10110\n",
|
||||
"189 0b10101000 0b10111111 0b10111\n",
|
||||
"190 0b10101010 0b10111110 0b10100\n",
|
||||
"191 0b10101010 0b10111111 0b10101\n",
|
||||
"192 0b10000000 0b11101010 0b1101010\n",
|
||||
"193 0b10000000 0b11101011 0b1101011\n",
|
||||
"194 0b10000010 0b11101010 0b1101000\n",
|
||||
"195 0b10000010 0b11101011 0b1101001\n",
|
||||
"196 0b10000000 0b11101110 0b1101110\n",
|
||||
"197 0b10000000 0b11101111 0b1101111\n",
|
||||
"198 0b10000010 0b11101110 0b1101100\n",
|
||||
"199 0b10000010 0b11101111 0b1101101\n",
|
||||
"200 0b10001000 0b11101010 0b1100010\n",
|
||||
"201 0b10001000 0b11101011 0b1100011\n",
|
||||
"202 0b10001010 0b11101010 0b1100000\n",
|
||||
"203 0b10001010 0b11101011 0b1100001\n",
|
||||
"204 0b10001000 0b11101110 0b1100110\n",
|
||||
"205 0b10001000 0b11101111 0b1100111\n",
|
||||
"206 0b10001010 0b11101110 0b1100100\n",
|
||||
"207 0b10001010 0b11101111 0b1100101\n",
|
||||
"208 0b10000000 0b11111010 0b1111010\n",
|
||||
"209 0b10000000 0b11111011 0b1111011\n",
|
||||
"210 0b10000010 0b11111010 0b1111000\n",
|
||||
"211 0b10000010 0b11111011 0b1111001\n",
|
||||
"212 0b10000000 0b11111110 0b1111110\n",
|
||||
"213 0b10000000 0b11111111 0b1111111\n",
|
||||
"214 0b10000010 0b11111110 0b1111100\n",
|
||||
"215 0b10000010 0b11111111 0b1111101\n",
|
||||
"216 0b10001000 0b11111010 0b1110010\n",
|
||||
"217 0b10001000 0b11111011 0b1110011\n",
|
||||
"218 0b10001010 0b11111010 0b1110000\n",
|
||||
"219 0b10001010 0b11111011 0b1110001\n",
|
||||
"220 0b10001000 0b11111110 0b1110110\n",
|
||||
"221 0b10001000 0b11111111 0b1110111\n",
|
||||
"222 0b10001010 0b11111110 0b1110100\n",
|
||||
"223 0b10001010 0b11111111 0b1110101\n",
|
||||
"224 0b10100000 0b11101010 0b1001010\n",
|
||||
"225 0b10100000 0b11101011 0b1001011\n",
|
||||
"226 0b10100010 0b11101010 0b1001000\n",
|
||||
"227 0b10100010 0b11101011 0b1001001\n",
|
||||
"228 0b10100000 0b11101110 0b1001110\n",
|
||||
"229 0b10100000 0b11101111 0b1001111\n",
|
||||
"230 0b10100010 0b11101110 0b1001100\n",
|
||||
"231 0b10100010 0b11101111 0b1001101\n",
|
||||
"232 0b10101000 0b11101010 0b1000010\n",
|
||||
"233 0b10101000 0b11101011 0b1000011\n",
|
||||
"234 0b10101010 0b11101010 0b1000000\n",
|
||||
"235 0b10101010 0b11101011 0b1000001\n",
|
||||
"236 0b10101000 0b11101110 0b1000110\n",
|
||||
"237 0b10101000 0b11101111 0b1000111\n",
|
||||
"238 0b10101010 0b11101110 0b1000100\n",
|
||||
"239 0b10101010 0b11101111 0b1000101\n",
|
||||
"240 0b10100000 0b11111010 0b1011010\n",
|
||||
"241 0b10100000 0b11111011 0b1011011\n",
|
||||
"242 0b10100010 0b11111010 0b1011000\n",
|
||||
"243 0b10100010 0b11111011 0b1011001\n",
|
||||
"244 0b10100000 0b11111110 0b1011110\n",
|
||||
"245 0b10100000 0b11111111 0b1011111\n",
|
||||
"246 0b10100010 0b11111110 0b1011100\n",
|
||||
"247 0b10100010 0b11111111 0b1011101\n",
|
||||
"248 0b10101000 0b11111010 0b1010010\n",
|
||||
"249 0b10101000 0b11111011 0b1010011\n",
|
||||
"250 0b10101010 0b11111010 0b1010000\n",
|
||||
"251 0b10101010 0b11111011 0b1010001\n",
|
||||
"252 0b10101000 0b11111110 0b1010110\n",
|
||||
"253 0b10101000 0b11111111 0b1010111\n",
|
||||
"254 0b10101010 0b11111110 0b1010100\n",
|
||||
"255 0b10101010 0b11111111 0b1010101\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"a=0x32\n",
|
||||
"b=0x43\n",
|
||||
"\n",
|
||||
"c=a & b\n",
|
||||
"d=a | b\n",
|
||||
"e=a ^ b\n",
|
||||
"\n",
|
||||
"print(f\"{hex(a)} AND {bin(b)} = {bin(c)}\")\n",
|
||||
"print(f\"{bin(a)} OR {bin(b)} = {bin(d)}\")\n",
|
||||
"print(f\"{bin(a)} XOR {bin(b)} = {bin(e)}\")\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fb34d492",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Check the Boolean operations to see that the program works.\n",
|
||||
"\n",
|
||||
"> Using the program, determine the result of 0b10101010 XOR 0b10101010.\n",
|
||||
"\n",
|
||||
"> Modify the program so that you can specify hexademical values, and then display in a hexademical format.\n",
|
||||
"\n",
|
||||
"> Modify the program so that we have a loop from 0 to 255 (note: use for \"i in range()\"), and AND, OR and XOR is a value of 0b10101010. A sample run for the first few outputs is:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"i& AND\tOR\t XOR\n",
|
||||
"0b0 0b0\t0b10101010\t0b10101010\n",
|
||||
"0b1 0b0\t0b10101011\t0b10101011\n",
|
||||
"0b10 0b10\t0b10101010\t0b10101000\n",
|
||||
"0b11 0b10\t0b10101011\t0b10101001\n",
|
||||
"0b100 0b0\t0b10101110\t0b10101110\n",
|
||||
"0b101 0b0\t0b10101111\t0b10101111\n",
|
||||
"0b110 0b10\t0b10101110\t0b10101100\n",
|
||||
"0b111 0b10\t0b10101111\t0b10101101\n",
|
||||
"0b1000 0b1000\t0b10101010\t0b10100010\n",
|
||||
"0b1001 0b1000\t0b10101011\t0b10100011\n",
|
||||
"0b1010 0b1010\t0b10101010\t0b10100000\n",
|
||||
"0b1011 0b1010\t0b10101011\t0b10100001\n",
|
||||
"0b1100 0b1000\t0b10101110\t0b10100110\n",
|
||||
"0b1101 0b1000\t0b10101111\t0b10100111\n",
|
||||
"0b1110 0b1010\t0b10101110\t0b10100100\n",
|
||||
"0b1111 0b1010\t0b10101111\t0b10100101\n",
|
||||
"0b10000 0b0\t0b10111010\t0b10111010\n",
|
||||
"0b10001 0b0\t0b10111011\t0b10111011\n",
|
||||
"0b10010 0b10\t0b10111010\t0b10111000\n",
|
||||
"0b10011 0b10\t0b10111011\t0b10111001\n",
|
||||
"0b10100 0b0\t0b10111110\t0b10111110\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3634d7ce",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Modulo operation\n",
|
||||
"\n",
|
||||
"One of the most basic operations in cryptography is to use the modulo operation, and which gives the remainder of an integer division. For 17 modulo 5, we get 2. In most cases, with cryptography, we use the modulo of a prime number (p), and use (mod p) operation, such as:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"A = B (mod p)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The operator for modulo operations is defined with \"%\". "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 57,
|
||||
"id": "e870306b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"15434 (mod 127) = 67\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"a=15434\n",
|
||||
"p=127\n",
|
||||
"\n",
|
||||
"b = a%p\n",
|
||||
"\n",
|
||||
"print(f\"{a} (mod {p}) = {b}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "29be2ce3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Verify that the program is working correctly. Then determine the following:\n",
|
||||
"```\n",
|
||||
"15434 (mod 127) = ?\n",
|
||||
"546324 (mod 997) = ?\n",
|
||||
"905463124 (mod 524287) = ?\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b0d38eae",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Prime numbers\n",
|
||||
"\n",
|
||||
"Many areas of cryptography use prime numbers, and which are integer values which can only be divisable by itself and 1. Every other integer - known as composite numbers - can be made up of a multiplication of prime numbers. Examples of prime numbers are 13, 97 and 997. The following composite numbers can be factorized into the multiplication of prime numbers:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"33 = 3 x 11\n",
|
||||
"532 = 2 x 2 x 7 x 19\n",
|
||||
"2,542 = 2 x 31 x 41\n",
|
||||
"743,243 = 193 x 3,851\n",
|
||||
"1,234,567,890 = 2 x 3 x 3 x 5 x 3,607 x 3,803\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0b9e3720",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In the following, we will use the libnum library to generate a random prime number with a given number of bits:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 85,
|
||||
"id": "fd09fcb6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Random: 812768180957 Length: 40\n",
|
||||
"\n",
|
||||
"Prime (p): 560263049029. Length: 40 bits, Digits: 12\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import libnum\n",
|
||||
"\n",
|
||||
"bitsize=40\n",
|
||||
"\n",
|
||||
"r=libnum.randint_bits(bitsize)\n",
|
||||
"\n",
|
||||
"print (\"Random: %d Length: %d\" % (r,libnum.len_in_bits(r)))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"p=libnum.generate_prime(bitsize)\n",
|
||||
"\n",
|
||||
"print (\"\\nPrime (p): %d. Length: %d bits, Digits: %d\" % (p,libnum.len_in_bits(p), len(str(p)) )) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5a1a3c85",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"another library is Crypto:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 94,
|
||||
"id": "6ec3d9cb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"No of bits in prime is 64\n",
|
||||
"\n",
|
||||
"Random n-bit Prime (p): 11916865567959269669\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import Crypto.Util.number\n",
|
||||
"\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"bits=64\n",
|
||||
"\n",
|
||||
"print (\"No of bits in prime is \",bits)\n",
|
||||
"\n",
|
||||
"p=Crypto.Util.number.getPrime(bits, randfunc=Crypto.Random.get_random_bytes)\n",
|
||||
"print (\"\\nRandom n-bit Prime (p): \",p)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dc11d9d0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Generate a 64-bit random prime number. And use this page to determine if it is prime [here](https://asecuritysite.com/primes/testprime).\n",
|
||||
"\n",
|
||||
"> Generate a 256-bit random prime number. And use this page to determine if it is prime [here](https://asecuritysite.com/primes/testprime).\n",
|
||||
"\n",
|
||||
"> By observing the last few digits of a number, which numbers are obviously not prime numbers?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d2d3bd5d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Finite Fields\n",
|
||||
"Within cryptography, we typically constrain our operations within a finite field. This is normally defined by a prime number (p), and where we have values between 0 and (p-1). This can be defined with the (mod p) operator. For this, we need to define a mapping from A to B, and which can be reversed back from B to A. For the add operation with a (mod p) operation, we can reverse with a subtraction:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"For a logarithmic operation, we should be able to map all the values in A to B:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"In the following, we will determine the mapping of values when we add and subtract 5 using the (mod p) operation:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 39,
|
||||
"id": "d4b145d0",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"0+5 (mod 7)=5\n",
|
||||
"0-5 (mod 7)=2\n",
|
||||
"1+5 (mod 7)=6\n",
|
||||
"1-5 (mod 7)=3\n",
|
||||
"2+5 (mod 7)=0\n",
|
||||
"2-5 (mod 7)=4\n",
|
||||
"3+5 (mod 7)=1\n",
|
||||
"3-5 (mod 7)=5\n",
|
||||
"4+5 (mod 7)=2\n",
|
||||
"4-5 (mod 7)=6\n",
|
||||
"5+5 (mod 7)=3\n",
|
||||
"5-5 (mod 7)=0\n",
|
||||
"6+5 (mod 7)=4\n",
|
||||
"6-5 (mod 7)=1\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"b=5\n",
|
||||
"p=7\n",
|
||||
"\n",
|
||||
"for a in range(p):\n",
|
||||
" c=(a+b) % p\n",
|
||||
" d=(a-b) % p\n",
|
||||
" print(f\"{a}+{b} (mod {p})={c}\")\n",
|
||||
" print(f\"{a}-{b} (mod {p})={d}\")\n",
|
||||
" "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6867a166",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"> Verify that for each value of a, that we get a unique mapping to a value in the range of 0 to p-1.\n",
|
||||
"> Verify that we can add a given value to a number, and then subtract the same value to get the original value back. Note the value should be between 0 and p-1."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "528f0427",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Inverse mod\n",
|
||||
"As we are using integer values, the perform a division by finding the inverse mod of a value, and then multiplying it with another value. For a divided by b, we get:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"Inv_b = pow(b,-1,p)\n",
|
||||
"a_b = a * Inv_b\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"In the following, we will multiply a by b, and then reverse by dividing by b:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 95,
|
||||
"id": "dcb77c31",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a=13, b=6\n",
|
||||
"13 times 6 (mod p)=2\n",
|
||||
"Inverse 6 (mod 19)=16\n",
|
||||
"2 divided by 6 (mod 19)=13\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"a = 13\n",
|
||||
"b= 6\n",
|
||||
"p=19\n",
|
||||
"\n",
|
||||
"c=a*b % p\n",
|
||||
"\n",
|
||||
"print(f\"a={a}, b={b}\")\n",
|
||||
"\n",
|
||||
"print(f\"{a} times {b} (mod p)={c}\")\n",
|
||||
"\n",
|
||||
"Inv_b=pow(b,-1,p)\n",
|
||||
"\n",
|
||||
"print(f\"Inverse {b} (mod {p})={Inv_b}\")\n",
|
||||
"\n",
|
||||
"d = c*Inv_b %p\n",
|
||||
"print(f\"{c} divided by {b} (mod {p})={d}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4127f768",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> For a prime number of 19, determine the inverse mod of 6?\n",
|
||||
"\n",
|
||||
"> For a prime number of 97, determine the inverse mod of 6?\n",
|
||||
"\n",
|
||||
"> For a prime number of 997, a=101 and b=97. Compute c = a times b (mod p), and show that c divided by b (mod p) will give a."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d4676b59",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We can also use the libnum library to compute the inverse mod value, such as:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 41,
|
||||
"id": "349b3ff1",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Result=54\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import libnum\n",
|
||||
"\n",
|
||||
"p=997\n",
|
||||
"a=54\n",
|
||||
"b=62\n",
|
||||
"\n",
|
||||
"c= a*b %p\n",
|
||||
"\n",
|
||||
"Inv_b = libnum.invmod(b,p)\n",
|
||||
"\n",
|
||||
"res = (c* Inv_b) % p\n",
|
||||
"\n",
|
||||
"print(f\"Result={res}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b24407b8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## GCD (Greatest Common Divisor)\n",
|
||||
"Another basic operator in cryptography is GCD, and which returns the largest value that can be divided into a defined value. For example, the GCD(60, 12) is 12, as 12 is the largest divider of 60 and 12. In the following we will use the libnum library to determine the GCD of two numbers:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 99,
|
||||
"id": "3565fb67",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"GCD(802,72)=2\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from libnum import gcd\n",
|
||||
"a=56\n",
|
||||
"b=72\n",
|
||||
"\n",
|
||||
"print(f\"GCD({a},{b})={gcd(a,b)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9c647834",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Run the program, and verify its operation with a few examples.\n",
|
||||
"\n",
|
||||
"> What is the result of GCD(802,72)?\n",
|
||||
"\n",
|
||||
"> What is the result of GCD(997,81)?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ee22a1f0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Overall, we tend to use this operation to determine when two values do not share the same factor, and thus often look for:\n",
|
||||
"\n",
|
||||
"GCD(a,b)==1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f5e2f3fc",
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "html"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"> Determine if 91 and 27 share any factors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "84b8a11d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Exponentiation cipher\n",
|
||||
"Exponentiation ciphers use a form of C=M^e (mod p) to encrypt and decrypt a message (M) using an encryption key of e and a prime number p. It is used in Pohlig-Hellman and RSA. In the following, we use two methods of computing the exponentiation:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d8e266cc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Cipher = M^e (mod p)\n",
|
||||
"\n",
|
||||
"M=1234567890\n",
|
||||
"e=65537\n",
|
||||
"p=2**255-1\n",
|
||||
"\n",
|
||||
"C=M**e % p # Slow for large values\n",
|
||||
"print (f\"Cipher = {C}\")\n",
|
||||
"\n",
|
||||
"C=pow(M,e,p) # Much faster\n",
|
||||
"print (f\"Cipher = {C}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4c49a2c7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Which of the two methods is the fastest?\n",
|
||||
"> Make the message value much larger, what effect does it have on the computation?\n",
|
||||
"> Why is the pow() method faster?\n",
|
||||
"> If you create d=pow(e,-1,p), and then try M=pow(C,d,p), what is the result?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4c083835",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ddb45b14",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Lab 1: Cryptography Fundamentals"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "27a217f9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Objective: The key objective of this lab is to be introduced to some of the fundamental principles involved in cryptography, including the usage of Base-64, hexadecimal, the modulus operator some basic operators (such as AND, OR, X-OR, Rotate Right and Rotate Left), and prime numbers. This lab also involves cracking puzzles, and which have been added to get you to think about the methods involved in cipher cracking. You can undertake the additional challenges if you want to further develop your cryptography skills.\n",
|
||||
"\n",
|
||||
"Go to vsoc2.napier.ac.uk and find your folder. Run your Ubuntu instance demo. The virtual machine's password is napier123. Lab demo: (Note that you will be using Ubuntu, while the demo shows Kali). A demo of the lab is here."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c3d1c955",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.1 Is prime?\n",
|
||||
"\n",
|
||||
"Using: here\n",
|
||||
"\n",
|
||||
"Test for the following prime numbers: 91: [Yes] [No]\n",
|
||||
"\n",
|
||||
"421: [Yes] [No]\n",
|
||||
"\n",
|
||||
"1449: [Yes] [No]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7c70d292",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.2 gcd\n",
|
||||
"\n",
|
||||
"Using: here\n",
|
||||
"\n",
|
||||
"Determine the GCD for the following: 88, 46:\n",
|
||||
"\n",
|
||||
"105, 35:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "22cfed86",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.3 Base-64 convertor\n",
|
||||
"\n",
|
||||
"Using: here\n",
|
||||
"\n",
|
||||
"Determine the Base 64 and Hex values for the following strings:\n",
|
||||
"\n",
|
||||
"Hello:\n",
|
||||
"\n",
|
||||
"hello:\n",
|
||||
"\n",
|
||||
"HELLO:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "41348372",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.4 Base-64 convertor\n",
|
||||
"\n",
|
||||
"Using: here\n",
|
||||
"\n",
|
||||
"Determine the following ASCII strings for these encoded formats:\n",
|
||||
"\n",
|
||||
"bGxveWRz\n",
|
||||
"6E6170696572\n",
|
||||
"01000001 01101110 01101011 01101100 01100101 00110001 00110010 00110011\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cb873433",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.5 The mod operator\n",
|
||||
"\n",
|
||||
"Using Python, what is the result of 53,431 (mod 453)?\n",
|
||||
"\n",
|
||||
"In Python, this is:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2d9dc064",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print (53431 % 453)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e2bf6a52",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.6 Bitwise operations\n",
|
||||
"Using Python, what is the results of the following:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9f6d382a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print (0x43 | 0x21)\n",
|
||||
"print (0x43 & 0x21)\n",
|
||||
"print (0x43 ^ 0x21)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7c4bcb4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In this case, \"|\" does a bitwise OR, \"&\" does a bitwise AND, and \"^\" does a bitwise X-OR. Using a pen and paper, prove that these results are correct. Results:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "23c4d2f7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.7 Hex, Oct, Char and Binary\n",
|
||||
"\n",
|
||||
"Using Python, what is the hex, octal, character, and binary equivalents of the value of 93:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4ca29ad0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"val1=93\n",
|
||||
"print (\"Dec:\\t\",val1)\n",
|
||||
"print (\"Bin:\\t\",bin(val1))\n",
|
||||
"print (\"Hex:\\t\",hex(val1))\n",
|
||||
"print (\"Oct:\\t\",oct(val1))\n",
|
||||
"print (\"Char:\\t\",chr(val1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3193073d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"## A.8 Node.js\n",
|
||||
"\n",
|
||||
"JavaScript is often used in cryptography. Using node.js, repeat A.7.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "eea0739b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "NameError",
|
||||
"evalue": "name 'console' is not defined",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
|
||||
"\u001b[0;32m<ipython-input-1-353e49e51dcc>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mval\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m93\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mconsole\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mval\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtoString\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mconsole\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mval\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtoString\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m16\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mconsole\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mval\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtoString\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m8\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mconsole\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mString\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfromCharCode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mval\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
|
||||
"\u001b[0;31mNameError\u001b[0m: name 'console' is not defined"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"val=93\n",
|
||||
"console.log(val.toString(2))\n",
|
||||
"console.log(val.toString(16))\n",
|
||||
"console.log(val.toString(8))\n",
|
||||
"console.log(String.fromCharCode(val))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f56f2f5d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"A.9 Base64\n",
|
||||
"\n",
|
||||
"Using Python, what is the Base-64 conversion for the string of “crypto”?\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e348a9ae",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import base64\n",
|
||||
"str='crypto'\n",
|
||||
"print (base64.b64encode(str.encode()))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "49065b48",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"## Base64\n",
|
||||
"If we use a string of \"crypto1\", what do you observe from the Base64 conversion compared to the result in the previous question (A.9)? Observation:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "86ef2106",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.11 Bit shift\n",
|
||||
"\n",
|
||||
"Using Python, using a decimal value of 41, determine the result of a shift left by one bit, a shift left by two bits, a right shift by one bit, and a right shift by two bits:\n",
|
||||
"\n",
|
||||
"Web link (Bit shift): here\n",
|
||||
"\n",
|
||||
"Decimal form: 41\n",
|
||||
"\n",
|
||||
"Shift left (1):\n",
|
||||
"\n",
|
||||
"Shift left (2):\n",
|
||||
"\n",
|
||||
"Shift right(1):\n",
|
||||
"\n",
|
||||
"Shift right(2):\n",
|
||||
"\n",
|
||||
"Why would a shift left or shift right operator not be used on its own in cryptography?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a87e860c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.12 Factors\n",
|
||||
"\n",
|
||||
"In several cases in cryptography, we try and factorize a value into its factors. An example is 15, and which has factors of 5 and 3. Using the Python program defined in the following link, determine the factors of 432:\n",
|
||||
"\n",
|
||||
"Web link (Factorization): here\n",
|
||||
"\n",
|
||||
"Think of two extremely large values and determine their factors."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "db2c5f72",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A.13 Compression\n",
|
||||
"\n",
|
||||
"Another format we can use for our data is compression, and we can do the compression before or after the encryption process. One of the most popular methods is gzip compress, and which uses the LZ method to reduce the number of bits used. For this we will use node.js. Create a file named a_13.js and determine what the following Base64 conversions are when they are uncompressed (Hint: they are cities of the World):\n",
|
||||
"\n",
|
||||
"Web link (Compression): here\n",
|
||||
"\n",
|
||||
"Take a string of “abc” and compress it, and now keep building up the string with the same sequence (such as “abcabc…”). What do you observe from the length of the compression string if you use a random characters of the same length as an input:\n",
|
||||
"\n",
|
||||
"eJzzyc9Lyc8DAAgpAms=\n",
|
||||
"eJxzSi3KycwDAAfXAl0=\n",
|
||||
"eJzzSy1XiMwvygYADKUC8A=="
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "base",
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
996
z_jupyter/02_symmetric_key.ipynb
Normal file
@@ -0,0 +1,996 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "509b908c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Symmetric Key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e8a9af38",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Introduction\n",
|
||||
"\n",
|
||||
"Symmetric key encryption involves the same key being used to encrypt and decrypt:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" Apart from ECB mode, we also normally apply a salt value known as an IV (Initialization Vector). The main modes are ECB (Electronic Code Book), CBC (Cipher Block Chaining), CTR (Counter), OFB (Output Feedback) and GCM (Galois/Counter Mode). Overall, Bob and Alice will share the same encryption key, and covert plaintext into ciphertext for the encryption key, and then from ciphertext to plaintext when we decrypt. Overall, Bob and Alice share the same key, and where Eve will find it difficult to find the key.\n",
|
||||
" \n",
|
||||
" ## Block cipher\n",
|
||||
"\n",
|
||||
" With a block cipher, we take the plaintext data, and split it into blocks. This block size can vary between different ciphers, but will typically be 128 bits (16 bytes). Some older symmetric key methods, such as DES and 3DES, use a 64-bit block size (8 bytes). \n",
|
||||
" \n",
|
||||
" \n",
|
||||
" \n",
|
||||
" In the following, we define a message, and then the number of bytes per block (n). We can then check the value of n to change the size of the block. For the last block, we will pad with the space character:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "9a64a147",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message: Hello how are you?\n",
|
||||
"Bytes per block: 8\n",
|
||||
"\n",
|
||||
"Blocks ...\n",
|
||||
"Block [ 0 ] Hello ho\n",
|
||||
"Block [ 1 ] w are yo\n",
|
||||
"Block [ 2 ] u? \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/encryption/blk\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"BLOCKSIZE = 8\n",
|
||||
"n=BLOCKSIZE\n",
|
||||
"message=\"Hello how are you?\"\n",
|
||||
"\n",
|
||||
"print (\"Message:\",message)\n",
|
||||
"print (\"Bytes per block:\",n)\n",
|
||||
"print (\"\\nBlocks ...\")\n",
|
||||
"\n",
|
||||
"message = [message[i: i + n] for i in range(0, len(message), n)]\n",
|
||||
"\n",
|
||||
"lengthOfLastBlock = len(message[len(message)-1])\n",
|
||||
"\n",
|
||||
"if ( lengthOfLastBlock < BLOCKSIZE):\n",
|
||||
"\tfor i in range(lengthOfLastBlock, BLOCKSIZE):\n",
|
||||
" \t\tmessage[len(message)-1] += \" \"\n",
|
||||
"\n",
|
||||
"i=0\n",
|
||||
"for b in message:\n",
|
||||
"\tprint ('Block [',i,']',b)\n",
|
||||
"\ti=i+1\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1dbd2658",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> For a message of \"This is a test message.\". How many blocks will be used for a 64-bit block size?\n",
|
||||
"> For a message of \"This is a test message.\". How many blocks will be used for a 128-bit block size?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ec4619c5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
" \n",
|
||||
" ### Padding with PKCS7\n",
|
||||
"In the last block, we may not have enough bytes to fill it up. We thus need to add padding bytes before the encryption, and then remove after we decrypt. The most typical way that we pad is with PKCS7, and where we find out the number of bytes that we need to pad for the last block, and then take that value and repeat it for the number of bytes we need to pad. in the following, we have size as the number of bits in a block, and a message. For \"abc\" and for a block size of 128 bits (16 bytes), we will have 13 filling bytes. The value of 13 is represented as 0xd:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "30efb5d0",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message: abcde\n",
|
||||
"Block size: 128\n",
|
||||
"Padded: 61626364650b0b0b0b0b0b0b0b0b0b0b\n",
|
||||
"Unpadded: abcde\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/hazmat/hashnew28\n",
|
||||
"\n",
|
||||
"from cryptography.hazmat.primitives import padding\n",
|
||||
"import sys\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"size=128\n",
|
||||
"message=\"abcde\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"Message: \",message)\n",
|
||||
"print (\"Block size: \",size)\n",
|
||||
"\n",
|
||||
"message=message.encode()\n",
|
||||
"padder = padding.PKCS7(size).padder()\n",
|
||||
"padded_data = padder.update(message)\n",
|
||||
"\n",
|
||||
"padded_data += padder.finalize()\n",
|
||||
"print (\"Padded: \",binascii.hexlify(padded_data).decode())\n",
|
||||
"\n",
|
||||
"unpadder = padding.PKCS7(size).unpadder()\n",
|
||||
"data = unpadder.update(padded_data)\n",
|
||||
"\n",
|
||||
"unpadded = data + unpadder.finalize()\n",
|
||||
"\n",
|
||||
"print (\"Unpadded: \",unpadded.decode())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b909868d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> For a message of \"hello\" and a block size of 128 bits. What is the padding value?\"\n",
|
||||
"> For a message of \"The boy stood on the burning deck!\" and a block size of 128 bits. What is the padding value?\"\n",
|
||||
"> What will happen when we have 18 characters in the plaintext. Will we have one block or two, and what will the padding value be?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "10722ff1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
" ## AES encryption\n",
|
||||
" \n",
|
||||
" The most popular symmetric key method is AES (Advanced Encryption Standard), and which was defined as a standard by NIST. It has a 128-bit block (16 bytes) and can use a 128-bit, 192-bit or 256-bit encryption key. We then have a number of modes that can be used. The most basic mode is ECB (Electronic Code Book), and which basically just applies the encryption key to each block:\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"In the following, we apply create AES encryption with ECB mode:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "11f31dd9",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message:\t Hello\n",
|
||||
"Key:\t b'dd87fcbf7b6d0a43b339e4cab145e8c3520649a6fcbf7cebdc1af053999cd20c'\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"=== AES ECB === \n",
|
||||
"Cipher: b'f52c9d5089181d25bf57221d49a2d256'\n",
|
||||
"Decrypted: Hello\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 02_01.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew4\n",
|
||||
"import os\n",
|
||||
"from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes \n",
|
||||
"from cryptography.hazmat.primitives import padding\n",
|
||||
"import sys\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"def go_encrypt(msg,method,mode):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" encryptor = cipher.encryptor()\n",
|
||||
" ct = encryptor.update(msg) + encryptor.finalize()\n",
|
||||
" return (ct)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def go_decrypt(ct,method,mode):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" decryptor = cipher.decryptor()\n",
|
||||
" return (decryptor.update(ct) + decryptor.finalize())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def pad(data,size=128):\n",
|
||||
" padder = padding.PKCS7(size).padder()\n",
|
||||
" padded_data = padder.update(data)\n",
|
||||
" padded_data += padder.finalize()\n",
|
||||
" return(padded_data)\n",
|
||||
"\n",
|
||||
"def unpad(data,size=128):\n",
|
||||
" padder = padding.PKCS7(size).unpadder()\n",
|
||||
" unpadded_data = padder.update(data)\n",
|
||||
" unpadded_data += padder.finalize()\n",
|
||||
" return(unpadded_data)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"key = os.urandom(32)\n",
|
||||
"\n",
|
||||
"msg=b\"Hello\"\n",
|
||||
"\n",
|
||||
"print (\"Message:\\t\",msg.decode())\n",
|
||||
"print (\"Key:\\t\",binascii.b2a_hex(key))\n",
|
||||
"\n",
|
||||
"padded_data=pad(msg)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"\\n\\n=== AES ECB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.ECB())\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.ECB())\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "96dae988",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> With a message of \"Hello123\". What is the ciphertext in hexadecimal?\n",
|
||||
"> If you encrypt the same message, do the message change?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "69c8303b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Additional Modes\n",
|
||||
"The problem with ECB, is that the output cipher is always the same for the same plaintext input. To overcome this, we can add an Initialisation Vector (IV) or salt. This is normally a random value that is greater than 64 bits. The cipher is then stored with the IV, and when we decrypt, we need both the encryption key and the salt value. With CBC (Cipher Block Chaining), we add salt into the first block encryption, and then chain the output of this into the next block, and so on:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"In the following, we use the cipher modes of CBC, OBF, CFB and CTR, and where we add a random salt value:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "704df22b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message:\t Hello\n",
|
||||
"Key:\t b'4cf24c4b7435aeb48e92f93f614dccc4d4e2b712867b1cabd0fafb80f1ab7d6b'\n",
|
||||
"IV:\t b'e476433e82a1bf574af60eff91832e52'\n",
|
||||
"=== AES CBC === \n",
|
||||
"Cipher: b'bdf3405006a681a750ed2f692e58278c'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== AES OFB === \n",
|
||||
"Cipher: b'a59ba9e04357114e348ea440317e149b'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== AES CFB === \n",
|
||||
"Cipher: b'a59ba9e04357114e348ea440317e149b'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== AES CTR === \n",
|
||||
"Cipher: b'a59ba9e04357114e348ea440317e149b'\n",
|
||||
"Decrypted: Hello\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 02_02.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew4\n",
|
||||
"import os\n",
|
||||
"from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes \n",
|
||||
"from cryptography.hazmat.primitives import padding\n",
|
||||
"import sys\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"def go_encrypt(msg,method,mode):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" encryptor = cipher.encryptor()\n",
|
||||
" ct = encryptor.update(msg) + encryptor.finalize()\n",
|
||||
" return (ct)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def go_decrypt(ct,method,mode):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" decryptor = cipher.decryptor()\n",
|
||||
" return (decryptor.update(ct) + decryptor.finalize())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def pad(data,size=128):\n",
|
||||
" padder = padding.PKCS7(size).padder()\n",
|
||||
" padded_data = padder.update(data)\n",
|
||||
" padded_data += padder.finalize()\n",
|
||||
" return(padded_data)\n",
|
||||
"\n",
|
||||
"def unpad(data,size=128):\n",
|
||||
" padder = padding.PKCS7(size).unpadder()\n",
|
||||
" unpadded_data = padder.update(data)\n",
|
||||
" unpadded_data += padder.finalize()\n",
|
||||
" return(unpadded_data)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"key = os.urandom(32)\n",
|
||||
"iv = os.urandom(16)\n",
|
||||
"msg=b\"Hello\"\n",
|
||||
"\n",
|
||||
"print (\"Message:\\t\",msg.decode())\n",
|
||||
"print (\"Key:\\t\",binascii.b2a_hex(key))\n",
|
||||
"print (\"IV:\\t\",binascii.b2a_hex(iv))\n",
|
||||
"\n",
|
||||
"padded_data=pad(msg)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"=== AES CBC === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CBC(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.CBC(iv))\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"=== AES OFB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.OFB(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.OFB(iv))\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== AES CFB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CFB(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.CFB(iv))\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== AES CTR === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CTR(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.CTR(iv))\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "110beed2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> What is the size of the IV?\n",
|
||||
"> What is the size of the key used?\n",
|
||||
"> For each run, do you get a different cipher for the same input?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "23a803f5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Stream ciphers\n",
|
||||
"With a stream cipher, we take the salt value and some randomization, and create an infinitely long key stream. With this key, we then XOR each bit of the plaintext stream with the key stream. This makes the cipher much faster than a block cipher, and where the main overhead is the key stream generation:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"One of the main methods that we use for a stream cipher is ChaCha20, and which provides an alterative to AES. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "718d27a4",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message:\t Hello\n",
|
||||
"Key:\t b'ca472445b83c22523cb4f25ce14c1f21c74294b1672f89a9a570f865794c004a'\n",
|
||||
"IV:\t b'064c1792484091dd65e70ec5a81ea6d9'\n",
|
||||
"\n",
|
||||
"=== ChaCha20 === \n",
|
||||
"Cipher: b'f36e696aa3'\n",
|
||||
"Decrypted: Hello\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 02_03.py\n",
|
||||
"# https://asecuritysite.com/symmetric/hashnew4\n",
|
||||
"import os\n",
|
||||
"from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes \n",
|
||||
"from cryptography.hazmat.primitives import padding\n",
|
||||
"import sys\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"def go_encrypt(msg,method,mode):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" encryptor = cipher.encryptor()\n",
|
||||
" ct = encryptor.update(msg) + encryptor.finalize()\n",
|
||||
" return (ct)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def go_decrypt(ct,method,mode):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" decryptor = cipher.decryptor()\n",
|
||||
" return (decryptor.update(ct) + decryptor.finalize())\n",
|
||||
"\n",
|
||||
"def go_encrypt_with_auth(msg,method,mode,add):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" encryptor = cipher.encryptor()\n",
|
||||
" encryptor.authenticate_additional_data(add)\n",
|
||||
" ct = encryptor.update(msg) + encryptor.finalize()\n",
|
||||
" return (ct,encryptor.tag)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def go_decrypt_with_auth(ct,method,mode,add):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" decryptor = cipher.decryptor()\n",
|
||||
" decryptor.authenticate_additional_data(add)\n",
|
||||
" pl=decryptor.update(ct) + decryptor.finalize()\n",
|
||||
" return (pl)\n",
|
||||
"\n",
|
||||
"def pad(data,size=128):\n",
|
||||
" padder = padding.PKCS7(size).padder()\n",
|
||||
" padded_data = padder.update(data)\n",
|
||||
" padded_data += padder.finalize()\n",
|
||||
" return(padded_data)\n",
|
||||
"\n",
|
||||
"def unpad(data,size=128):\n",
|
||||
" padder = padding.PKCS7(size).unpadder()\n",
|
||||
" unpadded_data = padder.update(data)\n",
|
||||
" unpadded_data += padder.finalize()\n",
|
||||
" return(unpadded_data)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"key = os.urandom(32)\n",
|
||||
"iv = os.urandom(16)\n",
|
||||
"msg=b\"Hello\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"Message:\\t\",msg.decode())\n",
|
||||
"print (\"Key:\\t\",binascii.b2a_hex(key))\n",
|
||||
"print (\"IV:\\t\",binascii.b2a_hex(iv))\n",
|
||||
"\n",
|
||||
"padded_data=pad(msg)\n",
|
||||
"\n",
|
||||
"print (\"\\n=== ChaCha20 === \")\n",
|
||||
"\n",
|
||||
"cipher=go_encrypt(msg,algorithms.ChaCha20(key,iv), None)\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.ChaCha20(key,iv), None)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {plain.decode()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "082cd7f3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> What is the size of the salt value used?\n",
|
||||
"\n",
|
||||
"> What is the size of the key used?\n",
|
||||
"\n",
|
||||
"> Run the ChaCha20 code, and determine the number of bytes in the cipher for \"Hello\", \"Hello1\" and \"Hello2\". What can you say about the relationship between the plaintext size and the ciphertext size?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4c17ac2c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## AES GCM \n",
|
||||
"The most popular symmetric key method is AES GCM, and which is a stream cipher which uses AES encryption. It also adds an authentication tag, so that the cipher can be checked that is have not changed.\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"The following provides the sample sample code, and where we add in some additional data (AE). This method is known as AEAD (Authenticated Encryption with Additional Data):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "db724b07",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message:\t Hello\n",
|
||||
"Key:\t b'3459f49cb7b8ae9b1dcbb390525ff6b9add7fa0f377ea28f3fff8d28b7b097e5'\n",
|
||||
"IV:\t b'e41b966e55930acd56d5e3dea466d09c'\n",
|
||||
"=== AES GCM === \n",
|
||||
"Cipher: b'b4c55b4769'\n",
|
||||
"Decrypted: Hello\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 02_04.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew4\n",
|
||||
"import os\n",
|
||||
"from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes \n",
|
||||
"from cryptography.hazmat.primitives import padding\n",
|
||||
"import sys\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def go_encrypt_with_auth(msg,method,mode,add):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" encryptor = cipher.encryptor()\n",
|
||||
" encryptor.authenticate_additional_data(add)\n",
|
||||
" ct = encryptor.update(msg) + encryptor.finalize()\n",
|
||||
" return (ct,encryptor.tag)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def go_decrypt_with_auth(ct,method,mode,add):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" decryptor = cipher.decryptor()\n",
|
||||
" decryptor.authenticate_additional_data(add)\n",
|
||||
" pl=decryptor.update(ct) + decryptor.finalize()\n",
|
||||
" return (pl)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"key = os.urandom(32)\n",
|
||||
"iv = os.urandom(16)\n",
|
||||
"msg=b\"Hello\"\n",
|
||||
"tag= b\"Some data for the authentication tag\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"Message:\\t\",msg.decode())\n",
|
||||
"print (\"Key:\\t\",binascii.b2a_hex(key))\n",
|
||||
"print (\"IV:\\t\",binascii.b2a_hex(iv))\n",
|
||||
"\n",
|
||||
"padded_data=pad(msg)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"=== AES GCM === \")\n",
|
||||
"# In GCM mode we convert to a stream cipher, so there is no need for padding\n",
|
||||
"cipher,auth_tag=go_encrypt_with_auth(msg,algorithms.AES(key), modes.GCM(iv),tag)\n",
|
||||
"\n",
|
||||
"plain=go_decrypt_with_auth(cipher,algorithms.AES(key), modes.GCM(iv,auth_tag),tag)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {plain.decode()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6c29af0e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Verify that the cipher changes for each run.\n",
|
||||
"\n",
|
||||
"> What do we not need to pad in this code?\n",
|
||||
"\n",
|
||||
"> If you change the tag before the decryption, does the cipher decrypt?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4c190297",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
" \n",
|
||||
" ## Additional Ciphers\n",
|
||||
" There are many other symmetric key methods supported in the cryptography library. This includes implement AES, Chacha20, Camellia, 3DES, IDEA, CAST5 and Blowfish. The following Python program will use a random 256-bit encryption key, and a random 128-bit IV value. In most of the modes, we need to pad the plaintext to the size of the block (typically this is 128 bits or 16 bytes), but AES GCM mode we do not need to pad the cipher as it is a stream cipher."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "1fed6488",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message:\t Hello\n",
|
||||
"Key:\t b'394f66d40b7ff08e054f155d581299feeee5dd4c346f455432cf280003b65cc9'\n",
|
||||
"IV:\t b'783992db351505f6e4455ece244288b1'\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"=== AES ECB === \n",
|
||||
"Cipher: b'8d18d2608555aafa6c49a867a3df7da3'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== AES CBC === \n",
|
||||
"Cipher: b'e883fc6c0b568e984f37b5be0660990d'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== AES OFB === \n",
|
||||
"Cipher: b'39dccf1ec235d002ca472abe03e9cc98'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== AES CFB === \n",
|
||||
"Cipher: b'39dccf1ec235d002ca472abe03e9cc98'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== AES CTR === \n",
|
||||
"Cipher: b'39dccf1ec235d002ca472abe03e9cc98'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== AES GCM === \n",
|
||||
"Cipher: b'38426fbe32'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== AES XTS === \n",
|
||||
"Cipher: b'dbc50e1f568ac761307228c06a11c6a2'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"\n",
|
||||
"=== Blowfish ECB === \n",
|
||||
"Cipher: b'0d3166526e87a287e20dbbca5068a253'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== Blowfish CBC === \n",
|
||||
"Cipher: b'bdb3d83379e84e42de2c68cfc6100cd8'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"\n",
|
||||
"=== ChaCha20 === \n",
|
||||
"Cipher: b'3aa44314ab'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"\n",
|
||||
"=== 3DES ECB === \n",
|
||||
"Cipher: b'ee9fbc2a9e2ab17d9294e35946806f88'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== 3DES CBC === \n",
|
||||
"Cipher: b'41521ecf924f5aac9a3043e9de7f4c98'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"\n",
|
||||
"=== Camellia ECB === \n",
|
||||
"Cipher: b'115c858dbb2b404788f4aca3be95ecbe'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== Camellia CBC === \n",
|
||||
"Cipher: b'b87a6aa181ccc4f0ff16af4662d5a500'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== IDEA ECB === \n",
|
||||
"Cipher: b'880a57ed61680708eb9bd39e0d3e6942'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== IDEA CBC === \n",
|
||||
"Cipher: b'1479e18fd3dc95bb899d1eda3476f271'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"\n",
|
||||
"=== CAST5 ECB === \n",
|
||||
"Cipher: b'72c565e0207e7afbbbf9e0f53fbd29a0'\n",
|
||||
"Decrypted: Hello\n",
|
||||
"=== CAST5 CBC === \n",
|
||||
"Cipher: b'3c21106fb5e60aeb8421a974cbe98674'\n",
|
||||
"Decrypted: Hello\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 02_05.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew4\n",
|
||||
"import os\n",
|
||||
"from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes \n",
|
||||
"from cryptography.hazmat.primitives import padding\n",
|
||||
"import sys\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"def go_encrypt(msg,method,mode):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" encryptor = cipher.encryptor()\n",
|
||||
" ct = encryptor.update(msg) + encryptor.finalize()\n",
|
||||
" return (ct)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def go_decrypt(ct,method,mode):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" decryptor = cipher.decryptor()\n",
|
||||
" return (decryptor.update(ct) + decryptor.finalize())\n",
|
||||
"\n",
|
||||
"def go_encrypt_with_auth(msg,method,mode,add):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" encryptor = cipher.encryptor()\n",
|
||||
" encryptor.authenticate_additional_data(add)\n",
|
||||
" ct = encryptor.update(msg) + encryptor.finalize()\n",
|
||||
" return (ct,encryptor.tag)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def go_decrypt_with_auth(ct,method,mode,add):\n",
|
||||
" cipher = Cipher(method, mode,backend=default_backend())\n",
|
||||
" decryptor = cipher.decryptor()\n",
|
||||
" decryptor.authenticate_additional_data(add)\n",
|
||||
" pl=decryptor.update(ct) + decryptor.finalize()\n",
|
||||
" return (pl)\n",
|
||||
"\n",
|
||||
"def pad(data,size=128):\n",
|
||||
" padder = padding.PKCS7(size).padder()\n",
|
||||
" padded_data = padder.update(data)\n",
|
||||
" padded_data += padder.finalize()\n",
|
||||
" return(padded_data)\n",
|
||||
"\n",
|
||||
"def unpad(data,size=128):\n",
|
||||
" padder = padding.PKCS7(size).unpadder()\n",
|
||||
" unpadded_data = padder.update(data)\n",
|
||||
" unpadded_data += padder.finalize()\n",
|
||||
" return(unpadded_data)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"key = os.urandom(32)\n",
|
||||
"iv = os.urandom(16)\n",
|
||||
"msg=b\"Hello\"\n",
|
||||
"tag= b\"Some data for the authentication tag\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"Message:\\t\",msg.decode())\n",
|
||||
"print (\"Key:\\t\",binascii.b2a_hex(key))\n",
|
||||
"print (\"IV:\\t\",binascii.b2a_hex(iv))\n",
|
||||
"\n",
|
||||
"padded_data=pad(msg)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"\\n\\n=== AES ECB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.ECB())\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.ECB())\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CBC(iv))\n",
|
||||
"\n",
|
||||
"print (\"=== AES CBC === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CBC(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.CBC(iv))\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CBC(iv))\n",
|
||||
"\n",
|
||||
"print (\"=== AES OFB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.OFB(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.OFB(iv))\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== AES CFB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CFB(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.CFB(iv))\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== AES CTR === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CTR(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.CTR(iv))\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== AES GCM === \")\n",
|
||||
"# In GCM mode we convert to a stream cipher, so there is no need for padding\n",
|
||||
"cipher,auth_tag=go_encrypt_with_auth(msg,algorithms.AES(key), modes.GCM(iv),tag)\n",
|
||||
"\n",
|
||||
"plain=go_decrypt_with_auth(cipher,algorithms.AES(key), modes.GCM(iv,auth_tag),tag)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {plain.decode()}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"=== AES XTS === \")\n",
|
||||
"# In XTS the iv value is known as a tweak - and relates to the sector number\n",
|
||||
"# The keys are double length, so that a 32 byte key (256 bits) is actually AES-128\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.AES(key), modes.XTS(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.AES(key), modes.XTS(iv))\n",
|
||||
"data=unpad(plain)\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"\\n=== Blowfish ECB === \")\n",
|
||||
"\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.Blowfish(key), modes.ECB())\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.Blowfish(key), modes.ECB())\n",
|
||||
"\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== Blowfish CBC === \")\n",
|
||||
"\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.Blowfish(key), modes.CBC(iv[:8]))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.Blowfish(key), modes.CBC(iv[:8]))\n",
|
||||
"\n",
|
||||
"data=unpad(plain)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"\\n=== ChaCha20 === \")\n",
|
||||
"\n",
|
||||
"cipher=go_encrypt(msg,algorithms.ChaCha20(key,iv), None)\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.ChaCha20(key,iv), None)\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"\\n=== 3DES ECB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.TripleDES(key[:16]), modes.ECB())\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.TripleDES(key[:16]), modes.ECB())\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== 3DES CBC === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.TripleDES(key[:16]), modes.CBC(iv[:8]))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.TripleDES(key[:16]), modes.CBC(iv[:8]))\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"\\n=== Camellia ECB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.Camellia(key), modes.ECB())\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.Camellia(key), modes.ECB())\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"=== Camellia CBC === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.Camellia(key), modes.CBC(iv))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.Camellia(key), modes.CBC(iv))\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== IDEA ECB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.IDEA(key[:16]), modes.ECB())\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.IDEA(key[:16]), modes.ECB())\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== IDEA CBC === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.IDEA(key[:16]), modes.CBC(iv[:8]))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.IDEA(key[:16]), modes.CBC(iv[:8]))\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"\\n=== CAST5 ECB === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.CAST5(key[:16]), modes.ECB())\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.CAST5(key[:16]), modes.ECB())\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")\n",
|
||||
"\n",
|
||||
"print (\"=== CAST5 CBC === \")\n",
|
||||
"cipher=go_encrypt(padded_data,algorithms.CAST5(key[:16]), modes.CBC(iv[:8]))\n",
|
||||
"\n",
|
||||
"plain=go_decrypt(cipher,algorithms.CAST5(key[:16]), modes.CBC(iv[:8]))\n",
|
||||
"\n",
|
||||
"print (\"Cipher: \",binascii.b2a_hex(cipher))\n",
|
||||
"print (f\"Decrypted: {data.decode()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "02727c7e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Computing time to crack symmetric key with brute force\n",
|
||||
"If we have x bits for a symmetric key, we will then have 2^x different keys. If we assume that it takes t seconds to try a single key, then the total time to crack will be:\n",
|
||||
"\n",
|
||||
"T = 2^x * t\n",
|
||||
"\n",
|
||||
"Overall, the average time will be half of this value. For example, if we have a 32-bit key and can crack for 1 nanosecond per key, we can compute the average time with:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "bb4410df",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Time to crack = 18446744073.709553 seconds\n",
|
||||
"Time to crack = 213503.9823346013 days\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x=32\n",
|
||||
"keys=2**x\n",
|
||||
"t=1e-9\n",
|
||||
"\n",
|
||||
"time=keys*t\n",
|
||||
"print(f\"Time to crack = {time/2} seconds\")\n",
|
||||
"print(f\"Time to crack = {time/2/60/60} hours\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6f21c025",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Modify the program to show the number of days to crack.\n",
|
||||
"> For a 64 bit key, and 1 pico second crack per key, what is the average cracking time in days?"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
480
z_jupyter/03_hashing.ipynb
Normal file
@@ -0,0 +1,480 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7782a35",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# Hashing\n",
|
||||
"Within hashing methods, we take data in the form of a byte array, and then create a fixed length hash value. For MD5, the length of the hash is 128 bits, for SHA-1 it is 160 bits, and for SHA-256, it is 256 bits. \n",
|
||||
"\n",
|
||||
"<img src='graphics/g_hash_01.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"These hashes include MD5, SHA-1 and SHA-256. With MD5 we get a 128-bit output, and which is 32 hex characters:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_hash_02.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"SHA-1 has an output of 160 bits, and SHA-256 has an output of 256 bits. MD5 should not be used in production environments as the method has weaknesses, along with the output hash begin too short. SHA-1, too, has been shown to have weaknesses, and thus we should use SHA-2 methods. These include SHA224, SHA-256, SHA-384 and SHA-512. A newer standard is known as SHA-3. \n",
|
||||
"\n",
|
||||
"<img src='graphics/g_hash_04.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## OpenSSL hashing\n",
|
||||
"OpenSSL can be used to create hash values for SHA1, SHA-256, and other methods. An example for Linux and Windows is [<a href=\"https://asecuritysite.com/openssl/openssl_full2\">here</a>]:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"Linux command: echo -n \"Hello\" | openssl dgst -md5\n",
|
||||
"Windows command: echo | set /p = \"Hello\" | openssl dgst -md5\n",
|
||||
"\n",
|
||||
"Message: Hello\n",
|
||||
"Mode: md5\n",
|
||||
"========\n",
|
||||
"MD5d1a7fb5eab1c16cb4f7cf341cf188c3d\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cd0b8fe6",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Using OpenSSL in the command prompt, or using this site [<a href=\"https://asecuritysite.com/openssl/openssl_full2\">here</a>], determine the hash values SHA-1 and SHA-256 hash values for: \"Edinburgh\" and \"Glasgow\".\n",
|
||||
"> Do the hash values change when we use \"edinburgh\" and \"glasgow\"?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "09119c37",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## MD5 and SHA-1\n",
|
||||
"In the following we will use the hashing methods supported by the Hazmat primitive. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"id": "e88c246d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Data: Hello\n",
|
||||
" Hex: 48656c6c6f\n",
|
||||
"MD5: 8b1a9953c4611296a827abf8c47804d7 ixqZU8RhEpaoJ6v4xHgE1w==\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 03_01.py\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"st = \"Hello\"\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" data=st.encode() # Convert to a byte array\n",
|
||||
"\n",
|
||||
" digest = hashes.Hash(hashes.MD5(),backend=default_backend())\n",
|
||||
" digest.update(data)\n",
|
||||
" res=digest.finalize()\n",
|
||||
" hexval=binascii.b2a_hex(res).decode() # hex format\n",
|
||||
" b64val=binascii.b2a_base64(res).decode() # Base64 format\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" print (\"Data: \",st)\n",
|
||||
" print (\" Hex: \",binascii.b2a_hex(data).decode())\n",
|
||||
" print (f\"MD5: {hexval} {b64val}\")\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f916c2c0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"\n",
|
||||
"> Can you determine the hash value for \"Hello\"?\n",
|
||||
"\n",
|
||||
"> Now modify Line 11 in the program below to give SHA1() and also SHA256(). What are the values (list the first two hex characters)?\n",
|
||||
"\n",
|
||||
"> What is the length of the hash (in bits) for SHA-1?\n",
|
||||
"\n",
|
||||
"> What is the lenguth of the hash (in bits) for SHA-256?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ee4c4c0e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Two of the main formats for hashing are hexademical and Base64. In this example, we will use the binascii library to convert our data into a hash value:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_hash_05.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"In this case, we will use other hashing methods such as Blake2, SHA-3, SHA-224, SHA-384 and SHA-512:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"id": "5b576b95",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Data: hello\n",
|
||||
" Hex: 68656c6c6f\n",
|
||||
"\n",
|
||||
"MD5: 5d41402abc4b2a76b9719d911017c592 XUFAKrxLKna5cZ2REBfFkg==\n",
|
||||
"\n",
|
||||
"SHA1: aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d qvTGHdzF6KLavt4PO0gs2a6pQ00=\n",
|
||||
"\n",
|
||||
"SHA224: ea09ae9cc6768c50fcee903ed054556e5bfc8347907f12598aa24193 6gmunMZ2jFD87pA+0FRVblv8g0eQfxJZiqJBkw==\n",
|
||||
"\n",
|
||||
"SHA256: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=\n",
|
||||
"\n",
|
||||
"SHA384: 59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f WeF0h3dEjGnea4ANejO7+5/xtGPkQ1TDVTvNucZm+pASWjx5+QOXvfX2oT3oKGhP\n",
|
||||
"\n",
|
||||
"SHA3_224: b87f88c72702fff1748e58b87e9141a42c0dbedc29a78cb0d4a5cd81 uH+IxycC//F0jli4fpFBpCwNvtwpp4yw1KXNgQ==\n",
|
||||
"\n",
|
||||
"SHA3_256: 3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392 Mzi+aU9QxfM4gUmGzfBoZFOoiLhPQk15KvS5ICOY85I=\n",
|
||||
"\n",
|
||||
"SHA3_384: 720aea11019ef06440fbf05d87aa24680a2153df3907b23631e7177ce620fa1330ff07c0fddee54699a4c3ee0ee9d887 cgrqEQGe8GRA+/Bdh6okaAohU985B7I2MecXfOYg+hMw/wfA/d7lRpmkw+4O6diH\n",
|
||||
"\n",
|
||||
"SHA3_512: 75d527c368f2efe848ecf6b073a36767800805e9eef2b1857d5f984f036eb6df891d75f72d9b154518c1cd58835286d1da9a38deba3de98b5a53e5ed78a84976 ddUnw2jy7+hI7Pawc6NnZ4AIBenu8rGFfV+YTwNutt+JHXX3LZsVRRjBzViDUobR2po43ro96YtaU+XteKhJdg==\n",
|
||||
"\n",
|
||||
"SHA512: 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043 m3HSJL1i83hdltRq0+o9czGb+8KJDKra4t/3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw==\n",
|
||||
"\n",
|
||||
"SHA512_224: fe8509ed1fb7dcefc27e6ac1a80eddbec4cb3d2c6fe565244374061c /oUJ7R+33O/CfmrBqA7dvsTLPSxv5WUkQ3QGHA==\n",
|
||||
"\n",
|
||||
"SHA512_256: e30d87cfa2a75db545eac4d61baf970366a8357c7f72fa95b52d0accb698f13a 4w2Hz6KnXbVF6sTWG6+XA2aoNXx/cvqVtS0KzLaY8To=\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 03_02.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"st = \"hello\"\n",
|
||||
"hex=False\n",
|
||||
"showhex=\"No\"\n",
|
||||
"\n",
|
||||
"def show_hash(name,type,data):\n",
|
||||
" digest = hashes.Hash(type,backend=default_backend())\n",
|
||||
" digest.update(data)\n",
|
||||
" res=digest.finalize()\n",
|
||||
" hex=binascii.b2a_hex(res).decode()\n",
|
||||
" b64=binascii.b2a_base64(res).decode()\n",
|
||||
" print (f\"{name}: {hex} {b64}\")\n",
|
||||
"\n",
|
||||
"if (showhex==\"yes\"): hex=True\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
"\tif (hex==True): data = binascii.a2b_hex(st)\n",
|
||||
"\telse: data=st.encode()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\tprint (\"Data: \",st)\n",
|
||||
"\tprint (\" Hex: \",binascii.b2a_hex(data).decode())\n",
|
||||
"\tprint()\n",
|
||||
"\n",
|
||||
"\tshow_hash(\"MD5\",hashes.MD5(),data)\n",
|
||||
"\tshow_hash(\"SHA1\",hashes.SHA1(),data)\t\n",
|
||||
"\tshow_hash(\"SHA224\",hashes.SHA224(),data)\n",
|
||||
"\tshow_hash(\"SHA256\",hashes.SHA256(),data)\n",
|
||||
"\tshow_hash(\"SHA384\",hashes.SHA384(),data)\n",
|
||||
"\tshow_hash(\"SHA3_224\",hashes.SHA3_224(),data)\n",
|
||||
"\tshow_hash(\"SHA3_256\",hashes.SHA3_256(),data)\n",
|
||||
"\tshow_hash(\"SHA3_384\",hashes.SHA3_384(),data)\n",
|
||||
"\tshow_hash(\"SHA3_512\",hashes.SHA3_512(),data)\n",
|
||||
"\tshow_hash(\"SHA512\",hashes.SHA512(),data)\n",
|
||||
"\tshow_hash(\"SHA512_224\",hashes.SHA512_224(),data)\n",
|
||||
"\tshow_hash(\"SHA512_256\",hashes.SHA512_256(),data)\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "36c0aa30",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"> In this case the input data is \"00\". Can you run the program again, and this time use the data input of \"The quick brown fox jumps over the lazy dog\". Prove that:\n",
|
||||
"\n",
|
||||
"* MD5 hash value is \"9e107d9d372bb6826bd81d3542a419d6\"\n",
|
||||
"* SHA-1 hash value is \"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\"\n",
|
||||
"* SHA-256 hash value is \"d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"> How many hex characters does MD5, SHA-1 and SHA-256, and how would you determine number of characters used?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5d0ef125",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Adding salt\n",
|
||||
"One problem with hashing methods, is that we get the same hash output for the same input. This can allow an intruder to match the hash to the input string. To overcome this, we can add a salt value to the hashing process. This can be to append or prepend the data onto the input data. We obviously need to store the salt value with the hash value, in order to check a hash. \n",
|
||||
"\n",
|
||||
"<img src='graphics/g_hash_08.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"id": "82ee9a0e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Data: hello\n",
|
||||
" Hex: 68656c6c6f\n",
|
||||
"\n",
|
||||
"MD5: bfd9929c0794146bae6dcccb4317e99c v9mSnAeUFGuubczLQxfpnA==\n",
|
||||
"\n",
|
||||
"SHA1: 710fd92d6fa82d1851f9691ba48f29124890761d cQ/ZLW+oLRhR+WkbpI8pEkiQdh0=\n",
|
||||
"\n",
|
||||
"SHA224: 079bb5febb6d8f6d8cdfdd8e63360aa1803170325ed6738bbf62b189 B5u1/rttj22M392OYzYKoYAxcDJe1nOLv2KxiQ==\n",
|
||||
"\n",
|
||||
"SHA256: 5bf84899a6394b4d1ceaf8a28ffe61425a40ddef1a1563321437f8dd388ba0d2 W/hImaY5S00c6viij/5hQlpA3e8aFWMyFDf43TiLoNI=\n",
|
||||
"\n",
|
||||
"SHA384: f5b0fd54d84d07531b579030015b699073efec74491cd62d0e78b217465d77a4cdd9ea5974622ceaecb4acd49da2cf0d 9bD9VNhNB1MbV5AwAVtpkHPv7HRJHNYtDniyF0Zdd6TN2epZdGIs6uy0rNSdos8N\n",
|
||||
"\n",
|
||||
"SHA3_224: b9473057d8131ff11cf1cffeb5f4bdebe972baa131344a3b86c22030 uUcwV9gTH/Ec8c/+tfS96+lyuqExNEo7hsIgMA==\n",
|
||||
"\n",
|
||||
"SHA3_256: 071cdb333657cce85c765a287dbfa3388e430fce8b48b398a08444674965edde BxzbMzZXzOhcdloofb+jOI5DD86LSLOYoIREZ0ll7d4=\n",
|
||||
"\n",
|
||||
"SHA3_384: a1f631cb30bdebc5020cfdc0f7fe59dba5702f3c6f0f418bc756c759ae5e645d213ce81810fed5fc3473793d37beff3d ofYxyzC968UCDP3A9/5Z26VwLzxvD0GLx1bHWa5eZF0hPOgYEP7V/DRzeT03vv89\n",
|
||||
"\n",
|
||||
"SHA3_512: bf033772d578b5b5f27e7025bf04c57ff752d71517175f20fb48785a1e2b3f9f40e5b1d30a0fee24daeb6f1d61240ab938b772faed649feb9db457387e204c7c vwM3ctV4tbXyfnAlvwTFf/dS1xUXF18g+0h4Wh4rP59A5bHTCg/uJNrrbx1hJAq5OLdy+u1kn+udtFc4fiBMfA==\n",
|
||||
"\n",
|
||||
"SHA512: 261e05408898a3afc8d81a8f118a3aee30f04cf110c77087a4fa82a35dcd25fe8cad9e3448f38eb0fcd538ccc91403e61dd72fd57db8ab35b304a3ded7d2ac0b Jh4FQIiYo6/I2BqPEYo67jDwTPEQx3CHpPqCo13NJf6MrZ40SPOOsPzVOMzJFAPmHdcv1X24qzWzBKPe19KsCw==\n",
|
||||
"\n",
|
||||
"SHA512_224: 00b5af9dec28d8d3d69cedea1c093eb0568882b62a81f52265e99089 ALWvnewo2NPWnO3qHAk+sFaIgrYqgfUiZemQiQ==\n",
|
||||
"\n",
|
||||
"SHA512_256: ba41801fb5b9c05853c4628a0816eacabbe55f767fa040790fcba7d5e60aeec3 ukGAH7W5wFhTxGKKCBbqyrvlX3Z/oEB5D8un1eYK7sM=\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 03_03.py\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"st = \"hello\"\n",
|
||||
"salt = \"N20\"\n",
|
||||
"hex=False\n",
|
||||
"showhex=\"No\"\n",
|
||||
"\n",
|
||||
"def show_hash(name,type,data,salt):\n",
|
||||
" digest = hashes.Hash(type,backend=default_backend())\n",
|
||||
" digest.update(salt)\n",
|
||||
" digest.update(data)\n",
|
||||
" res=digest.finalize()\n",
|
||||
" hex=binascii.b2a_hex(res).decode()\n",
|
||||
" b64=binascii.b2a_base64(res).decode()\n",
|
||||
" print (f\"{name}: {hex} {b64}\")\n",
|
||||
"\n",
|
||||
"if (showhex==\"yes\"): hex=True\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
"\tif (hex==True): data = binascii.a2b_hex(st)\n",
|
||||
"\telse: data=st.encode()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\tprint (\"Data: \",st)\n",
|
||||
"\tprint (\" Hex: \",binascii.b2a_hex(data).decode())\n",
|
||||
"\tprint()\n",
|
||||
"\n",
|
||||
"\tshow_hash(\"MD5\",hashes.MD5(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA1\",hashes.SHA1(),data,salt.encode())\t\n",
|
||||
"\tshow_hash(\"SHA224\",hashes.SHA224(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA256\",hashes.SHA256(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA384\",hashes.SHA384(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA3_224\",hashes.SHA3_224(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA3_256\",hashes.SHA3_256(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA3_384\",hashes.SHA3_384(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA3_512\",hashes.SHA3_512(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA512\",hashes.SHA512(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA512_224\",hashes.SHA512_224(),data,salt.encode())\n",
|
||||
"\tshow_hash(\"SHA512_256\",hashes.SHA512_256(),data,salt.encode())\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c4eac92e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Verify that the hash value changes for different salt values.\n",
|
||||
"\n",
|
||||
"> Rather than a string for the salt value. Can you modify the program, so that it has a random salt value with 16 bytes?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9154359d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Variable length hashes (XOF)\n",
|
||||
"There are some hashing methods that support a variable number of bytes in the output hash. These include Blake2b, Blake2s, SHAKE128 and SHAKE256:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_hash_07.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"id": "b04c8f47",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Data: hello\n",
|
||||
" Hex: 68656c6c6f\n",
|
||||
"\n",
|
||||
"Blake2p (64 bytes): e4cfa39a3d37be31c59609e807970799caa68a19bfaa15135f165085e01d41a65ba1e1b146aeb6bd0092b49eac214c103ccfa3a365954bbbe52f74a2b3620c94 5M+jmj03vjHFlgnoB5cHmcqmihm/qhUTXxZQheAdQaZboeGxRq62vQCStJ6sIUwQPM+jo2WVS7vlL3Sis2IMlA==\n",
|
||||
"\n",
|
||||
"Blake2s (32 bytes): 19213bacc58dee6dbde3ceb9a47cbb330b3d86f8cca8997eb00be456f140ca25 GSE7rMWN7m294865pHy7Mws9hvjMqJl+sAvkVvFAyiU=\n",
|
||||
"\n",
|
||||
"SHAKE128 (64 bytes): 8eb4b6a932f280335ee1a279f8c208a349e7bc65daf831d3021c213825292463c59e22d0fe2c767cd7cacc4df42dd5f6147f0c5c512ecb9b933d14b9cc1b2974 jrS2qTLygDNe4aJ5+MIIo0nnvGXa+DHTAhwhOCUpJGPFniLQ/ix2fNfKzE30LdX2FH8MXFEuy5uTPRS5zBspdA==\n",
|
||||
"\n",
|
||||
"SHAKE256 (64 bytes): 1234075ae4a1e77316cf2d8000974581a343b9ebbca7e3d1db83394c30f221626f594e4f0de63902349a5ea5781213215813919f92a4d86d127466e3d07e8be3 EjQHWuSh53MWzy2AAJdFgaNDueu8p+PR24M5TDDyIWJvWU5PDeY5AjSaXqV4EhMhWBORn5Kk2G0SdGbj0H6L4w==\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 03_04.py\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"st = \"hello\"\n",
|
||||
"hex=False\n",
|
||||
"showhex=\"No\"\n",
|
||||
"\n",
|
||||
"def show_hash(name,type,data):\n",
|
||||
" digest = hashes.Hash(type,backend=default_backend())\n",
|
||||
" digest.update(data)\n",
|
||||
" res=digest.finalize()\n",
|
||||
" hex=binascii.b2a_hex(res).decode()\n",
|
||||
" b64=binascii.b2a_base64(res).decode()\n",
|
||||
" print (f\"{name}: {hex} {b64}\")\n",
|
||||
"\n",
|
||||
"if (showhex==\"yes\"): hex=True\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
"\tif (hex==True): data = binascii.a2b_hex(st)\n",
|
||||
"\telse: data=st.encode()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\tprint (\"Data: \",st)\n",
|
||||
"\tprint (\" Hex: \",binascii.b2a_hex(data).decode())\n",
|
||||
"\tprint()\n",
|
||||
"\n",
|
||||
"\tshow_hash(\"Blake2p (64 bytes)\",hashes.BLAKE2b(64),data)\n",
|
||||
"\tshow_hash(\"Blake2s (32 bytes)\",hashes.BLAKE2s(32),data)\n",
|
||||
"\tshow_hash(\"SHAKE128 (64 bytes)\",hashes.SHAKE128(64),data)\n",
|
||||
"\tshow_hash(\"SHAKE256 (64 bytes)\",hashes.SHAKE256(64),data)\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fc4ff412",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Run the program and verify the hashes produced.\n",
|
||||
"\n",
|
||||
"> Modify the program so that that we get a hash with 16 bytes, and verify that the length is correct.\n",
|
||||
"\n",
|
||||
"> Modify the program so that that we get a hash with 512 bytes, and verify that the length is correct."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "24740fab",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## LM and NTLM Hash\n",
|
||||
"Previous Microsoft Windows systems have used the LM and NTLM hash to store user passwords. The method is supported in the passlib library:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c5ad92fc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import passlib.hash;\n",
|
||||
"string=\"hello\"\n",
|
||||
"print \"LM Hash:\"+passlib.hash.lmhash.encrypt(string)\n",
|
||||
"print \"NT Hash:\"+passlib.hash.nthash.encrypt(string)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "680f89f0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Compute the LM and NTLM hash for \"edinburgh\" and \"glasgow\". How many bytes are in the hash?\n",
|
||||
"> Observe what happens to the hash when we use an input of \"aaaaaa\", \"aaaaaaa\", \"aaaaaaaa\", and \"aaaaaaaaaaaa\"?"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
394
z_jupyter/04_key_exchange.ipynb
Normal file
@@ -0,0 +1,394 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7782a35",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# Diffie Hellman\n",
|
||||
"With key exchange, Bob and Alice end up with the same secret key, even though Eve is listening to their communications:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_key_02.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"The Diffie-Hellman method allows Bob and Alice to pass public values to each other and then derive the same key:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_key_01.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"For this Bob generates a secret value (b) and Alice generates a secret value (a). Bob passes g^b mod p, and Alice passes g^a mod p.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1265ed12",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Bob and Alice have agreed on the values:\n",
|
||||
"\n",
|
||||
"g=2879, N= 9929\n",
|
||||
"\n",
|
||||
"Bob Select x=6, Alice selects y=9\n",
|
||||
"\n",
|
||||
"Now calculate (using a calculator or Python:\n",
|
||||
"\n",
|
||||
"Alice’s A value (g^x mod N):\n",
|
||||
"\n",
|
||||
"Bob’s B value (g^y mod N):\n",
|
||||
"\n",
|
||||
"Now they exchange the values. Next calculate the shared key:\n",
|
||||
"\n",
|
||||
"Alice’s value (B^x mod N):\n",
|
||||
"\n",
|
||||
"Bobs’s value (A^y mod N):\n",
|
||||
"\n",
|
||||
"> Do they match? Yes/No"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3ed130a0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We can use Python to implement a simple example with a given base generator (g) and prime number (p):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "80911155",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"g: 5 (a shared value), n: 1001 (a prime number)\n",
|
||||
"\n",
|
||||
"Alice calculates:\n",
|
||||
"a (Alice random): 410\n",
|
||||
"Alice value (A): 298 (g^a) mod p\n",
|
||||
"\n",
|
||||
"Bob calculates:\n",
|
||||
"b (Bob random): 105\n",
|
||||
"Bob value (B): 265 (g^b) mod p\n",
|
||||
"\n",
|
||||
"Alice calculates:\n",
|
||||
"Key: 155 (B^a) mod p\n",
|
||||
"Key: 210e3b160c355818509425b9d9e9fd3ea2e287f2c43a13e5be8817140db0b9e6\n",
|
||||
"\n",
|
||||
"Bob calculates:\n",
|
||||
"Key: 155 (A^b) mod p\n",
|
||||
"Key: 210e3b160c355818509425b9d9e9fd3ea2e287f2c43a13e5be8817140db0b9e6\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 04_01.py\n",
|
||||
"# https://asecuritysite.com/keyexchange/diffie_py\n",
|
||||
"import random\n",
|
||||
"import hashlib\n",
|
||||
"\n",
|
||||
"g=5\n",
|
||||
"p=1001\n",
|
||||
"\n",
|
||||
"a=random.randint(1, p)\n",
|
||||
"\n",
|
||||
"b=random.randint(1,p)\n",
|
||||
"\n",
|
||||
"A = (g**a) % p\n",
|
||||
"B = (g**b) % p\n",
|
||||
"\n",
|
||||
"print('g: ',g,' (a shared value), n: ',p, ' (a prime number)')\n",
|
||||
"\n",
|
||||
"print('\\nAlice calculates:')\n",
|
||||
"print('a (Alice random): ',a)\n",
|
||||
"print('Alice value (A): ',A,' (g^a) mod p')\n",
|
||||
"\n",
|
||||
"print('\\nBob calculates:')\n",
|
||||
"print('b (Bob random): ',b)\n",
|
||||
"print('Bob value (B): ',B,' (g^b) mod p')\n",
|
||||
"\n",
|
||||
"print('\\nAlice calculates:')\n",
|
||||
"keyA=(B**a) % p\n",
|
||||
"print('Key: ',keyA,' (B^a) mod p')\n",
|
||||
"print('Key: ',hashlib.sha256(str(keyA).encode()).hexdigest())\n",
|
||||
"\n",
|
||||
"print('\\nBob calculates:')\n",
|
||||
"keyB=(A**b) % p\n",
|
||||
"print('Key: ',keyB,' (A^b) mod p')\n",
|
||||
"print('Key: ',hashlib.sha256(str(keyB).encode()).hexdigest())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6d22b5c8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Run the code and verify that Bob and Alice compute the same shared secret.\n",
|
||||
"\n",
|
||||
"> The (g**b) % p operation can be computationally intensive. Replace this operation with pow(g,b,p), and verify that the program still works.\n",
|
||||
"\n",
|
||||
"> Use a prime number of 997, and verify the operation of the code.\n",
|
||||
"\n",
|
||||
"> Use a prime number of 2^19-1, and verify the operation of the code."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b8e14951",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Selecting generator for discrete logs\n",
|
||||
"With a discrete log method, we have the form of:\n",
|
||||
"\n",
|
||||
"Y=g^x (mod p)\n",
|
||||
"\n",
|
||||
"For the base, we must select a base generator that produces all the possible values of Y for x, with a given prime number of p.\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "548c6405",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"p: 11\n",
|
||||
"Values for g^x mod p: \n",
|
||||
"2 6 7 8 None\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 04_02.py\n",
|
||||
"# https://asecuritysite.com/dh/pickg2\n",
|
||||
"p=11\n",
|
||||
"\n",
|
||||
"def getG(p):\n",
|
||||
"\n",
|
||||
" for x in range (1,p):\n",
|
||||
"\t rand = x\n",
|
||||
"\t exp=1\n",
|
||||
"\t next = rand % p\n",
|
||||
"\n",
|
||||
"\t while (next != 1 ):\n",
|
||||
"\t\t next = (next*rand) % p\n",
|
||||
"\t\t exp = exp+1\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\t if (exp==p-1):\n",
|
||||
"\t\t print (rand,end=' ')\n",
|
||||
"\n",
|
||||
"print (\"p: \",p)\n",
|
||||
"print (\"Values for g^x mod p: \")\n",
|
||||
"print (getG(p))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "222bec32",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> For a prime number of p=11, what are the possible base generator values?\n",
|
||||
"> For a prime number of p=97, what are the possible base generator values?\n",
|
||||
"> If we pick a value of p=11, and take a value of g=5, show that we do not output all the possible values for Y=g^x (mod p).\n",
|
||||
"> If we pick a value of p=11, and take a value of g=6, show that we do output all the possible values for Y=g^x (mod p)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8c457f5e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Elliptic Curve Diffie Hellman (ECDH)\n",
|
||||
"The most popular key exchange method is ECDH (Elliptic Curve Diffie Hellman). This uses an elliptic curve method, of which the most popular curve is P256 (SECP256R1). \n",
|
||||
"\n",
|
||||
"<img src='graphics/g_key_12.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"The following is the some code:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "73037ef4",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Name of curve: secp256r1\n",
|
||||
"Generated key size: 32 bytes (256 bits)\n",
|
||||
"\n",
|
||||
"Bob private key value: 115386775143760985994606199743124500698563324842662591622007624940178885352350\n",
|
||||
"Bob's public key: 3059301306072a8648ce3d020106082a8648ce3d0301070342000453c9db700d76051a285ac6ecf2a27bc82056faca157b52d9744d1f781577e2a8bd0011523ad95fc5012b2c1d5bbae06a51f4a64e34e5397e4c282fe595bf8037\n",
|
||||
"\n",
|
||||
"Alice private key value: 73556695653589803082300318169887127685187875212044508782243551530526730975658\n",
|
||||
"Alice's public key: 3059301306072a8648ce3d020106082a8648ce3d03010703420004aa8ac00f7a33ab033eb047d9fe2892a9da3ad8381b8bd1f4e0007f89b13d5b6a243a3ec52af2c48903cdf662c6cf79acc05292bce510f4fcb11071cb6be338f2\n",
|
||||
"\n",
|
||||
"Bob's derived key: c1c76e98cb3ef84986fa5395b8da34bff86c180005ff3de1ea088807542ad517\n",
|
||||
"Alice's derived key: c1c76e98cb3ef84986fa5395b8da34bff86c180005ff3de1ea088807542ad517\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 04_03.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew13\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric import ec\n",
|
||||
"from cryptography.hazmat.primitives.kdf.hkdf import HKDF\n",
|
||||
"from cryptography.hazmat.primitives import serialization\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"Bob_private_key = ec.generate_private_key(ec.SECP384R1(),default_backend())\n",
|
||||
"\n",
|
||||
"Alice_private_key = ec.generate_private_key(ec.SECP384R1(),default_backend())\n",
|
||||
"size=32 # 256 bit key\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Bob_private_key = ec.generate_private_key(ec.SECP256R1(),default_backend())\n",
|
||||
"Alice_private_key = ec.generate_private_key(ec.SECP256R1(),default_backend()) \n",
|
||||
"\n",
|
||||
"Bob_shared_key = Bob_private_key.exchange(ec.ECDH(), Alice_private_key.public_key())\n",
|
||||
"\n",
|
||||
"Bob_derived_key = HKDF(algorithm=hashes.SHA256(),length=size,salt=None,info=b'',backend=default_backend()).derive(Bob_shared_key)\n",
|
||||
"\n",
|
||||
"Alice_shared_key = Alice_private_key.exchange(ec.ECDH(), Bob_private_key.public_key())\n",
|
||||
"\n",
|
||||
"Alice_derived_key = HKDF(algorithm=hashes.SHA256(),length=size,salt=None,info=b'',backend=default_backend()).derive(Alice_shared_key)\n",
|
||||
"\n",
|
||||
"print (\"Name of curve: \",Bob_private_key.public_key().curve.name)\n",
|
||||
"print (f\"Generated key size: {size} bytes ({size*8} bits)\")\n",
|
||||
"\n",
|
||||
"vals = Bob_private_key.private_numbers()\n",
|
||||
"print (f\"\\nBob private key value: {vals.private_value}\")\n",
|
||||
"vals=Bob_private_key.public_key()\n",
|
||||
"enc_point=binascii.b2a_hex(vals.public_bytes(encoding=serialization.Encoding.DER,format=serialization.PublicFormat.SubjectPublicKeyInfo)).decode()\n",
|
||||
"print(\"Bob's public key: \",enc_point)\n",
|
||||
"\n",
|
||||
"vals = Alice_private_key.private_numbers()\n",
|
||||
"print (f\"\\nAlice private key value: {vals.private_value}\")\n",
|
||||
"vals=Alice_private_key.public_key()\n",
|
||||
"enc_point=binascii.b2a_hex(vals.public_bytes(encoding=serialization.Encoding.DER,format=serialization.PublicFormat.SubjectPublicKeyInfo)).decode()\n",
|
||||
"print(\"Alice's public key: \",enc_point)\n",
|
||||
"\n",
|
||||
"print (\"\\nBob's derived key: \",binascii.b2a_hex(Bob_derived_key).decode())\n",
|
||||
"print(\"Alice's derived key: \",binascii.b2a_hex(Alice_derived_key).decode())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4a3e413f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> The program uses SECP256R1, and which is also known as the NIST P-256 curve. The Bitcoin curve is SECP256k1. Modify the program so that it uses this curve. Verify that it still works of the shared key.\n",
|
||||
"\n",
|
||||
"> An enhanced curve is SECP521R1. Modify the program so that it uses this curve. Verify that it still works of the shared key.\n",
|
||||
"\n",
|
||||
"> The Brainpool curves have some advantages over SECP2561. Modify the program so that it uses the P256R1 curve, and verify that it still works for the shared key.\n",
|
||||
"\n",
|
||||
"> The program creates a 256-bit key. Modify the program so that it generated a 128-bit key.\n",
|
||||
"\n",
|
||||
"> Modify the program so that is displays the shared key in a Base64 format.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1c0e6351",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## DH Parameters \n",
|
||||
"In the DH key generation we have two base parameters: g and p. We can use OpenSSL to generate these parameters. Such as:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ead31dbd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
">> Generate 768-bit Diffie-Hellman parameters:\n",
|
||||
"\n",
|
||||
"openssl dhparam -out dhparams.pem -text 768 \n",
|
||||
"\n",
|
||||
">> View your key exchange parameters with:\n",
|
||||
"\n",
|
||||
"cat dhparams.pem\t\n",
|
||||
"\n",
|
||||
">> What is the value of g:\n",
|
||||
"\n",
|
||||
">> How many bits does the prime number have?\n",
|
||||
"\n",
|
||||
">> How long does it take to produce the parameters for 1,024 bits (Group 2)?\n",
|
||||
"\n",
|
||||
">> How long does it take to produce the parameters for 1536 bits (Group 5)?\n",
|
||||
"\n",
|
||||
">> How would we change the g value?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a4266944",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## EC Paramters\n",
|
||||
"With elliptic curves, we can use OpenSSL to generate a curve:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f844cbaf",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
">> Let’s look at the Elliptic curves we can create:\n",
|
||||
"\n",
|
||||
"openssl ecparam -list_curves\n",
|
||||
"\n",
|
||||
">> We can create our elliptic parameter file with:\n",
|
||||
"\n",
|
||||
"openssl ecparam -name secp256k1 -out secp256k1.pem\n",
|
||||
"\n",
|
||||
">> Now view the details with:\n",
|
||||
"\n",
|
||||
"openssl ecparam -in secp256k1.pem -text -param_enc explicit -noout\n",
|
||||
"\n",
|
||||
">> What are the details of the key?\n",
|
||||
"\n",
|
||||
">> Now we can create our key pair:\n",
|
||||
"\n",
|
||||
"openssl ecparam -in secp256k1.pem -genkey -noout -out mykey.pem\n",
|
||||
"\n",
|
||||
">> Name three 160-bit curves:"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
337
z_jupyter/05_mac.ipynb
Normal file
@@ -0,0 +1,337 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7782a35",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# Message Authentication Code (MAC)\n",
|
||||
"A MAC involves a hashing being signed by a shared secret key between Bob and Alice. For this, we define a given hashing method, such as SHA-256, and a given MAC type.\n",
|
||||
"\n",
|
||||
"## HMAC\n",
|
||||
"HMAC (hash-based message authentication code) supports the usage of a key to hash data. This key is kept secret between Bob and Alice, and can be used to authentication both the data and that the sender still knows the secret. Overall HMAC can be used with a range of different hashing methods, such as MD5, SHA-1, SHA-256 (SHA-2) and SHA-3. \n",
|
||||
"\n",
|
||||
"<img src='graphics/g_mac_01.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"For HMAC-BLAKE2, we can have:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_mac_02.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"The code to implement this is:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "52ead7e5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Data: The quick brown fox jumps over the lazy dog\n",
|
||||
" Hex: 54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67\n",
|
||||
"Key: key\n",
|
||||
" Hex: 6b6579\n",
|
||||
"\n",
|
||||
"HMAC-SHA256: f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8 97yD9DBThCSxMpjmqm+xQ+9NWaFJRhdZl0edvC0aPNg=\n",
|
||||
"\n",
|
||||
"HMAC Verified\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 05_01.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew2\n",
|
||||
"\n",
|
||||
"from cryptography.hazmat.primitives import hashes, hmac\n",
|
||||
"import binascii\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"st = \"The quick brown fox jumps over the lazy dog\"\n",
|
||||
"hex=False\n",
|
||||
"showhex=\"No\"\n",
|
||||
"k=\"key\"\n",
|
||||
"\n",
|
||||
"def show_hmac(name,type,data,key):\n",
|
||||
" digest = hmac.HMAC(key, type,backend=default_backend())\n",
|
||||
" digest.update(data)\n",
|
||||
" res=digest.finalize()\n",
|
||||
" hex=binascii.b2a_hex(res).decode()\n",
|
||||
" b64=binascii.b2a_base64(res).decode()\n",
|
||||
" print (f\"HMAC-{name}: {hex} {b64}\")\n",
|
||||
" \n",
|
||||
" digest2 = hmac.HMAC(key, type,backend=default_backend())\n",
|
||||
" digest2.update(data)\n",
|
||||
" rtn=digest2.verify(res)\n",
|
||||
" if (rtn==None): print(\"HMAC Verified\")\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
"\tif (hex==True): data = binascii.a2b_hex(st)\n",
|
||||
"\telse: data=st.encode()\n",
|
||||
"\n",
|
||||
"\tif (hex==True): key = binascii.a2b_hex(k)\n",
|
||||
"\telse: key=k.encode()\n",
|
||||
"\n",
|
||||
"\tprint (\"Data: \",st)\n",
|
||||
"\tprint (\" Hex: \",binascii.b2a_hex(data).decode())\n",
|
||||
"\tprint (\"Key: \",k)\n",
|
||||
"\tprint (\" Hex: \",binascii.b2a_hex(key).decode())\n",
|
||||
"\tprint()\n",
|
||||
"\n",
|
||||
"\tshow_hmac(\"SHA256\",hashes.SHA256(),data,key)\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7b15458c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Verify that the HMAC signature works with the given message.\n",
|
||||
"\n",
|
||||
"> Modify the program for HMAC-MD5 and verify that it works.\n",
|
||||
"\n",
|
||||
"> Modify the program for HMAC-SHA1 and verify that it works.\n",
|
||||
"\n",
|
||||
"> Modify the program for HMAC-SHA512 and verify that it works.\n",
|
||||
"\n",
|
||||
"> Observe how the signature varies for different hashing methods."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e4358ba5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Poly1305\n",
|
||||
"For a stream cipher, it is important that we have a MAC, so that we can detect any changes in the bits in the cipher. ChaCha20 typically uses Poly1305 for its MAC. \n",
|
||||
"\n",
|
||||
"<img src='graphics/g_mac_05.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "3e3b1107",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message: --f=/Users/billbuchanan/Library/Jupyter/runtime/kernel-v2-71602TT5d9wYK6Zod.json\n",
|
||||
"Key: a84edba3b95371406aa09d7f3c0e36b8fb1ac7808dd204078f0660cf9dfe3834\n",
|
||||
"\n",
|
||||
"Poly1305 tag (16 bytes): cf7fd40e03581a380911434fc41d40c2\n",
|
||||
"Signature matches\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"--- Generating with alternative method ---\n",
|
||||
"cf7fd40e03581a380911434fc41d40c2\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 05_02.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew27\n",
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"from cryptography.hazmat.primitives import poly1305\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"message = \"message\"\n",
|
||||
"\n",
|
||||
"if (len(sys.argv)>1):\n",
|
||||
"\tmessage=str(sys.argv[1])\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"message=message.encode()\n",
|
||||
"key = os.urandom(32)\n",
|
||||
"\n",
|
||||
"c = poly1305.Poly1305(key)\n",
|
||||
"\n",
|
||||
"c.update(message)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"signature = c.finalize()\n",
|
||||
"\n",
|
||||
"print (f\"Message: {message.decode()}\" )\n",
|
||||
"\n",
|
||||
"print (f\"Key: {binascii.b2a_hex(key).decode()}\")\n",
|
||||
"\n",
|
||||
"print (f\"\\nPoly1305 tag (16 bytes): {binascii.b2a_hex(signature).decode()}\")\n",
|
||||
"\n",
|
||||
"c = poly1305.Poly1305(key)\n",
|
||||
"c.update(message)\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" rtn=c.verify(signature)\n",
|
||||
" print (\"Signature matches\")\n",
|
||||
"except:\n",
|
||||
" print (\"Signature does not match\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"\\n\\n--- Generating with alternative method ---\")\n",
|
||||
"tag=poly1305.Poly1305.generate_tag(key,message)\n",
|
||||
"print (binascii.b2a_hex(tag).decode())\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7a469b7b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Verify the the operation of the Poly1305 in this program.\n",
|
||||
"\n",
|
||||
"> What is the size of the key used in this example?\n",
|
||||
"\n",
|
||||
"> How many bits does the Poly1305 tag have?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5eafe837",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## CMAC\n",
|
||||
"CMACs (Cipher-based message authentication codes) create a message authentication codes (MACs) using a block cipher and a secret key. They differ from HMACs in that they use a symmetric key method for the MACs rather than a hashing method. In the following, we use the AES method to create the MAC:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_mac_03.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "c613e949",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message: --f=/Users/billbuchanan/Library/Jupyter/runtime/kernel-v2-71602TT5d9wYK6Zod.json\n",
|
||||
"Type: TripleDES\n",
|
||||
"Key: 56837cb6ddfc06db9f55553e653628cc3cdfaf738f45deee83698fdf60bd1c87\n",
|
||||
"CMAC signature: 58118c98fa654fb7a42a392b5df31c26\n",
|
||||
"Signature matches\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 05_03.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew26\n",
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"from cryptography.hazmat.primitives import cmac\n",
|
||||
"\n",
|
||||
"from cryptography.hazmat.primitives.ciphers import algorithms\n",
|
||||
"\n",
|
||||
"message = \"message\"\n",
|
||||
"ctype=\"TripleDES\"\n",
|
||||
"\n",
|
||||
"if (len(sys.argv)>1):\n",
|
||||
"\tmessage=str(sys.argv[1])\n",
|
||||
"if (len(sys.argv)>2):\n",
|
||||
"\tctype=str(sys.argv[2])\n",
|
||||
"\n",
|
||||
"message=message.encode()\n",
|
||||
"key = os.urandom(32)\n",
|
||||
"\n",
|
||||
"c = cmac.CMAC(algorithms.AES(key),backend=default_backend())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"c.update(message)\n",
|
||||
"\n",
|
||||
"c_copy = c.copy() \n",
|
||||
"\n",
|
||||
"signature = c.finalize()\n",
|
||||
"\n",
|
||||
"print (f\"Message: {message.decode()}\" )\n",
|
||||
"print (f\"Type: {ctype}\" )\n",
|
||||
"print (f\"Key: {binascii.b2a_hex(key).decode()}\")\n",
|
||||
"\n",
|
||||
"print (f\"CMAC signature: {binascii.b2a_hex(signature).decode()}\")\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" rtn=c_copy.verify(signature)\n",
|
||||
" print (\"Signature matches\")\n",
|
||||
"except:\n",
|
||||
" print (\"Signature does not match\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "928069a0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Verify the operation of the code.\n",
|
||||
"\n",
|
||||
"> Rather than using AES, implement the code using 3DES.\n",
|
||||
"\n",
|
||||
"> Rather than using AES, implement the code using Blowfish."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "472d880e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Generate HMAC with OpenSSL\n",
|
||||
"We can use OpenSSL to generate MACs. For HMAC, we can generate:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"Message: Hello\n",
|
||||
"Password: test\n",
|
||||
"Hash: sha256\n",
|
||||
"========================\n",
|
||||
"HMAC:\n",
|
||||
"Windows command: \"echo set /p=\"Hello\" | openssl dgst -sha256 -hmac test\"\n",
|
||||
"Linux command: \"echo -n \"Hello\" | openssl dgst -sha256 -hmac test\"\n",
|
||||
"Result:\n",
|
||||
"e2bb88dfaff4fea88d7dc7a00d18b79bb971653de0fe54c7f3985e4daa1e6a25\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b74c84f4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
">> With OpenSSL, generate the HMAC signature for a message of \"Goodbye\" and a key of \"qwerty123\". Use a hash of SHA1, SHA256, and SHA3-256. Check your answer [here](https://asecuritysite.com/mac/openssl_hmac)."
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
548
z_jupyter/06_kdf.ipynb
Normal file
@@ -0,0 +1,548 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7782a35",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# Key Derivation Function (KDF)\n",
|
||||
"\n",
|
||||
"## HKDF\n",
|
||||
"HKDF (HMAC Key Derivation Function) is used to generate an encryption key based on a password. We can use a range of hashing methods to dervie the encryption key. In this case we will use a range of hashing methods, and derive a key of a given size.\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_kdf_01.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "4eb825c2",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Key: 00\n",
|
||||
" Hex: 3030\n",
|
||||
"Salt: \n",
|
||||
" Hex: \n",
|
||||
"\n",
|
||||
"HKDF SHA256: c9f9ff58d94c9d8901f5ed32e36f30af yfn/WNlMnYkB9e0y428wrw==\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 06_01.py\n",
|
||||
"# https://asecuritysite.com/hazmat/hashnew3\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"from cryptography.hazmat.primitives.kdf.hkdf import HKDF\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"st = \"00\"\n",
|
||||
"hex=False\n",
|
||||
"showhex=\"No\"\n",
|
||||
"k=\"00\"\n",
|
||||
"length=16\n",
|
||||
"slt=\"\"\n",
|
||||
"\n",
|
||||
"def show_hash(name,type,data,length,salt):\n",
|
||||
"\n",
|
||||
" hkdf = HKDF(algorithm=type, length=length,salt=salt, info=b\"\",backend=default_backend())\n",
|
||||
" mykey=hkdf.derive(data)\n",
|
||||
" hex=binascii.b2a_hex(mykey).decode()\n",
|
||||
" b64=binascii.b2a_base64(mykey).decode()\n",
|
||||
" print (f\"HKDF {name}: {hex} {b64}\")\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
"\tif (hex==True): data = binascii.a2b_hex(st)\n",
|
||||
"\telse: data=st.encode()\n",
|
||||
"\tif (hex==True): salt = binascii.a2b_hex(slt)\n",
|
||||
"\telse: salt=slt.encode()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\tprint (\"Key: \",st)\n",
|
||||
"\tprint (\" Hex: \",binascii.b2a_hex(data).decode())\n",
|
||||
"\n",
|
||||
"\tprint (\"Salt: \",slt)\n",
|
||||
"\tprint (\" Hex: \",binascii.b2a_hex(salt).decode())\n",
|
||||
"\n",
|
||||
"\tprint()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\tshow_hash(\"SHA256\",hashes.SHA256(),data,length,salt)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e39a85a4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Verify the operaton of the program.\n",
|
||||
"\n",
|
||||
"> Change the SHA-256 method to MD5. Verify the operation.\n",
|
||||
"\n",
|
||||
"> Change the SHA-256 method to SHA-1. Verify the operation.\n",
|
||||
"\n",
|
||||
"> Change the SHA-256 method to Blake2p, and use 64 bytes of hash. Verify the operation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fa6da6d0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## PBKDF2\n",
|
||||
"PBKDF2 (Password-Based Key Derivation Function 2) is defined in RFC 2898 and generates a salted hash. Often this is used to create an encryption key from a defined password, and where it is not possible to reverse the password from the hashed value. It is used in TrueCrypt to generate the key required to read the header information of the encrypted drive, and which stores the encryption keys. Also, it is used in WPA-2 in order to create a hashed version of the password. With this, WPA-2 uses 4,096 interations. We can also specify the length of the generated hashed. \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_kdf_03.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "23a3df3f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message:\tHello\n",
|
||||
"Salt:\t\te9ed6ffc41f8350c15ac0b67611ae723\n",
|
||||
"Salt:\t\t6e1v/EH4NQwVrAtnYRrnIw==\n",
|
||||
"Rounds:\t\t1000\n",
|
||||
"Hash:\t\tsha1\n",
|
||||
"\n",
|
||||
"Key:\t\tdf9f33fc4e8d7ec3655d2369539caa0228e7946bc629076d3381e3616dac1f73\n",
|
||||
"Key:\t\t358z/E6NfsNlXSNpU5yqAijnlGvGKQdtM4HjYW2sH3M=\n",
|
||||
"KDF Verified\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"# 06_02.py\n",
|
||||
"# https://asecuritysite.com/pbkdf2/hazkdf\n",
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"import base64\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"round=1000\n",
|
||||
"hashtype=0\n",
|
||||
"length=32\n",
|
||||
"message=\"Hello\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"salt = os.urandom(16)\n",
|
||||
"h=None\n",
|
||||
"if (hashtype==0): h=hashes.SHA1()\n",
|
||||
"elif (hashtype==1): h=hashes.SHA512_224()\n",
|
||||
"elif (hashtype==2): h=hashes.SHA512_256()\n",
|
||||
"elif (hashtype==3): h=hashes.SHA224()\n",
|
||||
"elif (hashtype==4): h=hashes.SHA256()\n",
|
||||
"elif (hashtype==5): h=hashes.SHA384()\n",
|
||||
"elif (hashtype==6): h=hashes.SHA512()\n",
|
||||
"elif (hashtype==7): h=hashes.SHA3_224()\n",
|
||||
"elif (hashtype==8): h=hashes.SHA3_256()\n",
|
||||
"elif (hashtype==9): h=hashes.SHA3_384()\n",
|
||||
"elif (hashtype==10): h=hashes.SHA3_512()\n",
|
||||
"elif (hashtype==11): h=hashes.MD5()\n",
|
||||
"elif (hashtype==12): h=hashes.SM3()\n",
|
||||
"elif (hashtype==13): h=hashes.BLAKE2b(64)\n",
|
||||
"elif (hashtype==14): h=hashes.BLAKE2s(32)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"kdf = PBKDF2HMAC(algorithm=h,length=length,salt=salt, iterations=round,backend=default_backend())\n",
|
||||
"\n",
|
||||
"key = kdf.derive(message.encode())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# verify\n",
|
||||
"\n",
|
||||
"kdf = PBKDF2HMAC(algorithm=h, length=length,salt=salt, iterations=round,backend=default_backend())\n",
|
||||
"\n",
|
||||
"rtn=kdf.verify(message.encode(), key)\n",
|
||||
"\n",
|
||||
"print(f\"Message:\\t{message}\")\n",
|
||||
"print(f\"Salt:\\t\\t{salt.hex()}\")\n",
|
||||
"print(f\"Salt:\\t\\t{base64.b64encode(salt).decode()}\")\n",
|
||||
"print(f\"Rounds:\\t\\t{round}\")\n",
|
||||
"print(f\"Hash:\\t\\t{kdf._algorithm.name}\")\n",
|
||||
"print(f\"\\nKey:\\t\\t{key.hex()}\")\n",
|
||||
"print(f\"Key:\\t\\t{base64.b64encode(key).decode()}\")\n",
|
||||
"if (rtn==None): print(\"KDF Verified\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1b11596f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We can also use a pure PBKDF2 method with:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "906b48e7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Using PBKDF2\n",
|
||||
"Password: qwerty, Salt: \n",
|
||||
"\n",
|
||||
"Hash: b'b1444b43fe945ff29561e772401db5a0'\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 06_03.py\n",
|
||||
"import binascii\n",
|
||||
"from Crypto.Protocol.KDF import PBKDF2, HKDF\n",
|
||||
"from Crypto.Hash import SHA256\n",
|
||||
"from Crypto.Random import get_random_bytes\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"password=\"qwerty\"\n",
|
||||
"salt = get_random_bytes(16)\n",
|
||||
"s=\"\"\n",
|
||||
"type=1\n",
|
||||
"bytes=16\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"salt=binascii.unhexlify(s)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"KEK = PBKDF2(password, salt, bytes, count=1000, hmac_hash_module=SHA256)\n",
|
||||
"print (\"Using PBKDF2\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (f\"Password: {password}, Salt: {s}\")\n",
|
||||
"print (\"\\nHash: \",binascii.hexlify(KEK))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "19cdb854",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## scrypt\n",
|
||||
"scrypt is a password-based key derivation function which produces a hash with a salt and iterations. The iteration count slows down the cracking and the salt makes pre-computation difficult. The main parameters are: passphrase (P); salt (S); Blocksize (r) and CPU/Memory cost parameter (N - a power of 2). \n",
|
||||
"\n",
|
||||
"<img src='graphics/g_kdf_04.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a9f5ff8f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 06_04.py\n",
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"import base64\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"from cryptography.hazmat.primitives.kdf.scrypt import Scrypt\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"length=32\n",
|
||||
"message=\"Hello\"\n",
|
||||
"N=14\n",
|
||||
"r=8\n",
|
||||
"p=1\n",
|
||||
"\n",
|
||||
"if (len(sys.argv)>1):\n",
|
||||
"\tmessage=str(sys.argv[1])\n",
|
||||
"if (len(sys.argv)>2):\n",
|
||||
"\tN=int(sys.argv[2])\n",
|
||||
"if (len(sys.argv)>3):\n",
|
||||
"\tr=int(sys.argv[3])\n",
|
||||
"if (len(sys.argv)>4):\n",
|
||||
"\tlength=int(sys.argv[4])\n",
|
||||
"if (len(sys.argv)>5):\n",
|
||||
"\tp=int(sys.argv[5])\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"salt = os.urandom(16)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"kdf = Scrypt(salt=salt,length=length,n=2**N,r=r,p=p)\n",
|
||||
"\n",
|
||||
"key = kdf.derive(message.encode())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# verify\n",
|
||||
"\n",
|
||||
"kdf = Scrypt(salt=salt,length=length,n=2**N,r=r,p=p)\n",
|
||||
"\n",
|
||||
"rtn=kdf.verify(message.encode(), key)\n",
|
||||
"\n",
|
||||
"print(\"== scrypt === \")\n",
|
||||
"print(f\"Message:\\t{message}\")\n",
|
||||
"print(f\"Salt:\\t\\t{salt.hex()}\")\n",
|
||||
"print(f\"Salt:\\t\\t{base64.b64encode(salt).decode()}\")\n",
|
||||
"print(f\"scrypt param:\\tn=2**{N}, r={r}, p={p}\")\n",
|
||||
"print(f\"\\nKey:\\t\\t{key.hex()}\")\n",
|
||||
"print(f\"Key:\\t\\t{base64.b64encode(key).decode()}\")\n",
|
||||
"if (rtn==None): print(\"KDF Verified\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ed20a77c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> From the Cryptography libary, which other KDFs are available?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "31a8309e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# bcrypt\n",
|
||||
"MD5 and SHA-1 produce a hash signature, but this can be attacked by rainbow tables. Bcrypt is a more powerful hash generator for passwords and uses salt to create a non-recurrent hash. It was designed by Niels Provos and David Mazières, and is based on the Blowfish cipher. It is used as the default password hashing method for BSD and other systems. \n",
|
||||
"\n",
|
||||
"Overall it uses a 128-bit salt value, which requires 22 Radix-64 characters. It can use a number of iterations, which will slow down any brute-force cracking of the hashed value.\n",
|
||||
"\n",
|
||||
"For example, “Hello” with a salt value of “$2a$06$NkYh0RCM8pNWPaYvRLgN9.” gives:\n",
|
||||
"\n",
|
||||
"$2a$06$NkYh0RCM8pNWPaYvRLgN9.LbJw4gcnWCOQYIom0P08UEZRQQjbfpy\n",
|
||||
"\n",
|
||||
"As illustrated below, the first part is \"$2a$\" (or \"$2b$\"), and then followed by the number of iterations used (in this case is it 6 iterations (where each additional iternation doubles the hash time). The 128-bit (22 character) salt values comes after this, and then finally there is a 184-bit hash code (which is 31 characters).\n",
|
||||
"\n",
|
||||
"<img src='graphics/bc.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"The slowness of Bcrypt is highlighted with a recent AWS EC2 server benchmark using hashcat [here]:\n",
|
||||
"\n",
|
||||
"Hash type: MD5 Speed/sec: 380.02M words\n",
|
||||
"Hash type: SHA1 Speed/sec: 218.86M words\n",
|
||||
"Hash type: SHA256 Speed/sec: 110.37M words\n",
|
||||
"Hash type: bcrypt, Blowfish(OpenBSD) Speed/sec: 25.86k words\n",
|
||||
"Hash type: NTLM. Speed/sec: 370.22M words\n",
|
||||
"\n",
|
||||
"You can see that Blowfish is almost four times slower than MD5 (380,000,000 words/sec down to only 25,860 words/sec). With John The Ripper:\n",
|
||||
"\n",
|
||||
"md5crypt [MD5 32/64 X2] 318237 c/s real, 8881 c/s virtual\n",
|
||||
"bcrypt (\"$2a$05\", 32 iterations) 25488 c/s real, 708 c/s virtual\n",
|
||||
"LM [DES 128/128 SSE2-16] 88090K c/s real, 2462K c/s virtual\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "1badea25",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "ModuleNotFoundError",
|
||||
"evalue": "No module named 'bcrypt'",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
|
||||
"\u001b[0;32m<ipython-input-3-2e06d0a93f8e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mbinascii\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mCrypto\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mProtocol\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mKDF\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mPBKDF2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mscrypt\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mHKDF\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mbcrypt\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mCrypto\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mHash\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mSHA256\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mCrypto\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mRandom\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mget_random_bytes\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
|
||||
"\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'bcrypt'"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# 06_05.py\n",
|
||||
"# https://asecuritysite.com/bcrypt/kdf\n",
|
||||
"import binascii\n",
|
||||
"from Crypto.Protocol.KDF import PBKDF2, scrypt,HKDF\n",
|
||||
"import bcrypt\n",
|
||||
"from Crypto.Hash import SHA256\n",
|
||||
"from Crypto.Random import get_random_bytes\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"password=\"qwerty\"\n",
|
||||
"salt = get_random_bytes(16)\n",
|
||||
"s=\"\"\n",
|
||||
"type=1\n",
|
||||
"bytes=16\n",
|
||||
"\n",
|
||||
"if (len(sys.argv)>1):\n",
|
||||
"\tpassword=str(sys.argv[1])\n",
|
||||
"if (len(sys.argv)>2):\n",
|
||||
"\ts=str(sys.argv[2])\n",
|
||||
"if (len(sys.argv)>3):\n",
|
||||
"\ttype=int(sys.argv[3])\n",
|
||||
"if (len(sys.argv)>4):\n",
|
||||
"\tbytes=int(sys.argv[4])\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"salt=binascii.unhexlify(s)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"KEK = bcrypt.kdf(password=password.encode(),salt=b'salt',desired_key_bytes=bytes,rounds=100)\n",
|
||||
"print (\"Using bcrypt\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (f\"Password: {password}, Salt: {s}\")\n",
|
||||
"print (\"\\nHash: \",binascii.hexlify(KEK))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5d4cdaac",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Change the program so that the number of rounds is 500, 1000, 5000 and 10000. What happens to the creation of the hash?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fe1a15b0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Argon 2.0\n",
|
||||
"This case we will use PyNaCl (Networking and Cryptography) library, and which is a Python binding to libsodium. We will hash a password using SHA-256 and SHA-512, and also create a KDF (Key Derivation Function) using scrypt and Argon2. With Argon2, we have a memory robust key derivation function from a password and a salt value. Argon2 was designed Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich is a key derivation function (KDF), where were we can create hashed values of passwords, or create encryption keys based on a password. It was a winner of the Password Hashing Competition in July 2015, and is robust against GPU and side channel attacks [paper]. We will also use the salt value as a key for the key-hash method of SIPHash24. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2aa950e4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"With many fast hashing methods, such as MD5, we can now get billions or even trillions or hashes per second, where even 9 or 10 character passwords can be cracked for a reasonable financial cost. This includes salting of the password, as the salt is contained with the hashed password, and can be easily cracked with brute force (or dictionaries). The alternative is to use a hashing method which has a cost in memory, and for CPU processing. We also want to create a method which makes it difficult to apply parallel threads (and thus run it on GPUs). So a step forward is Argon2 which was designed Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich as a key derivation function. It was a winner of the Password Hashing Competition in July 2015. It is resistant to GPU attacks, and also has a memory cost. The costs include: execution time (CPU cost); memory required (memory cost); and degree of parallelism.\n",
|
||||
"\n",
|
||||
"The parameters include:\n",
|
||||
"\n",
|
||||
"* Password (P): Defines the password bytes to be hashed\n",
|
||||
"* Salt (S): Defines the bytes to be used for salting.\n",
|
||||
"* Parallelism (p): Defines the number of thread that are required for the parallelism.\n",
|
||||
"* TagLength (T): Define the number of bytes to return for the hash.\n",
|
||||
"* MemorySizeKB (m): Amount of memory (in KB) to use.\n",
|
||||
"\n",
|
||||
"$argon2id$v=19$m=8,t=3,p=1$yh3bPPtc2tSnm8xpK1RZbw$CBE1uk3HK23zkotoY9280NWemhMj6FnljoDMSZ8PZ58\n",
|
||||
"\n",
|
||||
"Note: You will need to install the libary with \"pip install PyNaCl\".\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_hash_06.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "634aa8a1",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "ModuleNotFoundError",
|
||||
"evalue": "No module named 'nacl'",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
|
||||
"\u001b[0;32m<ipython-input-1-f832e5aa398c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# https://asecuritysite.com/nacl/nacl02\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mnacl\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhash\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnacl\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhashlib\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnacl\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpwhash\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnacl\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mencoding\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
|
||||
"\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'nacl'"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/argon2/nacl02\n",
|
||||
"# 06_06.py\n",
|
||||
"import nacl.hash\n",
|
||||
"import nacl.hashlib\n",
|
||||
"import nacl.pwhash\n",
|
||||
"import nacl.encoding\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"from os import urandom\n",
|
||||
"\n",
|
||||
"password='hello'\n",
|
||||
"salt=''\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"salt=salt.zfill(16)\n",
|
||||
"\n",
|
||||
"print(\"Password: \",password)\n",
|
||||
"print(\"Salt: \",salt)\n",
|
||||
"\n",
|
||||
"salt=salt.encode()\n",
|
||||
"password=password.encode()\n",
|
||||
"\n",
|
||||
"mlevel=nacl.pwhash.MEMLIMIT_INTERACTIVE\n",
|
||||
"olevel=nacl.pwhash.OPSLIMIT_INTERACTIVE\n",
|
||||
"\n",
|
||||
"print (\"\\nSHA256: \",nacl.hash.sha256(password))\n",
|
||||
"print (\"SHA512: \",nacl.hash.sha512(password))\n",
|
||||
"print (\"\\nBlake2b: \",nacl.hashlib.blake2b(password,salt=salt).hexdigest())\n",
|
||||
"print (\"Scrypt: \",binascii.hexlify(nacl.hashlib.scrypt(password,salt, n=2, r=8, p=1, maxmem=2**25, dklen=64)))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"\\nArgon2id\")\n",
|
||||
"print(binascii.hexlify(nacl.pwhash.argon2id.kdf(size=32,password=password,salt=salt,opslimit=3,memlimit=8192)))\n",
|
||||
"print(nacl.pwhash.argon2id.str(password=password,opslimit=3,memlimit=8192))\n",
|
||||
"\n",
|
||||
"print(\"\\nArgon2i\")\n",
|
||||
"\n",
|
||||
"print(binascii.hexlify(nacl.pwhash.argon2i.kdf(size=32,password=password,salt=salt,opslimit=3,memlimit=8192)))\n",
|
||||
"print(nacl.pwhash.argon2i.str(password=password,opslimit=3,memlimit=8192))\n",
|
||||
"\n",
|
||||
"salt=salt.zfill(32)\n",
|
||||
"print(\"\\nScrypt\")\n",
|
||||
"print(binascii.hexlify(nacl.pwhash.scrypt.kdf(size=32,password=password,salt=salt,opslimit=olevel,memlimit=mlevel)))\n",
|
||||
"print(nacl.pwhash.scrypt.str(password=password,opslimit=3,memlimit=mlevel))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "358fadf4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> What is the value of the salt we have used?\n",
|
||||
"> The program for different values of opslimits, and observe the result."
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
452
z_jupyter/07_public_key.ipynb
Normal file
@@ -0,0 +1,452 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7782a35",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# Public Key Encryption\n",
|
||||
"The two main method used for public key methods are RSA and ECC (Elliptic Curve Cryptography). With encryption Bob can use Alice's public key to encrypt data, and then she will use her private key to decrypt it:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_public_04.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## RSA\n",
|
||||
"Overall, Bob generates two random prime numbers (p and q), and create a public modulus of:\n",
|
||||
"\n",
|
||||
"N=p.q\n",
|
||||
"\n",
|
||||
"Next Bob computes φ:\n",
|
||||
"\n",
|
||||
"φ=(p−1).(q−1)\n",
|
||||
"\n",
|
||||
"Bob then picks a public exponent of e and which does not share a factor with φ, and computes the private exponent as:\n",
|
||||
"\n",
|
||||
"d=e^{−1}(modφ)\n",
|
||||
"\n",
|
||||
"Bob will then use a public exponent (e) to cipher a message (M) with:\n",
|
||||
"\n",
|
||||
"C=M^e (mod N)\n",
|
||||
"\n",
|
||||
"To decrypt we use the private exponent (d) to decipher the ciphertext:\n",
|
||||
"\n",
|
||||
"M=C^d (mod N)\n",
|
||||
"\n",
|
||||
"Bob's public key is [e,N] and his private key is [d,N].\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_public_02.png' width=\"800px\">\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c6b56278",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In the following, we can create a PEM file which contains the details of the RSA keys:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "4eb825c2",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"RSA key size: 512\n",
|
||||
"M=5\n",
|
||||
"\n",
|
||||
"=== RSA Private key ===\n",
|
||||
"p=98710391635011658445043479723965207117107833632529428791312969625241457542591 q=91574907843657592470899807478818283529012640132059371827885349647328299106257 d=2885732068138574425866818792280420045060058024166826343777663006218892797603507245051130842680362766169475457680538759083143987436171153523033398613515713 N=9039395017187541924674204339436090645879983879639675848014372451895974442048802001144807129089503774586739781388049268071126576402394788054433636812091887\n",
|
||||
"\n",
|
||||
"Bit length of p and q is 256\n",
|
||||
"Bit length of N is 512\n",
|
||||
"\n",
|
||||
"=== RSA Public key ===\n",
|
||||
"\n",
|
||||
"N=9039395017187541924674204339436090645879983879639675848014372451895974442048802001144807129089503774586739781388049268071126576402394788054433636812091887 e=65537\n",
|
||||
"\n",
|
||||
"Message=5\n",
|
||||
"Cipher=3544860157153023115291949857759384949327036235359598261186917451178297711294191011096096138343964468460279246190156272920524720409418704879718038288800283\n",
|
||||
"Decrypt=5\n",
|
||||
"\n",
|
||||
"=== Private Key PEM format ===\n",
|
||||
"Private key: -----BEGIN PRIVATE KEY-----\n",
|
||||
"MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEArJekeLwmsS1Gif9t\n",
|
||||
"W85cd5FXHJV6HCN3oaIbeEkXoJIZAzQwguv/F2I/uy+A5bJGRk8Ls1oILZSRh6kk\n",
|
||||
"5hRx7wIDAQABAkA3GSoeiSJpCaUtROfqmRSX70Q6EdYryX7VkOToH511WuhnZ6nZ\n",
|
||||
"lq4f44Kl0GSwjyRKN8Y51iaGhQZf77YFqh3BAiEA2jwaDeS8C1/L3UDNHCOGTkeI\n",
|
||||
"lE+9tJXpt/MXiIiURb8CIQDKdY+iOSk5zCw4ICTXOePdQVzEW5qPZLj1kHsfJoK/\n",
|
||||
"0QIgbxLf/+pHe1KKpFXzDztVhEoMTdA4Mc2LY0Cq3acGMGkCIGUIj9ozzlfyhOqp\n",
|
||||
"V9k0IXtrv+CZmiMO76JULK0Z6cvRAiEAqBdXqjbpaMEscG+U2pSvp7wJaNL+wTml\n",
|
||||
"2Ex3GP+obQQ=\n",
|
||||
"-----END PRIVATE KEY-----\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"=== Public Key PEM format ===\n",
|
||||
"Public key: -----BEGIN PUBLIC KEY-----\n",
|
||||
"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKyXpHi8JrEtRon/bVvOXHeRVxyVehwj\n",
|
||||
"d6GiG3hJF6CSGQM0MILr/xdiP7svgOWyRkZPC7NaCC2UkYepJOYUce8CAwEAAQ==\n",
|
||||
"-----END PUBLIC KEY-----\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/hazmat/hashnew5\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric import rsa\n",
|
||||
"from cryptography.hazmat.primitives import serialization\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"size=512\n",
|
||||
"M=5\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
"\tprint(f\"RSA key size: {size}\\nM={M}\\n\")\n",
|
||||
"\n",
|
||||
"\tprivate_key = rsa.generate_private_key(public_exponent=65537,key_size=size,backend=default_backend())\n",
|
||||
"\n",
|
||||
"\tpriv= private_key.private_numbers()\n",
|
||||
"\tp=priv.p\n",
|
||||
"\tq=priv.q \n",
|
||||
"\td=priv.d\n",
|
||||
"\tn=p*q\n",
|
||||
"\tprint(\"=== RSA Private key ===\")\n",
|
||||
"\tprint (f\"p={p} q={q} d={d} N={n}\")\n",
|
||||
"\tprint (f\"\\nBit length of p and q is {p.bit_length()}\")\n",
|
||||
"\tprint (f\"Bit length of N is {n.bit_length()}\")\n",
|
||||
"\n",
|
||||
"\tprint(\"\\n=== RSA Public key ===\")\n",
|
||||
"\tpub = private_key.public_key()\n",
|
||||
"\te=pub.public_numbers().e\n",
|
||||
"\tn=pub.public_numbers().n\n",
|
||||
"\tprint (f\"\\nN={n} e={e}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\tC = pow(M,e,n)\n",
|
||||
"\tPlain = pow(C,d,n)\n",
|
||||
"\tprint (f\"\\nMessage={M}\")\n",
|
||||
"\tprint (f\"Cipher={C}\")\n",
|
||||
"\tprint (f\"Decrypt={Plain}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\tprint(\"\\n=== Private Key PEM format ===\")\n",
|
||||
"\tpem = private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())\n",
|
||||
"\tprint (\"Private key: \",pem.decode())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\tpem = pub.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo)\n",
|
||||
"\n",
|
||||
"\tprint(\"\\n=== Public Key PEM format ===\")\n",
|
||||
"\tprint (\"Public key: \",pem.decode())\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fc3f0b7a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### DER and PEM format\n",
|
||||
"We need ways to distribute our public keys, private keys and digital certificates in a portable format. One of the most common forms is Distinguished Encoding Rules (DER) encoding of ASN.1. Overall it is truly binary representation of the encoded data. The other common format is PEM, and which converts the binary encoding into a text readable format. With PEM we can encode cryptographic infromation in a Base64 ASCII format and with plain-text headers and footers of \"-----BEGIN RSA PRIVATE KEY-----\" and \"-----END RSA PRIVATE KEY-----\", whereas with DER we have binary format. \n",
|
||||
"\n",
|
||||
"We need ways to distribute our public keys, private keys and digital certificates in a portable format. One of the most common forms is Distinguished Encoding Rules (DER) encoding of ASN.1 (Abstract Syntax Notation One). Overall it is a truly binary representation of the encoded data. The other common format is PEM, and which converts the binary encoding into a text readable format. With PEM we can encode cryptographic information in a Base64 ASCII format and with plain-text headers and footers of “ — — -BEGIN RSA PRIVATE KEY — — -” and “ — — -END RSA PRIVATE KEY — — -”, whereas with DER we have binary format.\n",
|
||||
"\n",
|
||||
"This page will look at the DER format and has code to decode a hex string and into its contents. Overall ASN.1 is used to define abstract types and values. One of the most basic types is SEQUENCE and is an ordered collection of one or more types. In DER, SEQUENCE is identified with a tag of “30”, and followed by a byte value for the length of the object defined. The other common types are OBJECT IDENTIFIER (and which has a tag of “06”) and BIT STRING (and which has a tag of “03”).\n",
|
||||
"\n",
|
||||
"The object identifier tag is used to define the cryptography methods used. An example identifier for ECC encryption is “1.2.840.10045.2.1”, and where 1 is OSI, 2 is member body, 840 is US (ANSI), and 10045 is “ansi-X9–62”, and “2” is key type [1]. Other common algorithms are: “1.2.840.113549.1.1.1” (X509 RSA), “1.2.840.10040.4.1” (X509 Digital Signature Standard -DSS), and “1.2.840.10046.2.1” (Diffie-Hellman — DH). The following is an example of the hex sequence for an object ID, and where we have the “06” tag, followed by an identifier for seven bytes (“07”), and then the Object ID of seven bytes (“2a8648ce3d0201”):\n",
|
||||
"\n",
|
||||
"06 07 2a8648ce3d0201 # Object ID - 7 bytes long - 1.2.840.10045.2.1 (ECC)\n",
|
||||
"\n",
|
||||
"We can also define the curve type in the object identifier, and where we have the form of iso(1), member-body(2), us(840), ansi-X9–62(10045), curves(3), prime(1). For example, 1.2.840.10045.3.1.7 defines ECDSA P-256. Other examples are SECP192R1 (“1.2.840.10045.3.1.1”), SECP224R1 (“1.3.132.0.33”), SECP256K1 (“1.3.132.0.10”), SECP256R1 (“1.2.840.10045.3.1.7”), SECP384R1 (“1.3.132.0.34”), SECP521R1 (“1.3.132.0.35”), and BRAINPOOLP256R1 (“1.3.36.3.3.2.8.1.1.7”). An example where we have an identifier (“06”), followed by the number of bytes identifier (“08”) and Object ID of eight bytes (“2a8648ce3d030107”):\n",
|
||||
"\n",
|
||||
"06 08 2a8648ce3d030107 # Object ID - 8 bytes long - 1.2.840.10045.3.1.7 (ECDSA P256)\n",
|
||||
"\n",
|
||||
"For the “03” tag, we define a bitstream for keys. In the following, we have “03”, followed by the number of bytes (66 bytes) for the keys, and then the keys are defined after this (64 bytes):\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"03 42 # Bit stream - 0x42 (66 bytes long)\n",
|
||||
"\n",
|
||||
"0004 # Identifies public key\n",
|
||||
"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838 # Identifies public key x co-ordinate\n",
|
||||
"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e # Identifies public key y co-ordinate\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"An example hex string for a DER format for ECC public keys is:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"3059301306072a8648ce3d020106082a8648ce3d030107034200042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"We can then break down with:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"30 59 # Sequence length 0x59 - 91 bytes long\n",
|
||||
"30 13 # Sequence length 0x13 - 21 bytes long\n",
|
||||
"06 07 2a8648ce3d0201 # Object ID - 7 bytes long - 1.2.840.10045.2.1 (ECC)\n",
|
||||
"06 08 2a8648ce3d030107 # Object ID - 8 bytes long - 1.2.840.10045.3.1.7 (ECDSA P256)\n",
|
||||
"03 42 # Bit stream - 0x42 (66 bytes long)\n",
|
||||
"0004 # Identifies public key\n",
|
||||
"2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838 # Identifies public key x co-ordinate\n",
|
||||
"c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e # Identifies public key y co-ordinate\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"If we need to convert a DER into a hex format, we can just use \"xxd\" and \"tr\":\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"% xxd -plain 512b-rsa-example-keypair.der | tr -d '\\n'\n",
|
||||
"3082013b0201000241009bfc6690798442bbab13fd2b7bf8de1512e5f193e3068a7bb8b1e19e26bb9501bfe730ed648502dd1569a834b006ec3f353c1e1b2b8ffa8f001bdf07c6ac5307020301000102401b4af77b31f7e56146d6d1866943ab400eb5732688239dd9760091d4853c6f1ec051ebe6905b417fe6aa316bac59539626f1aedabe55a47540225f2717a0d291022100c8c4277cd561adbf328e1ecbe894f49f5577e5a8c970d00f8104b709b21b53e9022100c6e665be10c86db71eee8e41bce867099d8dee461bd590b9ee0dc5f9c6c9c96f0221009bb0318706da36a89c85c5b00eeee43c6345151dad0904efe0f74d1201c25b71022046d1258c84a1381f290e3aec40fc6623504b8678c3d448514ae6f0843c3900550221008d036e290ed74e1f2770b52079fb316a14b7e6559a6540cfe0e646f8b28ef4630a\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"In OpenSSL, we can convert from DER to PEM with:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl x509 -inform der -in mycert.der -out mycert.pem\n",
|
||||
"```\n",
|
||||
"and:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl x509 -outform der -in mycert.pem -out mycert.der\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"An example of a public key is:\n",
|
||||
"```\n",
|
||||
"-----BEGIN PUBLIC KEY-----\n",
|
||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw51PMBm2psyIjHPU1efH\n",
|
||||
"Ulyh22zy3hEhlsNPH6/Cqg0HJorX1WbNKLfiU2aAt24jn4CC+y8PusrmMMCIca5x\n",
|
||||
"0L4XZxm14QvKKImIOMOMblS1Te29n64HuuQ9owKLHuSMww4wiLiY/nAvjK/5/kKT\n",
|
||||
"HL6x7nK/Pq72eoQ/etFBkaX5nYGUD/+G+5BgAPx1mBgU5/y9+/+QZ9xbYU6zogOW\n",
|
||||
"Tfa6rDMSAbmJOtkk1ghnuaq4dSoHWbW+zpHMVtjtHgzDGhX9KjOmvSDQIGn4wevD\n",
|
||||
"p2yDLULUbsdO4ylacTkxyIc92ZHdZeP6Hh+KhNC04Z65zwXLEA3M4bucX+u6nszW\n",
|
||||
"xwIDAQAB\n",
|
||||
"-----END PUBLIC KEY-----\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "3ca1eac1",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"=== Private Key PEM format ===\n",
|
||||
"\n",
|
||||
"Private key (PEM):\n",
|
||||
" -----BEGIN PRIVATE KEY-----\n",
|
||||
"MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA15v1euL6NUSl9Mcx\n",
|
||||
"+/u9x+K9/6/Ird29f37QXQTvWc7BBRaRLDOY4LGA3DclBAWP6zrsMjrgC9nvdOJV\n",
|
||||
"5QaXnwIDAQABAkEAq4ZWFyoFFWWEhSQG/sj55M/ciVGl27PA8nHHf4jShWVAF1bO\n",
|
||||
"/4XrU+L64kAHrx3oK2QyU3zTisziZo1dV0VFgQIhAP76XMiECELFvm0hVH1uJw7I\n",
|
||||
"jwfZBVTdLXXQXX78bebfAiEA2HkzEAiz+zv3/QO7jjWHgBBFd8RlkxRkfxX6in5t\n",
|
||||
"J0ECIQCF5hQzeKKd7hpCVO55sA7yxH/YLy+NkVj+NZ3jwcw1IQIgNJW8gbibf/wh\n",
|
||||
"UaUGepUmRUWumllrEz9w6i48nkf33AECIHS/+veFHnZSYgG5FP3Cbs8IIhGxXzVg\n",
|
||||
"IOdwpeFnzOrq\n",
|
||||
"-----END PRIVATE KEY-----\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Private key (DER):\n",
|
||||
" 30820155020100300d06092a864886f70d01010105000482013f3082013b020100024100d79bf57ae2fa3544a5f4c731fbfbbdc7e2bdffafc8adddbd7f7ed05d04ef59cec10516912c3398e0b180dc372504058feb3aec323ae00bd9ef74e255e506979f0203010001024100ab8656172a05156584852406fec8f9e4cfdc8951a5dbb3c0f271c77f88d28565401756ceff85eb53e2fae24007af1de82b6432537cd38acce2668d5d57454581022100fefa5cc8840842c5be6d21547d6e270ec88f07d90554dd2d75d05d7efc6de6df022100d879331008b3fb3bf7fd03bb8e358780104577c4659314647f15fa8a7e6d274102210085e6143378a29dee1a4254ee79b00ef2c47fd82f2f8d9158fe359de3c1cc352102203495bc81b89b7ffc2151a5067a95264545ae9a596b133f70ea2e3c9e47f7dc01022074bffaf7851e76526201b914fdc26ecf082211b15f356020e770a5e167cceaea\n",
|
||||
"\n",
|
||||
"=== Public Key format ===\n",
|
||||
"Public key (PEM):\n",
|
||||
" -----BEGIN PUBLIC KEY-----\n",
|
||||
"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANeb9Xri+jVEpfTHMfv7vcfivf+vyK3d\n",
|
||||
"vX9+0F0E71nOwQUWkSwzmOCxgNw3JQQFj+s67DI64AvZ73TiVeUGl58CAwEAAQ==\n",
|
||||
"-----END PUBLIC KEY-----\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Public key (DER):\n",
|
||||
" 305c300d06092a864886f70d0101010500034b003048024100d79bf57ae2fa3544a5f4c731fbfbbdc7e2bdffafc8adddbd7f7ed05d04ef59cec10516912c3398e0b180dc372504058feb3aec323ae00bd9ef74e255e506979f0203010001\n",
|
||||
"\n",
|
||||
"Public key (OpenSSL):\n",
|
||||
" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDXm/V64vo1RKX0xzH7+73H4r3/r8it3b1/ftBdBO9ZzsEFFpEsM5jgsYDcNyUEBY/rOuwyOuAL2e904lXlBpef\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/hazmat/hashnew6\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric import rsa\n",
|
||||
"from cryptography.hazmat.primitives import serialization\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"size=512\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" private_key = rsa.generate_private_key(public_exponent=65537,key_size=size,backend=default_backend())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" pub = private_key.public_key()\n",
|
||||
"\n",
|
||||
" print(\"\\n=== Private Key PEM format ===\")\n",
|
||||
" pem = private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())\n",
|
||||
"\n",
|
||||
" der= private_key.private_bytes(encoding=serialization.Encoding.DER,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" print (\"\\nPrivate key (PEM):\\n\",pem.decode())\n",
|
||||
" print (\"\\nPrivate key (DER):\\n\",binascii.b2a_hex(der).decode())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" pem = pub.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo).decode(\"utf-8\")\n",
|
||||
"\n",
|
||||
" openssh = pub.public_bytes(encoding=serialization.Encoding.OpenSSH,format=serialization.PublicFormat.OpenSSH)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" print(\"\\n=== Public Key format ===\")\n",
|
||||
"\n",
|
||||
" der=''.join(pem.split('\\n')[1:-2])\n",
|
||||
" print (\"Public key (PEM):\\n\",pem)\n",
|
||||
" print (\"\\nPublic key (DER):\\n\",binascii.b2a_hex(binascii.a2b_base64(der)).decode())\n",
|
||||
" print (\"\\nPublic key (OpenSSL):\\n\",openssh.decode())\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5375d045",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Elliptic Curve\n",
|
||||
"With Elliptic Curve Cryptography (ECC) we can use a Weierstrass curve form of the form of y^2=x^3+ax+b(modp). Bitcoin and Ethereum use secp256k1 and which has the form of y^2=x^3+7(modp). In most cases, though, we use the NIST defined curves. These are SECP256R1, SECP384R1, and SECP521R1, but an also use SECP224R1 and SECP192R1. SECP256R1 has 256-bit (x,y) points, and where the private key is a 256-bit scalar value (a) and which gives a public key point of a.G. In this case, G is the base point of the curve. This page generates a range of ECC key pair, and displays the private and public key in various formats. The encoding formats are PEM, DER and Raw, and the formating is undertaken with OpenSSH, PublicSubjectInfo and Raw. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "477d486c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from cryptography.hazmat.primitives import serialization as crypto_serialization\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric import ec\n",
|
||||
"from cryptography.hazmat.backends import default_backend as crypto_default_backend\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"private_key_encoding= crypto_serialization.Encoding.PEM\n",
|
||||
"private_key_format= crypto_serialization.PrivateFormat.OpenSSH\n",
|
||||
"public_key_format= crypto_serialization.PublicFormat.OpenSSH\n",
|
||||
"# PEM or DER\n",
|
||||
"public_key_encode=0\n",
|
||||
"public_key_form=0\n",
|
||||
"private_key_encode=0\n",
|
||||
"private_key_form=0\n",
|
||||
"curve =0\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"if (private_key_encode==0): \n",
|
||||
"\tprivate_key_encoding= crypto_serialization.Encoding.PEM\n",
|
||||
"elif (private_key_encode==1): \n",
|
||||
"\tprivate_key_encoding= crypto_serialization.Encoding.DER\n",
|
||||
"else:\n",
|
||||
"\tprivate_key_encoding= crypto_serialization.Encoding.Raw\n",
|
||||
"\n",
|
||||
"if (private_key_form==0): \n",
|
||||
"\tprivate_key_format= crypto_serialization.PrivateFormat.PKCS8\n",
|
||||
"elif (private_key_form==1): \n",
|
||||
"\tprivate_key_format= crypto_serialization.PrivateFormat.OpenSSH\n",
|
||||
"else:\n",
|
||||
"\tprivate_key_format= crypto_serialization.PrivateFormat.Raw\n",
|
||||
"\n",
|
||||
"if (public_key_encode==0): \n",
|
||||
"\tpublic_key_encoding= crypto_serialization.Encoding.PEM\n",
|
||||
"elif (public_key_encode==1): \n",
|
||||
"\tpublic_key_encoding= crypto_serialization.Encoding.DER\n",
|
||||
"elif (public_key_encode==2): \n",
|
||||
"\tpublic_key_encoding= crypto_serialization.Encoding.OpenSSH\n",
|
||||
"else:\n",
|
||||
"\tpublic_key_encoding= crypto_serialization.Encoding.Raw\n",
|
||||
"\n",
|
||||
"if (public_key_form==0): \n",
|
||||
"\tpublic_key_format= crypto_serialization.PublicFormat.SubjectPublicKeyInfo\n",
|
||||
"elif (public_key_form==1): \n",
|
||||
"\tpublic_key_format= crypto_serialization.PublicFormat.OpenSSH\n",
|
||||
"else:\n",
|
||||
"\tpublic_key_format= crypto_serialization.PublicFormat.Raw\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"key=ec.generate_private_key(ec.SECP256K1())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
"\tprint(\"Private key encoding:\\t\",private_key_encoding)\n",
|
||||
"\tprint(\"Private key format:\\t\",private_key_format)\n",
|
||||
"\tprint(\"Public key encoding:\\t\",public_key_encoding)\n",
|
||||
"\tprint(\"Public key format:\\t\",public_key_format)\n",
|
||||
"\tprint(\"Curve:\\t\\t\\t\",key.curve.name)\n",
|
||||
"\tprint(\"Key size:\\t\\t\",key.curve.key_size)\n",
|
||||
"\n",
|
||||
"\tprivate_key = key.private_bytes(private_key_encoding,private_key_format,crypto_serialization.NoEncryption())\n",
|
||||
"\n",
|
||||
"\tif (private_key_encoding== crypto_serialization.Encoding.DER or private_key_encoding== crypto_serialization.Encoding.Raw):\n",
|
||||
"\t\tprint(f\"\\nPrivate key:\\n{binascii.b2a_hex(private_key).decode()}\")\n",
|
||||
"\telse:\n",
|
||||
"\t\tprint(f\"\\nPrivate key:\\n{private_key.decode()}\")\n",
|
||||
"except Exception as e:\n",
|
||||
"\tprint(\"Private key error: \",e) \n",
|
||||
"try:\n",
|
||||
"\tpublic_key = key.public_key().public_bytes(public_key_encoding,public_key_format)\n",
|
||||
"\n",
|
||||
"\tif (public_key_encoding== crypto_serialization.Encoding.DER or public_key_encoding== crypto_serialization.Encoding.Raw):\n",
|
||||
"\t\tprint(f\"\\nPublic key:\\n{binascii.b2a_hex(public_key).decode()}\")\n",
|
||||
"\telse:\n",
|
||||
"\t\tprint(f\"\\nPublic key:\\n{public_key.decode()}\")\n",
|
||||
"except Exception as e:\n",
|
||||
"\tprint(\"Public key error: \",e) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "806aa071",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Modify the program so that it shows the keys as PEM, DER and Raw. How do the key differ?\n",
|
||||
"> Update the program so that is uses the SECP256R1 curve, and verify its operation.\n",
|
||||
"> Update the program so that is uses the SECP521R1 curve, and verify its operation."
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
483
z_jupyter/08_public_key_enc.ipynb
Normal file
@@ -0,0 +1,483 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7782a35",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# Public Key Encryption\n",
|
||||
"The two main method used for public key methods are RSA and ECC (Elliptic Curve Cryptography). With encryption Bob can use Alice's public key to encrypt data, and then she will use her private key to decrypt it:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_public_04.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## RSA\n",
|
||||
"Overall, Bob generates two random prime numbers (p and q), and create a public modulus of:\n",
|
||||
"\n",
|
||||
"N=p.q\n",
|
||||
"\n",
|
||||
"Next Bob computes φ:\n",
|
||||
"\n",
|
||||
"φ=(p−1).(q−1)\n",
|
||||
"\n",
|
||||
"Bob then picks a public exponent of e and which does not share a factor with φ, and computes the private exponent as:\n",
|
||||
"\n",
|
||||
"d=e^{−1}(modφ)\n",
|
||||
"\n",
|
||||
"Bob will then use a public exponent (e) to cipher a message (M) with:\n",
|
||||
"\n",
|
||||
"C=M^e (mod N)\n",
|
||||
"\n",
|
||||
"To decrypt we use the private exponent (d) to decipher the ciphertext:\n",
|
||||
"\n",
|
||||
"M=C^d (mod N)\n",
|
||||
"\n",
|
||||
"Bob's public key is [e,N] and his private key is [d,N].\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_public_12.png' width=\"800px\">\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "8fcac21d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message=Hello\n",
|
||||
"p=1015811308611355393\n",
|
||||
"q=755523213775410319\n",
|
||||
"\n",
|
||||
"d=589399628769593821059839430475148801\n",
|
||||
"e=65537\n",
|
||||
"N=767469024471456365658376241308500367\n",
|
||||
"\n",
|
||||
"Private key (d,n)\n",
|
||||
"Public key (e,n)\n",
|
||||
"\n",
|
||||
"cipher=302667991570245321224673969207643936\n",
|
||||
"decipher=b'Hello'\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/rsa/rsa12\n",
|
||||
"from Crypto.Util.number import *\n",
|
||||
"from Crypto import Random\n",
|
||||
"import Crypto\n",
|
||||
"import libnum\n",
|
||||
"\n",
|
||||
"bits=60\n",
|
||||
"msg=\"Hello\"\n",
|
||||
"\n",
|
||||
"p = Crypto.Util.number.getPrime(bits, randfunc=Crypto.Random.get_random_bytes)\n",
|
||||
"q = Crypto.Util.number.getPrime(bits, randfunc=Crypto.Random.get_random_bytes)\n",
|
||||
"\n",
|
||||
"n = p*q\n",
|
||||
"PHI=(p-1)*(q-1)\n",
|
||||
"\n",
|
||||
"e=65537\n",
|
||||
"d=libnum.invmod(e,PHI)\n",
|
||||
"\n",
|
||||
"m= bytes_to_long(msg.encode('utf-8'))\n",
|
||||
"\n",
|
||||
"c=pow(m,e, n)\n",
|
||||
"res=pow(c,d ,n)\n",
|
||||
"\n",
|
||||
"print (\"Message=%s\\np=%s\\nq=%s\\n\\nd=%d\\ne=%d\\nN=%s\\n\\nPrivate key (d,n)\\nPublic key (e,n)\\n\\ncipher=%s\\ndecipher=%s\" % (msg,p,q,d,e,n,c,(long_to_bytes(res))))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "788ce969",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"> Change the size of the prime numbers to 100 bits, and verify that the program works.\n",
|
||||
"\n",
|
||||
"> Change the \"d=libnum.invmod(e,PHI)\" to \"pow(e,-1,PHI)\" and show that the code still works correctly."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0a96db97",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"A more complex example is:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6d7657bf",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/hazmat/hashnew8\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric import rsa\n",
|
||||
"from cryptography.hazmat.primitives import serialization\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric import padding\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"size=1024\n",
|
||||
"message = b\"Hello world\"\n",
|
||||
"\n",
|
||||
"if (len(sys.argv)>1):\n",
|
||||
"\tmessage=str(sys.argv[1]).encode()\n",
|
||||
"if (len(sys.argv)>2):\n",
|
||||
"\tsize=int(sys.argv[2])\n",
|
||||
"\n",
|
||||
"print(\"Message: \",message)\n",
|
||||
"print(\"Key size: \",size)\n",
|
||||
"try:\n",
|
||||
" private_key = rsa.generate_private_key(public_exponent=65537,key_size=size)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" pub = private_key.public_key()\n",
|
||||
"\n",
|
||||
" ciphertext = pub.encrypt(message,padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),algorithm=hashes.SHA256(),label=None))\n",
|
||||
"\n",
|
||||
" print (\"\\nCiphertext:\\n\",binascii.b2a_hex(ciphertext).decode())\n",
|
||||
"\n",
|
||||
" plaintext = private_key.decrypt(ciphertext,padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),algorithm=hashes.SHA256(),label=None))\n",
|
||||
" print(\"\\nDecrypted Message: \",plaintext.decode())\n",
|
||||
"\n",
|
||||
" print(\"\\n=== Private Key PEM format ===\")\n",
|
||||
" pem = private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" print (\"\\nPrivate key (PEM):\\n\",pem.decode())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" pem = pub.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo).decode(\"utf-8\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" print(\"\\n=== Public Key format ===\")\n",
|
||||
" print (\"Public key (PEM):\\n\",pem)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3d288d40",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Implement the code with 2K RSA key, and verify its operation.\n",
|
||||
"\n",
|
||||
"> Implement the program using a DER format for the keys. When you view the keys, what do you observe from the first two hex characters of the hex value of the keys?\n",
|
||||
"\n",
|
||||
"> The code uses SHA-256 for the padding method. Change the implementation of this to SHA-1, and verify the operation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6d4d695a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ECIES\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"<img src='graphics/ecc3.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "ada57ad3",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Private key: 0x8429f9e6136fcfa883130853defd319d931e25207749de92b5e12a80c8e62619\n",
|
||||
"Public key: (0xa4581b11e2aa0249274374216d8fb965517e45e6bcc337f3fc679c2bfd84dce7, 0x4716b0eaf5f748af3921aac8455e623b96b590453f313b4d200419a801c11267)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"=========================\n",
|
||||
"Random value: 23353093005829895849666617279986636640\n",
|
||||
"rG: (38430190155405327152400342621384391216588051326127513706497722898874838651319, 32551409443475257236910193737311399537798158570670164100113247023590451377060)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"======Symmetric key========\n",
|
||||
"Encryption key: 34425016396310312658614745921144437662843062008454472115656949568073393878924 34425016396310312658614745921144437662843062008454472115656949568073393878924\n",
|
||||
"Encrypted:\t b'02c9b6ed4ffcf2bdf4f3118ecc232326'\n",
|
||||
"Decrypted:\t Hello\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/ecc/ecc3\n",
|
||||
"import collections\n",
|
||||
"import hashlib\n",
|
||||
"import random\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"from Crypto.Cipher import AES\n",
|
||||
"import Padding\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def enc_long(n):\n",
|
||||
" '''Encodes arbitrarily large number n to a sequence of bytes.\n",
|
||||
" Big endian byte order is used.'''\n",
|
||||
" s = \"\"\n",
|
||||
" while n > 0:\n",
|
||||
" s = chr(n & 0xFF) + s\n",
|
||||
" n >>= 8\n",
|
||||
" return s\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Padding for the input string --not\n",
|
||||
"# related to encryption itself.\n",
|
||||
"BLOCK_SIZE = 16 # Bytes\n",
|
||||
"pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * \\\n",
|
||||
" chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)\n",
|
||||
"unpad = lambda s: s[:-ord(s[len(s) - 1:])]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def encrypt(plaintext,key, mode):\n",
|
||||
"\tencobj = AES.new(key,mode)\n",
|
||||
"\treturn(encobj.encrypt(plaintext))\n",
|
||||
"\n",
|
||||
"def decrypt(ciphertext,key, mode):\n",
|
||||
"\tencobj = AES.new(key,mode)\n",
|
||||
"\treturn(encobj.decrypt(ciphertext))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"EllipticCurve = collections.namedtuple('EllipticCurve', 'name p a b g n h')\n",
|
||||
"\n",
|
||||
"curve = EllipticCurve(\n",
|
||||
" 'secp256k1',\n",
|
||||
" # Field characteristic.\n",
|
||||
" p=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,\n",
|
||||
" # Curve coefficients.\n",
|
||||
" a=0,\n",
|
||||
" b=7,\n",
|
||||
" # Base point.\n",
|
||||
" g=(0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,\n",
|
||||
" 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8),\n",
|
||||
" # Subgroup order.\n",
|
||||
" n=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,\n",
|
||||
" # Subgroup cofactor.\n",
|
||||
" h=1,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Modular arithmetic ##########################################################\n",
|
||||
"\n",
|
||||
"def inverse_mod(k, p):\n",
|
||||
" \"\"\"Returns the inverse of k modulo p.\n",
|
||||
" This function returns the only integer x such that (x * k) % p == 1.\n",
|
||||
" k must be non-zero and p must be a prime.\n",
|
||||
" \"\"\"\n",
|
||||
" if k == 0:\n",
|
||||
" raise ZeroDivisionError('division by zero')\n",
|
||||
"\n",
|
||||
" if k < 0:\n",
|
||||
" # k ** -1 = p - (-k) ** -1 (mod p)\n",
|
||||
" return p - inverse_mod(-k, p)\n",
|
||||
"\n",
|
||||
" # Extended Euclidean algorithm.\n",
|
||||
" s, old_s = 0, 1\n",
|
||||
" t, old_t = 1, 0\n",
|
||||
" r, old_r = p, k\n",
|
||||
"\n",
|
||||
" while r != 0:\n",
|
||||
" quotient = old_r // r\n",
|
||||
" old_r, r = r, old_r - quotient * r\n",
|
||||
" old_s, s = s, old_s - quotient * s\n",
|
||||
" old_t, t = t, old_t - quotient * t\n",
|
||||
"\n",
|
||||
" gcd, x, y = old_r, old_s, old_t\n",
|
||||
"\n",
|
||||
" assert gcd == 1\n",
|
||||
" assert (k * x) % p == 1\n",
|
||||
"\n",
|
||||
" return x % p\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Functions that work on curve points #########################################\n",
|
||||
"\n",
|
||||
"def is_on_curve(point):\n",
|
||||
" \"\"\"Returns True if the given point lies on the elliptic curve.\"\"\"\n",
|
||||
" if point is None:\n",
|
||||
" # None represents the point at infinity.\n",
|
||||
" return True\n",
|
||||
"\n",
|
||||
" x, y = point\n",
|
||||
"\n",
|
||||
" return (y * y - x * x * x - curve.a * x - curve.b) % curve.p == 0\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def point_neg(point):\n",
|
||||
" \"\"\"Returns -point.\"\"\"\n",
|
||||
" assert is_on_curve(point)\n",
|
||||
"\n",
|
||||
" if point is None:\n",
|
||||
" # -0 = 0\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
" x, y = point\n",
|
||||
" result = (x, -y % curve.p)\n",
|
||||
"\n",
|
||||
" assert is_on_curve(result)\n",
|
||||
"\n",
|
||||
" return result\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def point_add(point1, point2):\n",
|
||||
" \"\"\"Returns the result of point1 + point2 according to the group law.\"\"\"\n",
|
||||
" assert is_on_curve(point1)\n",
|
||||
" assert is_on_curve(point2)\n",
|
||||
"\n",
|
||||
" if point1 is None:\n",
|
||||
" # 0 + point2 = point2\n",
|
||||
" return point2\n",
|
||||
" if point2 is None:\n",
|
||||
" # point1 + 0 = point1\n",
|
||||
" return point1\n",
|
||||
"\n",
|
||||
" x1, y1 = point1\n",
|
||||
" x2, y2 = point2\n",
|
||||
"\n",
|
||||
" if x1 == x2 and y1 != y2:\n",
|
||||
" # point1 + (-point1) = 0\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
" if x1 == x2:\n",
|
||||
" # This is the case point1 == point2.\n",
|
||||
" m = (3 * x1 * x1 + curve.a) * inverse_mod(2 * y1, curve.p)\n",
|
||||
" else:\n",
|
||||
" # This is the case point1 != point2.\n",
|
||||
" m = (y1 - y2) * inverse_mod(x1 - x2, curve.p)\n",
|
||||
"\n",
|
||||
" x3 = m * m - x1 - x2\n",
|
||||
" y3 = y1 + m * (x3 - x1)\n",
|
||||
" result = (x3 % curve.p,\n",
|
||||
" -y3 % curve.p)\n",
|
||||
"\n",
|
||||
" assert is_on_curve(result)\n",
|
||||
"\n",
|
||||
" return result\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def scalar_mult(k, point):\n",
|
||||
" \"\"\"Returns k * point computed using the double and point_add algorithm.\"\"\"\n",
|
||||
" assert is_on_curve(point)\n",
|
||||
"\n",
|
||||
" if k % curve.n == 0 or point is None:\n",
|
||||
" return None\n",
|
||||
"\n",
|
||||
" if k < 0:\n",
|
||||
" # k * point = -k * (-point)\n",
|
||||
" return scalar_mult(-k, point_neg(point))\n",
|
||||
"\n",
|
||||
" result = None\n",
|
||||
" addend = point\n",
|
||||
"\n",
|
||||
" while k:\n",
|
||||
" if k & 1:\n",
|
||||
" # Add.\n",
|
||||
" result = point_add(result, addend)\n",
|
||||
"\n",
|
||||
" # Double.\n",
|
||||
" addend = point_add(addend, addend)\n",
|
||||
"\n",
|
||||
" k >>= 1\n",
|
||||
"\n",
|
||||
" assert is_on_curve(result)\n",
|
||||
"\n",
|
||||
" return result\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Keypair generation and ECDSA ################################################\n",
|
||||
"\n",
|
||||
"def make_keypair():\n",
|
||||
" \"\"\"Generates a random private-public key pair.\"\"\"\n",
|
||||
" private_key = random.randrange(1, curve.n)\n",
|
||||
" public_key = scalar_mult(private_key, curve.g)\n",
|
||||
"\n",
|
||||
" return private_key, public_key\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"message=\"Hello\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"dA, Qa = make_keypair()\n",
|
||||
"print(\"Private key:\", hex(dA))\n",
|
||||
"print((\"Public key: (0x{:x}, 0x{:x})\".format(*Qa)))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"\\n\\n=========================\")\n",
|
||||
"\n",
|
||||
"r = random.randint(0, 2**128)\n",
|
||||
"\n",
|
||||
"rG = scalar_mult(r,curve.g)\n",
|
||||
"S = scalar_mult(r,Qa)\n",
|
||||
"\n",
|
||||
"print(\"Random value: \" , r)\n",
|
||||
"print(\"rG: \" , rG)\n",
|
||||
"\n",
|
||||
"print(\"\\n\\n======Symmetric key========\")\n",
|
||||
"\n",
|
||||
"print(\"Encryption key:\",S[0],str(S[0]))\n",
|
||||
"password='hello'\n",
|
||||
"\n",
|
||||
"key = hashlib.sha256(str(S[0]).encode()).digest()\n",
|
||||
"\n",
|
||||
"message = Padding.appendPadding(message,blocksize=Padding.AES_blocksize,mode=0)\n",
|
||||
"\n",
|
||||
"ciphertext = encrypt(message.encode(),key,AES.MODE_ECB)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"Encrypted:\\t\",binascii.hexlify(ciphertext))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Snew = scalar_mult(dA,rG)\n",
|
||||
"key = hashlib.sha256(str(Snew[0]).encode()).digest()\n",
|
||||
"\n",
|
||||
"text = decrypt(ciphertext,key,AES.MODE_ECB)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(\"Decrypted:\\t\",Padding.removePadding(text.decode(),mode=0))"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
347
z_jupyter/09_public_key_sign.ipynb
Normal file
@@ -0,0 +1,347 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7782a35",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# Public Key Signatures\n",
|
||||
"With a public key signature, we use the private key to sign a hash of the message, and then prove the signature with the public key. In this case, Bob signs a hash of the message with his private key, and then Alice will check this with his public key:\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_sig_10.png' width=\"800px\">\n",
|
||||
"\n",
|
||||
"## RSA Signatures\n",
|
||||
"In the following, we create an RSA signature, using the private key, and then check with the public key:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "8fcac21d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Message=Hello\n",
|
||||
"p=1015811308611355393\n",
|
||||
"q=755523213775410319\n",
|
||||
"\n",
|
||||
"d=589399628769593821059839430475148801\n",
|
||||
"e=65537\n",
|
||||
"N=767469024471456365658376241308500367\n",
|
||||
"\n",
|
||||
"Private key (d,n)\n",
|
||||
"Public key (e,n)\n",
|
||||
"\n",
|
||||
"cipher=302667991570245321224673969207643936\n",
|
||||
"decipher=b'Hello'\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/hazmat/hashnew7\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric import rsa\n",
|
||||
"from cryptography.hazmat.primitives import serialization\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric import padding\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"from cryptography.hazmat.primitives import exceptions\n",
|
||||
"\n",
|
||||
"import sys\n",
|
||||
"import binascii\n",
|
||||
"\n",
|
||||
"size=512\n",
|
||||
"message = b\"Hello world\"\n",
|
||||
"\n",
|
||||
"if (len(sys.argv)>1):\n",
|
||||
"\tmessage=str(sys.argv[1]).encode()\n",
|
||||
"if (len(sys.argv)>2):\n",
|
||||
"\tsize=int(sys.argv[2])\n",
|
||||
"\n",
|
||||
"print(\"Message: \",message)\n",
|
||||
"print(\"Key size: \",size)\n",
|
||||
"try:\n",
|
||||
" private_key = rsa.generate_private_key(public_exponent=65537,key_size=size)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" pub = private_key.public_key()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" signature = private_key.sign(message,padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),hashes.SHA256())\n",
|
||||
"\n",
|
||||
" print (\"\\nSignature: \",binascii.b2a_hex(signature).decode())\n",
|
||||
"\n",
|
||||
" try:\n",
|
||||
" rtn=pub.verify(signature,message,padding.PSS(mgf=padding.MGF1(hashes.SHA256()),salt_length=padding.PSS.MAX_LENGTH),hashes.SHA256())\n",
|
||||
" except exceptions.InvalidSignature:\n",
|
||||
" print(\"A bad signature failed\")\n",
|
||||
" else:\n",
|
||||
" print(\"Good signature verified\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" try:\n",
|
||||
" pub.verify(signature,b\"test\",padding.PSS(mgf=padding.MGF1(hashes.SHA256()),salt_length=padding.PSS.MAX_LENGTH),hashes.SHA256())\n",
|
||||
" except exceptions.InvalidSignature:\n",
|
||||
" print(\"A bad signature failed\")\n",
|
||||
" else:\n",
|
||||
" print(\"Bad signature verified\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" print (\"\\nVerified: \",rtn)\n",
|
||||
" print(\"\\n=== Private Key PEM format ===\")\n",
|
||||
" pem = private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" print (\"\\nPrivate key (PEM):\\n\",pem.decode())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" pem = pub.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo).decode(\"utf-8\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" print(\"\\n=== Public Key format ===\")\n",
|
||||
" print (\"Public key (PEM):\\n\",pem)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(e)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "788ce969",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"> Implement the signature with SHA-1 hashing, and verify the operation/\n",
|
||||
"\n",
|
||||
"> Change the key size of 2,048 bits, and verify the operation."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0a96db97",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ECDSA\n",
|
||||
"ECDSA has been around for over two decades and was first proposed in [1]. The ECDSA method significantly improved the performance of signing messages than the RSA-based DSA method. Its usage of elliptic curve methods speeded up the whole process and supported much smaller key sizes. Its crown and glory were being selected by Satoshi Nakamoto for his Bitcoin protocol, and then its adoption into Ethereum. \n",
|
||||
"\n",
|
||||
"[1] Johnson, D., Menezes, A., & Vanstone, S. (2001). The elliptic curve digital signature algorithm (ECDSA). International journal of information security, 1(1), 36–63 [here].\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_sig_11.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6d7657bf",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/hazmat/hashnew10\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric import ec\n",
|
||||
"from cryptography.hazmat.primitives import serialization\n",
|
||||
"from cryptography.hazmat.primitives import hashes\n",
|
||||
"from cryptography import exceptions\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"private_key = ec.generate_private_key(ec.SECP384R1())\n",
|
||||
"\n",
|
||||
"data = b\"test\"\n",
|
||||
"\n",
|
||||
"if (len(sys.argv)>2):\n",
|
||||
"\ttype=int(sys.argv[2])\n",
|
||||
"if (len(sys.argv)>1):\n",
|
||||
"\tdata=str(sys.argv[1]).encode()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"private_key = ec.generate_private_key(ec.SECP256R1())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"private_vals = private_key.private_numbers()\n",
|
||||
"no_bits=private_vals.private_value.bit_length()\n",
|
||||
"\n",
|
||||
"print (f\"Private key value: {private_vals.private_value}. Number of bits {no_bits}\")\n",
|
||||
"\n",
|
||||
"public_key = private_key.public_key()\n",
|
||||
"pub=public_key.public_numbers()\n",
|
||||
"print (\"Name of curve: \",pub.curve.name)\n",
|
||||
"\n",
|
||||
"print (\"Message: \",data.decode())\n",
|
||||
"try:\n",
|
||||
"\n",
|
||||
" signature = private_key.sign(data,ec.ECDSA(hashes.SHA256()))\n",
|
||||
" print (\"Good Signature: \",binascii.b2a_hex(signature).decode())\n",
|
||||
" public_key.verify(signature, data, ec.ECDSA(hashes.SHA256()))\n",
|
||||
"except exceptions.InvalidSignature:\n",
|
||||
" print(\"A bad signature failed\")\n",
|
||||
"else:\n",
|
||||
" print(\"Good signature verified\")\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
"\n",
|
||||
" signature = private_key.sign(b\"bad message\",ec.ECDSA(hashes.SHA256()))\n",
|
||||
" print (\"Bad Signature: \",binascii.b2a_hex(signature).decode())\n",
|
||||
" public_key.verify(signature, data, ec.ECDSA(hashes.SHA256()))\n",
|
||||
"except exceptions.InvalidSignature:\n",
|
||||
" print(\"A bad signature failed\")\n",
|
||||
"else:\n",
|
||||
" print(\"Good signature verified\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"pem = private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())\n",
|
||||
"\n",
|
||||
"der = private_key.private_bytes(encoding=serialization.Encoding.DER,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"\\nPrivate key (PEM):\\n\",pem.decode())\n",
|
||||
"print (\"Private key (DER):\\n\",binascii.b2a_hex(der))\n",
|
||||
"\n",
|
||||
"pem = public_key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo)\n",
|
||||
"\n",
|
||||
"der = public_key.public_bytes(encoding=serialization.Encoding.DER,format=serialization.PublicFormat.SubjectPublicKeyInfo)\n",
|
||||
"\n",
|
||||
"print (\"\\nPublic key (PEM):\\n\",pem.decode())\n",
|
||||
"print (\"Public key (DER):\\n\",binascii.b2a_hex(der))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3d288d40",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> Implement with the SECP521R1, and observe the differences in the keys sizes used.\n",
|
||||
"\n",
|
||||
"> Implement the code with the BrainpoolP256R1 curve, and verify its operation.\n",
|
||||
"\n",
|
||||
"> The bitcoin curve is secp256k1. Modify the program so that it uses secp256k1."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6d4d695a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## EdDSA\n",
|
||||
"\n",
|
||||
"With Ed25519 we use a private key to sign data, and then the public key can prove it. We use Curve 25519 for the generation of the public key and for the signing process. Curve 25519 uses a Montgomery curve of the form of y2=x3+ax2+x(modp). If we have a point P, we then find a point nP - where n is the number of times we add P. Curve 25519 takes the form of y^2=x^3+486662x^2+x(modp) and a base point at x=9. This gives a base point (G), and where we find the point nG for a given n value, and where n is the private key value, and nG is the public key point. Normally in Curve 25519 we only focus on the x-point, and do not need the (x,y) value.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"<img src='graphics/g_sig_03.png' width=\"800px\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "ada57ad3",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Private key: 0x8429f9e6136fcfa883130853defd319d931e25207749de92b5e12a80c8e62619\n",
|
||||
"Public key: (0xa4581b11e2aa0249274374216d8fb965517e45e6bcc337f3fc679c2bfd84dce7, 0x4716b0eaf5f748af3921aac8455e623b96b590453f313b4d200419a801c11267)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"=========================\n",
|
||||
"Random value: 23353093005829895849666617279986636640\n",
|
||||
"rG: (38430190155405327152400342621384391216588051326127513706497722898874838651319, 32551409443475257236910193737311399537798158570670164100113247023590451377060)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"======Symmetric key========\n",
|
||||
"Encryption key: 34425016396310312658614745921144437662843062008454472115656949568073393878924 34425016396310312658614745921144437662843062008454472115656949568073393878924\n",
|
||||
"Encrypted:\t b'02c9b6ed4ffcf2bdf4f3118ecc232326'\n",
|
||||
"Decrypted:\t Hello\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# https://asecuritysite.com/hazmat/hashnew11\n",
|
||||
"from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey\n",
|
||||
"from cryptography import exceptions\n",
|
||||
"from cryptography.hazmat.primitives import serialization\n",
|
||||
"import binascii\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"data=b\"Test\"\n",
|
||||
"\n",
|
||||
"if (len(sys.argv)>1):\n",
|
||||
"\tdata=str(sys.argv[1]).encode()\n",
|
||||
"\n",
|
||||
"private_key = Ed25519PrivateKey.generate()\n",
|
||||
"public_key = private_key.public_key()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"public_key = private_key.public_key()\n",
|
||||
"\n",
|
||||
"print (\"Message: \",data.decode())\n",
|
||||
"try:\n",
|
||||
"\n",
|
||||
" signature = private_key.sign(data)\n",
|
||||
" print (\"Good Signature: \",binascii.b2a_hex(signature).decode())\n",
|
||||
" public_key.verify(signature, data)\n",
|
||||
"except exceptions.InvalidSignature:\n",
|
||||
" print(\"A bad signature failed\")\n",
|
||||
"else:\n",
|
||||
" print(\"Good signature verified\")\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
"\n",
|
||||
" signature = private_key.sign(b\"Bad data\")\n",
|
||||
" print (\"Bad Signature: \",binascii.b2a_hex(signature).decode())\n",
|
||||
" public_key.verify(signature, data)\n",
|
||||
"except exceptions.InvalidSignature:\n",
|
||||
" print(\"A bad signature failed\")\n",
|
||||
"else:\n",
|
||||
" print(\"Good signature verified\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"pem = private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())\n",
|
||||
"\n",
|
||||
"der = private_key.private_bytes(encoding=serialization.Encoding.DER,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print (\"\\nPrivate key (PEM):\\n\",pem.decode())\n",
|
||||
"print (\"Private key (DER):\\n\",binascii.b2a_hex(der))\n",
|
||||
"\n",
|
||||
"pem = public_key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo)\n",
|
||||
"\n",
|
||||
"der = public_key.public_bytes(encoding=serialization.Encoding.DER,format=serialization.PublicFormat.SubjectPublicKeyInfo)\n",
|
||||
"\n",
|
||||
"print (\"\\nPublic key (PEM):\\n\",pem.decode())\n",
|
||||
"print (\"Public key (DER):\\n\",binascii.b2a_hex(der))"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
532
z_jupyter/10_digital_certs.ipynb
Normal file
@@ -0,0 +1,532 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7782a35",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Trust and Digital Certificates\n",
|
||||
"\n",
|
||||
"Objective: Digital certificates are used to define a trust infrastructure within PKI (Public Key Infrastructure). A certificate can hold a key pair, while a distributable certificate will only contain the public key. In this lab we will read-in digital certificates and analyse them. A lab demo is [here](https://youtu.be/-uNQFv0GTZc).\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## A\tIntroduction\n",
|
||||
"\n",
|
||||
"### A.1\t\n",
|
||||
"From this web link (Digital Certificate): \n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"http://asecuritysite.com/digitalcert/digitalcert\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Open up Certificate 1 and identify the following:\t\n",
|
||||
"\n",
|
||||
"* Serial number:\n",
|
||||
"* Effective date:\n",
|
||||
"* Name:\n",
|
||||
"* Issuer:\n",
|
||||
"* What is CN used for:\n",
|
||||
"* What is OU used for:\n",
|
||||
"* What is O used for:\n",
|
||||
"* What is L used for:\n",
|
||||
"\n",
|
||||
"The public key should be \"30818902 ... 203010001\". We can see this starts with \"30\", and which represents a DER format. We can examine by pasting into this DER analyser [here](https://asecuritysite.com/digitalcert/sigs3). Using this, what do the two values represent, and what type of public key is it?\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### A.2\t\n",
|
||||
"Now open-up the ZIP file for the certificates , and view the CER file.\n",
|
||||
"\n",
|
||||
"* What other information can you gain from the certificate:\n",
|
||||
"* What is the size of the public key:\n",
|
||||
"* Which hashing method has been used:\n",
|
||||
"* Is the certificate trusted on your system: [Yes][No]\n",
|
||||
"\n",
|
||||
"### A.3\t\n",
|
||||
"Make a connection to the www.live.com Web site:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl s_client -connect www.live.com:443\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Can you identity the certificate chain?\n",
|
||||
"\n",
|
||||
"What is the subject on the certificate?\n",
|
||||
"\n",
|
||||
"Who is the issuer on the certificate?\n",
|
||||
"\n",
|
||||
"### A.4\t\n",
|
||||
"\n",
|
||||
"Google moved in July 2018 to mark sites as being insecure if they did not have a match between their digital certificate and the site. First open a browser and see if you can access testfire.net (you can try both https and http for the connection). \n",
|
||||
"\n",
|
||||
"* Run a scan from [SSLLabs](https://www.ssllabs.com/) on testfire.net. What do you observe from the result?\n",
|
||||
"* What is the SSLLabs rating on this site? Is it \"A\", \"B\", \"C\", \"D\", \"E\" or \"F\"?\n",
|
||||
"* What does a “T” rating identify?\n",
|
||||
"* Can you locate another \"T\" rated site?\n",
|
||||
"\n",
|
||||
"### A.5\t\n",
|
||||
"Which the certificates in A.2, for Example 2 to Example 6. Complete the following table:\n",
|
||||
"\n",
|
||||
"|Cert|\tOrganisation (Issued to)|\tDate range when valid|\tSize of public key|\tIssuer|\tRoot CA\tHash method|\tIs it trusted?|\n",
|
||||
"| ----| --- | ---| ---| ---| ---| ---| \n",
|
||||
"| 2 | ||||||\t\t\t\t\t\t\t\n",
|
||||
"|3 | ||||||\t\t\t\t\t\t\t\n",
|
||||
"|4 | ||||||\t\t\t\t\t\t\t\n",
|
||||
"|5 | ||||||\t\t\t\t\t\t\t\n",
|
||||
"|6 | ||||||\t\t\t\t\t\t\t\n",
|
||||
"\n",
|
||||
"### A.6\t\n",
|
||||
"Now download the DER files from:\n",
|
||||
"\n",
|
||||
"Web link (Digital Certificate): http://asecuritysite.com/der.zip\n",
|
||||
"\n",
|
||||
"Now use openssl to read the certificates:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl x509 -inform der -in [certname] -noout -text\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### A.7\n",
|
||||
"Examine the following certificate, and identify its weakness.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"There are two OID numbers related to the public key encryption method and the siganture method. Use this page [here](https://oidref.com/) to identify them.\n",
|
||||
"\n",
|
||||
"## B\tCreating certificates\n",
|
||||
"\n",
|
||||
"Now we will create our own self-signed certificates.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### B.1\t\n",
|
||||
"Create your own certificate from:\n",
|
||||
"\n",
|
||||
"Web link (Create Certificate): [here](http://asecuritysite.com/digitalcert/createcert)\n",
|
||||
"\n",
|
||||
"Add in your own details.\t\n",
|
||||
"\n",
|
||||
"* View the certificate, and verify some of the details on the certificate.\n",
|
||||
"* Can you view the DER file?\n",
|
||||
"\n",
|
||||
"We have a root certificate authority of My Global Corp, which is based in Washington, US, and the administrator is admin@myglobalcorp.com and we are going to issue a certificate to My Little Corp, which is based in Glasgow, UK, and the administrator is admin@mylittlecorp.com.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### B.2\t\n",
|
||||
"Create your RSA key pair with:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl genrsa -out ca.key 2048\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Next create a self-signed root CA certificate ca.crt for My Global Corp:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl req -new -x509 -days 1826 -key ca.key -out ca.crt\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\t\n",
|
||||
"* How many years will the certificate be valid for?\n",
|
||||
"* Which details have you entered:\n",
|
||||
"\n",
|
||||
"### B.3\t\n",
|
||||
"Next go to Places, and from your Home folder, open up ca.crt and view the details of the certificate.\n",
|
||||
"\n",
|
||||
"* Which Key Algorithm has been used:\n",
|
||||
"* Which hashing methods have been used:\n",
|
||||
"* When does the certificate expire:\n",
|
||||
"* Who is it verified by:\n",
|
||||
"* Who has it been issued to:\n",
|
||||
"\n",
|
||||
"### B.4\t\n",
|
||||
"Next we will create a subordinate CA (My Little Corp), and which will be used for the signing of the certificate. First, generate the key:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl genrsa -out ia.key 2048\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Next we will request a certificate for our newly created subordinate CA:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl req -new -key ia.key -out ia.csr\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"We can then create a certificate from the subordinate CA certificate and signed by the root CA.\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl x509 -req -days 730 -in ia.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out ia.crt\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* View the newly created certificate.\n",
|
||||
"* When does it expire:\n",
|
||||
"* Who is the subject of the certificate:\n",
|
||||
"* Which is their country:\n",
|
||||
"* Who signed the certificate:\n",
|
||||
"* Which is their country:\n",
|
||||
"* What is the serial number of the certificate:\n",
|
||||
"* Check the serial number for the root certificate. What is its serial number:\n",
|
||||
"\n",
|
||||
"### B.5\t\n",
|
||||
"If we want to use this certificate to digitally sign files and verify the signatures, we need to convert it to a PKCS12 file:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl pkcs12 -export -out ia.p12 -inkey ia.key -in ia.crt -chain -CAfile ca.crt\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* Can you view ia.p12 in a text edit?\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### B.6\t\n",
|
||||
"The crt format is in encoded in binary. If we want to export to a Base64 format, we can use DER:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl x509 -inform pem -outform pem -in ca.crt -out ca.cer\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"and for My Little Corp:\n",
|
||||
"```\n",
|
||||
"openssl x509 -inform pem -outform pem -in ia.crt -out ia.cer\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* View each of the output files in a text editor (ca.cer and then ia.cer). What can you observe from the format:\n",
|
||||
"* Which are the standard headers and footers on the file used:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### B.7\t\n",
|
||||
"Enter and run the following program, and verify its operation:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import OpenSSL.crypto\n",
|
||||
"from OpenSSL.crypto import load_certificate_request, FILETYPE_PEM\n",
|
||||
"\n",
|
||||
"csr = '''-----BEGIN NEW CERTIFICATE REQUEST-----\n",
|
||||
"MIICyTCCAbECAQAwajELMAkGA1UEBhMCVUsxDTALBgNVBAgTBE5vbmUxEjAQBgNV\n",
|
||||
"BAcTCUVkaW5idXJnaDEXMBUGA1UEChMOTXkgTGl0dGxlIENvcnAxDDAKBgNVBAsT\n",
|
||||
"A01MQzERMA8GA1UEAxMITUxDLm5vbmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n",
|
||||
"ggEKAoIBAQCuQE68qgssJ210wGxfKjCX3PG/RgSb5VpAp2rzavx71M9Bhg9kUORE\n",
|
||||
"OP7BQC3E6DGu+xba3NdnhrHAFNa+hH9dnTZrlxb98aM5q9+TUm76V1toIseOMDdU\n",
|
||||
"UE9IpxXoFvD6b0inbFZnbrjFj3XUUzIIqvvizw4rIOxzgbWqZ5+F7YpP8d59eWW0\n",
|
||||
"6iXzJKoeE/+Gw7Slsdr1+QQAUaX05MHTweMYbZEHir2M8f1RA4o81zEd2tWCK85F\n",
|
||||
"6VS/EkCzUG1cqDBQQ7D2S9MWN8Zk2P7CS8/yZx7uRTmT1t3UWKLUyIN0TU3IjCeY\n",
|
||||
"t53P6C+9DT6UD0fDFZRBCmPOH+qb6/YBAgMBAAGgGjAYBgkqhkiG9w0BCQcxCxMJ\n",
|
||||
"UXdlcnR5MTIzMA0GCSqGSIb3DQEBBQUAA4IBAQCqpXjmaQf2/o/xbNZG5ggAV8yV\n",
|
||||
"d6rSabnov5zIkcit9NQXsPJEi84u7CbcriYqY5h7XlMWjv476mAGbgAVZB2ZhIlp\n",
|
||||
"qLal+lx9xwhFbuLHNRxZcUMM0g9KQZaZTkAQdlDVU/vPzRjq+EHGoPfG7R9QKGD0\n",
|
||||
"k1b4DqOvInWLOs+yuWT7YYtWdr2TNKPpcBqbzCYzrWL6UaUN7LYFpNn4BbqXRgVw\n",
|
||||
"iMAnUh9fvLMe7oreYfTaevXT/506Sj9WvQFXTcLtRhs+M30q22/wUK0ZZ8APjpwf\n",
|
||||
"rQMegvzXXEIO3xEGrBi5/wXJxsawRLcM3ZSGPu/Ws950oM5Ahn8K8HBdKubQ\n",
|
||||
"-----END NEW CERTIFICATE REQUEST-----'''\n",
|
||||
"\n",
|
||||
"req = load_certificate_request(FILETYPE_PEM, csr)\n",
|
||||
"key = req.get_pubkey()\n",
|
||||
"key_type = 'RSA' if key.type() == OpenSSL.crypto.TYPE_RSA else 'DSA'\n",
|
||||
"subject = req.get_subject()\n",
|
||||
"components = dict(subject.get_components())\n",
|
||||
"print (\"Key algorithm:\", key_type)\n",
|
||||
"print (\"Key size:\", key.bits())\n",
|
||||
"print (\"Common name:\", components['CN'])\n",
|
||||
"print (\"Organisation:\", components['O'])\n",
|
||||
"print (\"Organisational unit\", components['OU'])\n",
|
||||
"print (\"City/locality:\", components['L'])\n",
|
||||
"print (\"State/province:\", components['ST'])\n",
|
||||
"print (\"Country:\", components['C'])\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Web link (CSR): [here](https://asecuritysite.com/digitalcert/csr)\n",
|
||||
"\n",
|
||||
"### D.8\t\n",
|
||||
"Now check the signing on these certificate requests:\n",
|
||||
"```\n",
|
||||
"-----BEGIN NEW CERTIFICATE REQUEST-----\n",
|
||||
"MIICyTCCAbECAQAwajELMAkGA1UEBhMCVUsxDTALBgNVBAgTBE5vbmUxEjAQBgNV\n",
|
||||
"BAcTCUVkaW5idXJnaDEXMBUGA1UEChMOTXkgTGl0dGxlIENvcnAxDDAKBgNVBAsT\n",
|
||||
"A01MQzERMA8GA1UEAxMITUxDLm5vbmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n",
|
||||
"ggEKAoIBAQCuQE68qgssJ210wGxfKjCX3PG/RgSb5VpAp2rzavx71M9Bhg9kUORE\n",
|
||||
"OP7BQC3E6DGu+xba3NdnhrHAFNa+hH9dnTZrlxb98aM5q9+TUm76V1toIseOMDdU\n",
|
||||
"UE9IpxXoFvD6b0inbFZnbrjFj3XUUzIIqvvizw4rIOxzgbWqZ5+F7YpP8d59eWW0\n",
|
||||
"6iXzJKoeE/+Gw7Slsdr1+QQAUaX05MHTweMYbZEHir2M8f1RA4o81zEd2tWCK85F\n",
|
||||
"6VS/EkCzUG1cqDBQQ7D2S9MWN8Zk2P7CS8/yZx7uRTmT1t3UWKLUyIN0TU3IjCeY\n",
|
||||
"t53P6C+9DT6UD0fDFZRBCmPOH+qb6/YBAgMBAAGgGjAYBgkqhkiG9w0BCQcxCxMJ\n",
|
||||
"UXdlcnR5MTIzMA0GCSqGSIb3DQEBBQUAA4IBAQCqpXjmaQf2/o/xbNZG5ggAV8yV\n",
|
||||
"d6rSabnov5zIkcit9NQXsPJEi84u7CbcriYqY5h7XlMWjv476mAGbgAVZB2ZhIlp\n",
|
||||
"qLal+lx9xwhFbuLHNRxZcUMM0g9KQZaZTkAQdlDVU/vPzRjq+EHGoPfG7R9QKGD0\n",
|
||||
"k1b4DqOvInWLOs+yuWT7YYtWdr2TNKPpcBqbzCYzrWL6UaUN7LYFpNn4BbqXRgVw\n",
|
||||
"iMAnUh9fvLMe7oreYfTaevXT/506Sj9WvQFXTcLtRhs+M30q22/wUK0ZZ8APjpwf\n",
|
||||
"rQMegvzXXEIO3xEGrBi5/wXJxsawRLcM3ZSGPu/Ws950oM5Ahn8K8HBdKubQ\n",
|
||||
"-----END NEW CERTIFICATE REQUEST-----\n",
|
||||
"```\n",
|
||||
"and:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"-----BEGIN NEW CERTIFICATE REQUEST-----\n",
|
||||
"MIIDPzCCAqgCAQAwZDELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAmJqMQswCQYDVQQH\n",
|
||||
"EwJiajERMA8GA1UEChMIbXhjei5uZXQxETAPBgNVBAsTCG14Y3oubmV0MRUwEwYD\n",
|
||||
"VQQDEwx3d3cubXhjei5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQ7\n",
|
||||
"an4v6pHRusBA0prMWXMWJCXY1AO1H0X8pvZj96T5GWg++JPCQE9guPgGwlD02U0B\n",
|
||||
"NDoEABeD1fwyKZ+JV5UFiOeSjO5sWrzIupdMI7hf34UaPNxHo6r4bLYEykw/Rnmb\n",
|
||||
"GKnNcD4QlPkypE+mLR4p0bnHZhe3lOlNtgd6NpXbAgMBAAGgggGZMBoGCisGAQQB\n",
|
||||
"gjcNAgMxDBYKNS4yLjM3OTAuMjB7BgorBgEEAYI3AgEOMW0wazAOBgNVHQ8BAf8E\n",
|
||||
"BAMCBPAwRAYJKoZIhvcNAQkPBDcwNTAOBggqhkiG9w0DAgICAIAwDgYIKoZIhvcN\n",
|
||||
"AwQCAgCAMAcGBSsOAwIHMAoGCCqGSIb3DQMHMBMGA1UdJQQMMAoGCCsGAQUFBwMB\n",
|
||||
"MIH9BgorBgEEAYI3DQICMYHuMIHrAgEBHloATQBpAGMAcgBvAHMAbwBmAHQAIABS\n",
|
||||
"AFMAQQAgAFMAQwBoAGEAbgBuAGUAbAAgAEMAcgB5AHAAdABvAGcAcgBhAHAAaABp\n",
|
||||
"AGMAIABQAHIAbwB2AGkAZABlAHIDgYkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n",
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n",
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n",
|
||||
"AAAAAAAAAAAAAAAAAAAAADANBgkqhkiG9w0BAQUFAAOBgQBIKHVhHb9FZdVLV4VZ\n",
|
||||
"9DK4aBSuYY//jlIpvsfMIdHXfAsuan7w7PH87asp1wdb6lD9snvLZix1UGK7VQg6\n",
|
||||
"wUFYNlMqJh1m7ITVvzhjdnx7EzCKkBXSxEom4mwbvSNvzqOKAWsDE0gvHQ9aCSby\n",
|
||||
"NFBQQMoW94LqrG/kuIQtjwVdZA==\n",
|
||||
"-----END NEW CERTIFICATE REQUEST-----\n",
|
||||
"```\n",
|
||||
"and:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"-----BEGIN CERTIFICATE REQUEST-----\n",
|
||||
"MIIByjCCATMCAQAwgYkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh\n",
|
||||
"MRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMR8w\n",
|
||||
"HQYDVQQLExZJbmZvcm1hdGlvbiBUZWNobm9sb2d5MRcwFQYDVQQDEw53d3cuZ29v\n",
|
||||
"Z2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApZtYJCHJ4VpVXHfV\n",
|
||||
"IlstQTlO4qC03hjX+ZkPyvdYd1Q4+qbAeTwXmCUKYHThVRd5aXSqlPzyIBwieMZr\n",
|
||||
"WFlRQddZ1IzXAlVRDWwAo60KecqeAXnnUK+5fXoTI/UgWshre8tJ+x/TMHaQKR/J\n",
|
||||
"cIWPhqaQhsJuzZbvAdGA80BLxdMCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBAIhl\n",
|
||||
"4PvFq+e7ipARgI5ZM+GZx6mpCz44DTo0JkwfRDf+BtrsaC0q68eTf2XhYOsq4fkH\n",
|
||||
"Q0uA0aVog3f5iJxCa3Hp5gxbJQ6zV6kJ0TEsuaaOhEko9sdpCoPOnRBm2i/XRD2D\n",
|
||||
"6iNh8f8z0ShGsFqjDgFHyF3o+lUyj+UC6H1QW7bn\n",
|
||||
"-----END CERTIFICATE REQUEST-----\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* What are the details on the requests?\n",
|
||||
"\n",
|
||||
"## C\tElliptic Curve Key Creation\n",
|
||||
"Elliptic curve key pairs are increasing used within corporate Web sites. \n",
|
||||
"\n",
|
||||
"In Openssl we can view the curves with the ecparam option:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl ecparam -list_curves\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* Outline some of the curve names:\n",
|
||||
"* By performing an Internet search, which are the most popular curves (and where are they used)?\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"We can create our elliptic parameter file with:\n",
|
||||
"```\n",
|
||||
"openssl ecparam -name secp256k1 -out secp256k1.pem\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Now view the details with:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl ecparam -in secp256k1.pem -text -param_enc explicit -noout\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* What are the details of the key?\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Now we can create our key pair:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl ecparam -in secp256k1.pem -genkey -noout -out mykey.pem\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Now we will encrypt your key pair (and add a password), and convert it into a format which is ready to be converted into a digital certificate:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl ec -aes-128-cbc -in mykey.pem -out enckey.pem\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Finally we will convert into a DER format, so that we can import the keys into a system:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"openssl ec -in enckey.pem -outform DER -out enckey.der\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* Examine each of the files created and outline what they contain:\n",
|
||||
"* Now pick another elliptic curve type and perform the same operations as above. Which type did you use?\n",
|
||||
"* Outline the commands used:\n",
|
||||
"* If you want to create a non-encrypted version (PFX), which command would you use:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Go to www.cloudflare.com and examine the digital certificate on the site.\n",
|
||||
"\n",
|
||||
"* What is the public key method used?\n",
|
||||
"* What is the size of the public key?\n",
|
||||
"* What is the curve type used?\n",
|
||||
"\n",
|
||||
"## E\tPFX files\n",
|
||||
"We have a root certificate authority of My Global Corp, which is based in Washington, US, and the administrator is admin@myglobalcorp.com and we are going to issue a certificate to My Little Corp, which is based in Glasgow, UK, and the administrator is admin@mylittlecorp.com.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### E.1\tWe will now view some PFX certificate files, and which are protected with a password:\n",
|
||||
"\n",
|
||||
"Web link (Digital Certificates): [here](http://asecuritysite.com/digitalcert/digitalcert2)\n",
|
||||
"\n",
|
||||
"* For Certificate 1, can you open it in the Web browser with an incorrect password:\n",
|
||||
"* Now enter “apples” as a password, and record some of the key details of the certificate:\n",
|
||||
"* Now repeat for Certificate 2:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### E.2\t\n",
|
||||
"Now with the PFX files (contained in the ZIP files from the Web site), try and import them onto your computer. Try to enter an incorrect password first and observe the message.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"* Was the import successful?\n",
|
||||
"* If successful, outline some of the details of the certificates:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## F\tCracking Certificates\n",
|
||||
"Digital certificates are often protected with a simple password. With this we can use a Python program to try various passwords on the certificate, and if it does not create an exception, then we have found the required password. First download the following pfx files:\n",
|
||||
"\n",
|
||||
"[here](https://asecuritysite.com/cert_crack.zip)\n",
|
||||
"\n",
|
||||
"Now for bill01.pfx and fred.pfx, crack the password with the following code:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import OpenSSL \n",
|
||||
"from cryptography import x509\n",
|
||||
"from cryptography.hazmat.backends import default_backend\n",
|
||||
"\n",
|
||||
"str=\"fred.pfx\"\n",
|
||||
"\n",
|
||||
"passwords=[\"ankle\",\"battery\",\"password\",\"bill\",\"apple\",\"apples\",\"orange\"]\n",
|
||||
"\n",
|
||||
"for password in passwords:\n",
|
||||
"\ttry:\n",
|
||||
"\t\tpfx = open(str, 'rb').read()\n",
|
||||
"\t\t\n",
|
||||
"\t\tp12 = OpenSSL.crypto.load_pkcs12(pfx, password.encode())\n",
|
||||
"\t\tprint (\"Found: \",password)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\t\tprivkey=OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey())\n",
|
||||
"\n",
|
||||
"\t\tcert=OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, p12.get_certificate())\n",
|
||||
"\n",
|
||||
"\t\tcert = x509.load_pem_x509_certificate(cert, default_backend())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\t\tprint (\" Issuer: \",cert.issuer)\n",
|
||||
"\t\tprint (\" Subect: \",cert.subject)\n",
|
||||
"\t\tprint (\" Serial number: \",cert.serial_number)\n",
|
||||
"\t\tprint (\" Hash: \",cert.signature_hash_algorithm.name)\n",
|
||||
"\t\tprint (privkey)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\texcept:\n",
|
||||
"\n",
|
||||
"\t\tprint (\"Not working: \",password)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* What is the password?\n",
|
||||
"* The files bill01.pfx, bill02.pfx ... bill18.pfx have a password which are **fruits**. Can you determine the fruits used?\n",
|
||||
"* The files country01.pfx, country02.pfx ... country06.pfx have a password which are **countries** of the world. Can you determine the countries used?\n",
|
||||
"\n",
|
||||
"## G\tSetting up a certificate on a Web site\n",
|
||||
"### G.1\t\n",
|
||||
"Now we will enable HTTPs on an Apache Web Server, and install a digital certificate. Execute the following commands:\n",
|
||||
"```\n",
|
||||
"sudo a2enmod ssl\n",
|
||||
"service apache2 restart\n",
|
||||
"openssl genrsa -out ca.key 2048\n",
|
||||
"sudo openssl req -nodes -new -key ca.key -out ca.csr\n",
|
||||
"sudo openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt\n",
|
||||
"sudo mkdir /etc/apache2/ssl\n",
|
||||
"sudo cp ca.crt ca.key ca.csr /etc/apache2/ssl/\n",
|
||||
"sudo nano /etc/apache2/sites-enabled/000-default.conf\n",
|
||||
"sudo /etc/init.d/apache2 restart\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"HTTPs should now be enabled with a self-signed certificate. If you try https://localhost, you will have to add an exception to view the page, as we are using a self-signed certificate:\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"## Additional lab question\n",
|
||||
"The ECDSA signature is used in Bitcoin and Ethereum. Using the code [here](https://asecuritysite.com/ecdsa/ecdsa3):\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import sys\n",
|
||||
"import random\n",
|
||||
"import hashlib\n",
|
||||
"import libnum\n",
|
||||
"\n",
|
||||
"from secp256k1 import curve,scalar_mult,point_add\n",
|
||||
"\n",
|
||||
"msg=\"Hello\"\n",
|
||||
"\n",
|
||||
"if (len(sys.argv)>1):\n",
|
||||
" msg=(sys.argv[1])\n",
|
||||
"\n",
|
||||
"# Alice's key pair (dA,QA)\n",
|
||||
"dA = random.randint(0, curve.n-1)\n",
|
||||
"QA = scalar_mult(dA,curve.g)\n",
|
||||
"\n",
|
||||
"h=int(hashlib.sha256(msg.encode()).hexdigest(),16)\n",
|
||||
"\n",
|
||||
"k = random.randint(0, curve.n-1)\n",
|
||||
"\n",
|
||||
"rpoint = scalar_mult(k,curve.g)\n",
|
||||
"\n",
|
||||
"r = rpoint[0] % curve.n\n",
|
||||
"\n",
|
||||
"# Bob takes m and (r,s) and checks\n",
|
||||
"inv_k = libnum.invmod(k,curve.n)\n",
|
||||
"\n",
|
||||
"s = (inv_k*(h+r*dA)) % curve.n\n",
|
||||
"\n",
|
||||
"print (f\"Msg: {msg}\\n\\nAlice's private key={dA}\\nAlice's public key={QA}\\nk= {k}\\n\\nr={r}\\ns={s}\")\n",
|
||||
"\n",
|
||||
"# To check signature\n",
|
||||
"\n",
|
||||
"inv_s = libnum.invmod(s,curve.n)\n",
|
||||
"c = inv_s\n",
|
||||
"u1=(h*c) % curve.n\n",
|
||||
"u2=(r*c) % curve.n\n",
|
||||
"P = point_add(scalar_mult(u1,curve.g), scalar_mult(u2,QA))\n",
|
||||
"\n",
|
||||
"res = P[0] % curve.n\n",
|
||||
"print (f\"\\nResult r={res}\")\n",
|
||||
"\n",
|
||||
"if (res==r):\n",
|
||||
"\tprint(\"Signature matches!\")\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Run the code and answer the following questions:\n",
|
||||
"\n",
|
||||
"* How is the private key created?\n",
|
||||
"* How is the public key created?\n",
|
||||
"* Can you identify the nonce value used in the signature?\n",
|
||||
"* What are the two output values of the signature?\n",
|
||||
"* Which key (public or private key) is used to verify the signature?\n",
|
||||
"* Which key (public or private key) is used to verify the signature?\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
485
z_jupyter/11_tunnelling.ipynb
Normal file
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a7782a35",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"# Tunnelling and Web Security\n",
|
||||
"Objective: In this lab we will investigate the usage of SSL/TLS and VPN tunnftels.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"YouTube Demo: https://youtu.be/ASCDJq4Wy9Y \n",
|
||||
"\n",
|
||||
"## A\tWeb cryptography assessment\n",
|
||||
"The Ssllabs tool (https://ssllabs.com) can be used to assess the security of the cryptography used on a Web site. Pick three of your favouriate sites to scan. Now perform a test on them, and determine:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"* What grade does the site get?\n",
|
||||
"* The digital certificate key size and type?\n",
|
||||
"* Does the name of the site match the name on the server?\t\t\t\n",
|
||||
"* Who is the signer of the digital certificate?\n",
|
||||
"* The expiry date on the digital certificate?\n",
|
||||
"* What is the hashing method on the certificate?\n",
|
||||
"* If it uses RSA keys, what is the e value that is used in the encryption (Me mod N)?\t\t\t\n",
|
||||
"* Determine a weak cipher suite used and example why it might be weak?\n",
|
||||
"* Is SSL v2 supported?\n",
|
||||
"* If SSL v2 was supported, what problems might there be with the site (this will require some research)?\t\t\t\n",
|
||||
"* Outline the usage of TLS 1.0/1.1 and 1.2, and identify a problem if one of these TLS versions were not supported?\t\n",
|
||||
"* Is the site vulnerable to Heartbleed?\n",
|
||||
"* Is the site vulnerable to DROWN?\n",
|
||||
"* Is the site vulnerable to BEAST?\n",
|
||||
"* Is the site vulnerable to POODLE?\t\t\t\n",
|
||||
"\n",
|
||||
"Research questions:\n",
|
||||
"\n",
|
||||
"* What does TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 identify?\n",
|
||||
"* If a site gets a ‘T’ grade, what is the problem?\n",
|
||||
"* If the site was susceptible to Poodle, what is the vulnerability?\n",
|
||||
"* Can you find a site which gets an \"A+\"? What features does a site need to get an \"A+\" grade?\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## A.2\t\n",
|
||||
"We will now create a Python program which calls up the SSLlabs assessment. First create a CSV file (sites.csv) with your sites in it. The format is Name of site, URL:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"web,site\n",
|
||||
"Cloudflare,www.cloudflare.com\n",
|
||||
"BBC,bbc.co.uk\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Next enter the following code and run it: \n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import requests\n",
|
||||
"import time\n",
|
||||
"import sys\n",
|
||||
"import logging\n",
|
||||
"\n",
|
||||
"API = 'https://api.ssllabs.com/api/v2/'\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def requestAPI(path, payload={}):\n",
|
||||
" '''This is a helper method that takes the path to the relevant\n",
|
||||
" API call and the user-defined payload and requests the\n",
|
||||
" data/server test from Qualys SSL Labs.\n",
|
||||
" Returns JSON formatted data'''\n",
|
||||
"\n",
|
||||
" url = API + path\n",
|
||||
"\n",
|
||||
" try:\n",
|
||||
" response = requests.get(url, params=payload)\n",
|
||||
" except requests.exception.RequestException:\n",
|
||||
" logging.exception('Request failed.')\n",
|
||||
" sys.exit(1)\n",
|
||||
"\n",
|
||||
" data = response.json()\n",
|
||||
" return data\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def resultsFromCache(host, publish='off', startNew='off', fromCache='on', all='done'):\n",
|
||||
" path = 'analyze'\n",
|
||||
" payload = {\n",
|
||||
" 'host': host,\n",
|
||||
" 'publish': publish,\n",
|
||||
" 'startNew': startNew,\n",
|
||||
" 'fromCache': fromCache,\n",
|
||||
" 'all': all\n",
|
||||
" }\n",
|
||||
" data = requestAPI(path, payload)\n",
|
||||
" return data\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def newScan(host, publish='off', startNew='on', all='done', ignoreMismatch='on'):\n",
|
||||
" path = 'analyze'\n",
|
||||
" payload = {\n",
|
||||
" 'host': host,\n",
|
||||
" 'publish': publish,\n",
|
||||
" 'startNew': startNew,\n",
|
||||
" 'all': all,\n",
|
||||
" 'ignoreMismatch': ignoreMismatch\n",
|
||||
" }\n",
|
||||
" results = requestAPI(path, payload)\n",
|
||||
"\n",
|
||||
" payload.pop('startNew')\n",
|
||||
"\n",
|
||||
" while results['status'] != 'READY' and results['status'] != 'ERROR':\n",
|
||||
" time.sleep(30)\n",
|
||||
" results = requestAPI(path, payload)\n",
|
||||
"\n",
|
||||
" return results\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"import csv\n",
|
||||
"print (\"Scanning\")\n",
|
||||
"with open('sites.csv') as csvfile:\n",
|
||||
" reader = csv.DictReader(csvfile)\n",
|
||||
" for row in reader:\n",
|
||||
" url = row['site'].strip()\n",
|
||||
" print (\"Scanning...\",url)\n",
|
||||
" a = newScan(url)\n",
|
||||
" with open(\"out3.txt\", \"a\") as myfile:\n",
|
||||
" myfile.write(str(row['web'])+\"\\n\"+str(a)+\"\\n\\n\\n\")\n",
|
||||
" print (row['web'])\n",
|
||||
"``` \n",
|
||||
"\n",
|
||||
"Note that it will can take a few minutes to perform a single scan. By reading the out3.txt file, outline your findings.\n",
|
||||
"\n",
|
||||
"Here is the [Replit](https://replit.com/@billbuchanan/ssllab#main.py) site.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Site name:\t\t\t\t\n",
|
||||
"Site rating:\n",
|
||||
"Other significant details:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Site name:\t\t\t\t\n",
|
||||
"Site rating:\n",
|
||||
"Other significant details:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## B\tViewing details\n",
|
||||
"\n",
|
||||
"### B.1\t\n",
|
||||
"On your VM instance (or your desktop), run Wireshark and capture traffic from your main network connection. Start a Web browser and go to:\n",
|
||||
"```\n",
|
||||
"https://google.com\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Stop Wireshark and identify some of your connection details:\n",
|
||||
"\t\n",
|
||||
"* Your IP address and TCP port:\n",
|
||||
"* Google’s Web server IP address and TCP port:\n",
|
||||
"* Which SSL/TLS version is used:\n",
|
||||
"* By examining the Wireshark trace, which encryption method is used for the tunnel (hint: look in the ‘Server Hello’ response):\n",
|
||||
"* By examining the Wireshark trace, which hashing method is used for the tunnel (hint: look in the ‘Server Hello’ response):\n",
|
||||
"* By examining the Wireshark trace, what is the length of the encryption key (hint: look in the ‘Server Hello’ response):\n",
|
||||
"* Using Firefox, and examining the connection details from the site (click on green padlock), can you verify the TLS version, the symmetric key encryption method, the handshaking method and the hashing method used within the tunnel? A sample is shown below.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### B.2\tRun Wireshark and capture traffic from your main network connection. Start a Web browser and go to:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"https://twitter.com\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Stop Wireshark and identify some of your connection details:\n",
|
||||
"\n",
|
||||
"* Your IP address and TCP port:\n",
|
||||
"* Twitter’s Web server IP address and TCP port:\n",
|
||||
"* Which SSL/TLS version is used:\n",
|
||||
"* By examining the Wireshark trace, which encryption method is used for the tunnel (hint: look in the ‘Server Hello’ response):\n",
|
||||
"* By examining the Wireshark trace, which hashing method is used for the tunnel (hint: look in the ‘Server Hello’ response):\n",
|
||||
"* By examining the Wireshark trace, what is the length of the encryption key (hint: look in the ‘Server Hello’ response):\n",
|
||||
"* Using Firefox, and examining the connection details from the site (click on green padlock), can you verify the TLS version, the symmetric key encryption method, the handshaking method and the hashing method used within the tunnel? A sample is shown below.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## C\tOpenSSL\n",
|
||||
"\n",
|
||||
"### C.1\t\n",
|
||||
"On your VM instance (or your desktop), make a connection to the www.live.com Web site:\n",
|
||||
"```\n",
|
||||
"openssl s_client -connect www.live.com:443\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* Which SSL/TLS method has been used:\n",
|
||||
"* Which method is used on the encryption key on the certificate, and what is the size of the public key?\n",
|
||||
"* Which is the handshaking method that has been used to create the encryption key?\n",
|
||||
"* Which TLS version is used for the tunnel?\n",
|
||||
"* Which symmetric encryption method is used for the tunnel:\n",
|
||||
"* Which hashing method is used for the tunnel:\n",
|
||||
"* What is the length of the symmetric encryption key:\n",
|
||||
"* Who has signed the certificate:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## D\tExamining traces\n",
|
||||
"\n",
|
||||
"### D.1\tDownload the following file, and examine the trace with Wireshark:\n",
|
||||
"```\n",
|
||||
"http://asecuritysite.com/log/ssl.zip\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* Client IP address and TCP port:\n",
|
||||
"* Web server IP address and TCP port:\n",
|
||||
"* Determine one of the symmetric key encryption methods, the key exchange, and the hashing methods that the client wants to use (Hint: look at the ‘Client Hello’ packet):\n",
|
||||
"* Which SSL/TLS method has been used:\n",
|
||||
"* Which encryption method is used for the tunnel:\n",
|
||||
"* Which hashing method is used for the tunnel:\n",
|
||||
"* What is the length of the encryption key:\n",
|
||||
"\n",
|
||||
"### D.2\tDownload the following file, and examine the trace with Wireshark:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"http://asecuritysite.com/log/https.zip\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* Client IP address and TCP port:\n",
|
||||
"* Web server IP address and TCP port:\n",
|
||||
"* Determine one of the symmetric key encryption methods, the key exchange, and the hashing methods that the client wants to use (Hint: look at the ‘Client Hello’ packet):\n",
|
||||
"* Which SSL/TLS method has been used:\n",
|
||||
"* Which encryption method is used for the tunnel:\n",
|
||||
"* Which hashing method is used for the tunnel:\n",
|
||||
"* What is the length of the encryption key:\n",
|
||||
"\n",
|
||||
"### D.3\tDownload the following file, and examine the trace with Wireshark:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"http://asecuritysite.com/log/heart.zip\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* Client IP address and TCP port:\n",
|
||||
"* Web server IP address and TCP port:\n",
|
||||
"* Determine one of the symmetric key encryption methods, the key exchange, and the hashing methods that the client wants to use (Hint: look at the ‘Client Hello’ packet):\n",
|
||||
"* Which SSL/TLS method has been used:\n",
|
||||
"* Which encryption method is used for the tunnel:\n",
|
||||
"* Which hashing method is used for the tunnel:\n",
|
||||
"* What is the length of the encryption key:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### D.4\tDownload the following file, and examine the trace with Wireshark:\n",
|
||||
"```\n",
|
||||
"http://asecuritysite.com/log/ipsec.zip \n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* Which is the IP address of the client and of the server:\n",
|
||||
"* Which packet number identifies the start of the VPN connection (Hint: look for UDP Port 500):\n",
|
||||
"* Determine one of the encryption and the hashing methods that the client wants to use:\n",
|
||||
"* Now determine the encryption and hashing methods that are agreed in the ISAKMP:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### D.5\tDownload the following file, and examine the trace with Wireshark:\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"http://asecuritysite.com/log/tor.zip \n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"* Which TCP port does the client use to send to?\n",
|
||||
"* What is the IP address of the Tor node that the client connects to?\n",
|
||||
"* What is strange about the packet size?\n",
|
||||
"* Is SSL/TLS used for the connection?\n",
|
||||
"* Can you trace any content in the conversation?\n",
|
||||
"* Can you determine the Web site that is being connected to?\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## E\tTLS Connection\n",
|
||||
"### E.1\t\n",
|
||||
"We will now create our own SSL/TLS server and client in Python. First, we need to generate a certificate for our server:\n",
|
||||
"```\n",
|
||||
"openssl req -new -x509 -days 365 -nodes -out mycert.pem -keyout mycert.pem\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Next we will create a server which will listen on Port 444 (as 443 is likely to be used already for HTTPs), and support two cipher suites ('AES256+ECDH:AES256+EDH'):\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import socket, ssl\n",
|
||||
"\n",
|
||||
"context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)\n",
|
||||
"context.load_cert_chain(certfile=\"mycert.pem\") \n",
|
||||
"\n",
|
||||
"def handle(conn):\n",
|
||||
" conn.write(b'GET / HTTP/1.1\\n')\n",
|
||||
" print(conn.recv().decode())\n",
|
||||
"\n",
|
||||
"while True:\n",
|
||||
" sock = socket.socket()\n",
|
||||
" sock.bind(('', 444))\n",
|
||||
" sock.listen(5)\n",
|
||||
" context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n",
|
||||
" context.load_cert_chain(certfile=\"mycert.pem\") \n",
|
||||
" context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 # optional\n",
|
||||
" context.set_ciphers('AES256+ECDH:AES256+EDH')\n",
|
||||
" while True:\n",
|
||||
" conn = None\n",
|
||||
" ssock, addr = sock.accept()\n",
|
||||
" try:\n",
|
||||
" conn = context.wrap_socket(ssock, server_side=True)\n",
|
||||
" handle(conn)\n",
|
||||
" except ssl.SSLError as e:\n",
|
||||
" print(e)\n",
|
||||
" finally:\n",
|
||||
" if conn:\n",
|
||||
" conn.close()\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Now we will create the client to connect on Port 444. As we have a self-signed certificate, we will disable the checking of the host and certificate (remember to change the IP address to the address of your local host):\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import socket, ssl\n",
|
||||
"\n",
|
||||
"HOST, PORT = '10.10.10.10', 444\n",
|
||||
"\n",
|
||||
"def handle(conn):\n",
|
||||
" conn.write(b'GET / HTTP/1.1\\n')\n",
|
||||
" print(conn.recv().decode())\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
"\n",
|
||||
" sock = socket.socket(socket.AF_INET)\n",
|
||||
"\n",
|
||||
" context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)\n",
|
||||
" context.check_hostname = False\n",
|
||||
" context.verify_mode=ssl.CERT_NONE\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 \n",
|
||||
"\n",
|
||||
" conn = context.wrap_socket(sock, server_hostname=HOST)\n",
|
||||
"\n",
|
||||
" try:\n",
|
||||
" conn.connect((HOST, PORT))\n",
|
||||
" handle(conn)\n",
|
||||
" finally:\n",
|
||||
" conn.close()\n",
|
||||
"\n",
|
||||
"if __name__ == '__main__':\n",
|
||||
" main()\n",
|
||||
"```\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"Now run Wireshark (sudo wireshark &), and capture from the Ethernet port (a sample run is show in in Figure 1). Now run the server, and then run the client. Stop Wireshark and determine:\n",
|
||||
"\t\n",
|
||||
"* The cipher suites sent from client to the server (‘Client Hello’): \n",
|
||||
"* The cipher suite selected by the server (‘Server Hello’):\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"If we change the code to:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"context.set_ciphers(‘HIGH’)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"What are the cipher suites sent from server, and which cipher suite is selected by the client:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"Figure 1: Sample capture\n",
|
||||
"\n",
|
||||
"Now select your own cipher suits to accept. The possible settings are given next. You can use the “+” (to add), “-“ (to take away), and “!” (for not).\n",
|
||||
"\n",
|
||||
"Key exchange:\n",
|
||||
"\n",
|
||||
"* kRSA, aRSA, RSA. RSA Key exchange.\n",
|
||||
"* kDHE, kEDH, DH. Ephemeral DH key agreement.\n",
|
||||
"* DHE, EDH. Cipher suites using authenticated ephemeral DH key agreement.\n",
|
||||
"* kEECDH, kECDHE, ECDH. Cipher suites using ephemeral ECDH key agreement.\n",
|
||||
"* ECDHE, EECDH. Cipher suites using authenticated ephemeral ECDH key agreement.\n",
|
||||
"* aECDSA, ECDSA. Cipher suites with ECDSA authentication.\n",
|
||||
"\n",
|
||||
"Encryption:\n",
|
||||
"\n",
|
||||
"* AES128, AES256, AES, AESGCM, AESCCM, AESCCM8.\n",
|
||||
"* ARIA128, ARIA256, ARIA.\n",
|
||||
"* CAMELLIA128, CAMELLIA256, CAMELLIA.\n",
|
||||
"* CHACHA20.\n",
|
||||
"* 3DES, DES, RC4, RC2, IDEA.\n",
|
||||
"\n",
|
||||
"Hashing methods:\n",
|
||||
"\n",
|
||||
"•\tMD5, SHA1, SHA. SHA256, SHA384\n",
|
||||
"•\taGOST, kGOST, GOST94, GOST89MAC.\n",
|
||||
"\n",
|
||||
"We can also use: HIGH (256-bit); MEDIUM (128-bit); LOW (56-bit or 64-bit).\n",
|
||||
"\n",
|
||||
"## G\tSecure services\n",
|
||||
"### G.1\t\n",
|
||||
"On your VM, determine your IP address with ipconfig, and then using nmap, show the running servers on the server:\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"ifconfig\n",
|
||||
"nmap [ip]\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"What are the servers that are running:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Open a Web browser on your server, and open up the home page with:\n",
|
||||
"<pre>\n",
|
||||
"https://[ip]\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"What is contained on the home page:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### G.2\t\n",
|
||||
"Now to the /var/www/html folder and show that there is a file named index.html. Connect to the sftp service by determining your IP address (<ip>) and use the command:\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"sftp sftpuser@[ip]\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"With this we run the normal FTP service, but integrate with the SSH service (and which runs on Port 22). Now run the following commands, and determine the output:\n",
|
||||
"\n",
|
||||
"<pre>\n",
|
||||
"pwd\n",
|
||||
"ls\n",
|
||||
"cd napier\n",
|
||||
"put index.html\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"### G.3\t\n",
|
||||
"Now exit from sftp and try and locate the file you have copied. Go back to sftp, and now see if you can copy a file to the /home/napier folder.\n",
|
||||
"\n",
|
||||
"Now start wireshark (with sudo wireshark &), and capture your session. Now login into your local host with the ssh server:\n",
|
||||
"<pre>\n",
|
||||
"ssh napier@localhost\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"What observations can you make on the creation of the secure connection:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### G.4\t\n",
|
||||
"Now, let’s repeat the lab question from last week. Let’s enable HTTPs:\n",
|
||||
"<pre>\n",
|
||||
"sudo a2enmod ssl\n",
|
||||
"service apache2 restart\n",
|
||||
"openssl genrsa -out ca.key 2048\n",
|
||||
"sudo openssl req -nodes -new -key ca.key -out ca.csr\n",
|
||||
"sudo openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt\n",
|
||||
"sudo mkdir /etc/apache2/ssl\n",
|
||||
"sudo cp ca.crt ca.key ca.csr /etc/apache2/ssl/\n",
|
||||
"sudo nano /etc/apache2/sites-enabled/000-default.conf\n",
|
||||
"sudo /etc/init.d/apache2 restart\n",
|
||||
"</pre>\n",
|
||||
"\n",
|
||||
"HTTPs should now be enabled with a self-signed certificate. If you try https://localhost, you will have to add an exception to view the page, as we are using a self-signed certificate:"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
BIN
z_jupyter/graphics/Thumbs.db
Normal file
BIN
z_jupyter/graphics/bc.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
BIN
z_jupyter/graphics/ecc3.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
z_jupyter/graphics/ecdh.png
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
z_jupyter/graphics/g_aws_01.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
z_jupyter/graphics/g_aws_02.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
z_jupyter/graphics/g_aws_03.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
z_jupyter/graphics/g_aws_04.png
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
z_jupyter/graphics/g_aws_05.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
z_jupyter/graphics/g_aws_06.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
z_jupyter/graphics/g_aws_07.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
z_jupyter/graphics/g_aws_08.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
z_jupyter/graphics/g_aws_09.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
z_jupyter/graphics/g_aws_10.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
z_jupyter/graphics/g_aws_11.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
z_jupyter/graphics/g_aws_11_2.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
z_jupyter/graphics/g_aws_12.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
z_jupyter/graphics/g_aws_12_2.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
z_jupyter/graphics/g_block_01.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
z_jupyter/graphics/g_block_02.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
z_jupyter/graphics/g_block_03.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
z_jupyter/graphics/g_block_04.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
z_jupyter/graphics/g_block_05.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
z_jupyter/graphics/g_cert_01.png
Normal file
|
After Width: | Height: | Size: 282 KiB |
BIN
z_jupyter/graphics/g_cert_02.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
z_jupyter/graphics/g_cert_03.png
Normal file
|
After Width: | Height: | Size: 286 KiB |
BIN
z_jupyter/graphics/g_cyan_01.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
z_jupyter/graphics/g_dig_pound_01.png
Normal file
|
After Width: | Height: | Size: 120 KiB |
BIN
z_jupyter/graphics/g_dig_pound_02.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
z_jupyter/graphics/g_dig_pound_03.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
z_jupyter/graphics/g_dig_pound_04.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
z_jupyter/graphics/g_dig_pound_05.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
z_jupyter/graphics/g_dig_pound_06.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
z_jupyter/graphics/g_dig_pound_07.png
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
z_jupyter/graphics/g_dig_pound_08.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
z_jupyter/graphics/g_dig_pound_09.png
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
z_jupyter/graphics/g_dig_pound_10.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
z_jupyter/graphics/g_dig_pound_11.png
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
z_jupyter/graphics/g_distsig_01.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
z_jupyter/graphics/g_distsig_04.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
z_jupyter/graphics/g_distsig_05.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
z_jupyter/graphics/g_distsig_06.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
z_jupyter/graphics/g_distsig_07.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
z_jupyter/graphics/g_distsig_08.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
z_jupyter/graphics/g_distsig_10.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
z_jupyter/graphics/g_distsig_11.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
z_jupyter/graphics/g_distsig_12.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
z_jupyter/graphics/g_distsig_13.png
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
z_jupyter/graphics/g_distsig_14.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
z_jupyter/graphics/g_distsig_14_02.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
z_jupyter/graphics/g_distsig_15.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
z_jupyter/graphics/g_distsig_16.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
z_jupyter/graphics/g_distsig_17.png
Normal file
|
After Width: | Height: | Size: 113 KiB |
BIN
z_jupyter/graphics/g_dsa_01.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
z_jupyter/graphics/g_dsa_02.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
z_jupyter/graphics/g_elgamal_01.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
z_jupyter/graphics/g_elgamal_02.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
z_jupyter/graphics/g_fun01.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
z_jupyter/graphics/g_fun02.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
z_jupyter/graphics/g_fun03.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
z_jupyter/graphics/g_fun04.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
z_jupyter/graphics/g_fun05.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
z_jupyter/graphics/g_fun06.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
z_jupyter/graphics/g_glass_01.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
z_jupyter/graphics/g_glass_02.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
z_jupyter/graphics/g_glass_03.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
z_jupyter/graphics/g_hash_01.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
z_jupyter/graphics/g_hash_02.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
z_jupyter/graphics/g_hash_03.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
z_jupyter/graphics/g_hash_04.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
z_jupyter/graphics/g_hash_05.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
z_jupyter/graphics/g_hash_06.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
z_jupyter/graphics/g_hash_07.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
z_jupyter/graphics/g_hash_08.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
z_jupyter/graphics/g_hom_01.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
z_jupyter/graphics/g_hom_02.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
z_jupyter/graphics/g_hom_03.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
z_jupyter/graphics/g_hom_04.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
z_jupyter/graphics/g_hom_04_02.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
z_jupyter/graphics/g_hom_05.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
z_jupyter/graphics/g_hom_06.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
z_jupyter/graphics/g_hom_07.png
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
z_jupyter/graphics/g_hom_08.png
Normal file
|
After Width: | Height: | Size: 62 KiB |