From 55ddaafdc7465342ef785cdaeb184e123e985722 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Mon, 4 Sep 2023 23:09:52 +0200 Subject: [PATCH] perfection of first tasks --- Tasks.md | 207 ++++++++++++++++++++++++++++++++++------------ src/md5.py | 3 +- src/md5range-4.py | 19 +++++ src/miniweb.py | 6 +- 4 files changed, 178 insertions(+), 57 deletions(-) create mode 100755 src/md5range-4.py diff --git a/Tasks.md b/Tasks.md index 70ec322..8580e74 100644 --- a/Tasks.md +++ b/Tasks.md @@ -1,57 +1,162 @@ # Tasks for beginners This document contains some tasks for Python beginners. It does not aim to teach general -programming techniques, only how to use Python. +programming techniques, only how to use Python. I try to avoid unrealistic tasks. ## MD5 Hashchecker -- [ ] Hash `foobar19` with the md5 hashing algorithm - - Hints: - - Use Pythons `hashlib`. - - Your hashing function does not take strings for input, only raw data (bytes). - - You need to explicitly tell your hash to actually process the input. - - When printing your results, the result may be interpreted as data for characters. - You want the numeric value of the result in Hexadecimal. -
- Solution - MD5 of `foobar19` is `fa5c65d5438f849387d3fdda2be4dd65` -
-- [ ] 1. rotate the base string `foobar` with numbers from 0 to 999999 like this: - 1. `foobar000000` - 2. `foobar000001` - 3. `foobar000002` - ... - 999999. `foobar999999` - 2. Get the MD5 hash value for each of those - 3. How many of these start with `00`? - - Hints: - - Use a for loop to do the thing X times - - Use Pythons string formatting to put the numbers and string together - - Use Options for the `%d` Placeholder to get 0 to be displayed as `000000` - - do the same hashing as in the previous task - - After hashing, check if your current hash matches the search. - Print it if that is the case to see if the match is a false positive. - - Increment a number on each match. The value of that number after the loop is how many - Hashes start with `00` for this task. - - Testvectors, the last 5 matches: - ```text - 999384 | 009671fd23fa783df1fff63516e5d115 - 999751 | 00ec2ade58f75c44b7300294497f7fb1 - 999844 | 009cfd7949b577a3311d9db3ee49c15d - 999852 | 006fe04f7d3f710f93d3e6324506154a - 999902 | 00c063364ddffa1bdf338dfcf0319424 - ``` -
- Solution - 3889 matches for the search parameters. -
-- [ ] Continuing from the previous task, what is the earliest value for `foobarXXXXXX` (where `X` - is a substitute for the iterating numbers) where the hash starts with `0000`? - - Hints: - - Stop on the earliest match. -
- Solution - 021820 | 00001c9393b83c8da0db478687211d1d -
-## Super basic webserver -- [ ] Make a webserver print "Schlangenjazz" when you connect to it +### Produce a single MD5 Hash + +Difficulty: 1/5 + +1. Hash the string `foobar19` with the MD5 hashing algorithm. + +
+Hints + +- Use Pythons `hashlib`. +- Your hashing function does not take strings for input, only raw data (bytes). +- You need to explicitly tell your hash to actually process the input. +- When printing your results, the result may be interpreted as data for characters. + You want the numeric value of the result in Hexadecimal. + +
+
+Solution + +The MD5 hash of `foobar19` is `fa5c65d5438f849387d3fdda2be4dd65`. + +[Example Code](src/md5.py) + +
+ +### Hash multiple values and search for specific ones. + +Difficulty: 2/5 + +1. Find a way to produce strings with the basis `foobar` with appended numbers from `000000` to +`999999`. + +```text +1. `foobar000000` +2. `foobar000001` +3. `foobar000002` + ... +999998. `foobar999998` +999999. `foobar999999` +``` + +2. Hash all these with the MD5 hashing algorithm. +3. Find the exact numbers, how many of these hashes start with `00` +4. **Bonus**: + 1. If MD5 was a good / perfect Hashing algorithm (it is definitely not), + how many matches for a `00` prefix should exist? Why? + 2. How many matches for $0$ to $50000$? How many matches for $0$ to $50.000.000$? + +
+Testvectors + +Last 5 Matches + +```text +999384 | 009671fd23fa783df1fff63516e5d115 +999751 | 00ec2ade58f75c44b7300294497f7fb1 +999844 | 009cfd7949b577a3311d9db3ee49c15d +999852 | 006fe04f7d3f710f93d3e6324506154a +999902 | 00c063364ddffa1bdf338dfcf0319424 +``` + +
+
+Hints + +- Use a for loop to do the thing X times +- Use Pythons string formatting to put the numbers and string together +- Use Options for the `%d` Placeholder to get $0$ to be displayed as `000000` +- After hashing, check if your current hash matches the search. + Print it if that is the case to see if the match is a false positive. +- Increment a number on each match. The value of that number after the loop is how many + Hashes start with `00` for this task. + +
+
+Solution + +There are 3889 hashes for `foobar000000` to `foobar999999` that start with `00`. + +[Code Example](src/md5range.py) + +**Bonus** +We want $N/16^2$ occurrences for an ideal hashing algorithm, where $N$ is the maximum of our range +$+ 1$. + +$16^2$ comes from $2$ characters in a range of `0` to `e` (Hexadecimal). + +We want the hashing algorithm to spread out as much as possible, no value should be more common +than any other value. This is essential for the security of the hashing algorithm. + +| Value | Ideal Occurences | +|--------------|------------------| +| $1.000.000$ | $\approx 3906$ | +| $500.000$ | $\approx 1953$ | +| $50.000.000$ | $\approx 195312$ | + +
+ +### Find earliest hash that fits criteria + +Difficulty: 2/5 + +1. Find the earliest integer $X$ for `foobarXXXXXX` (where $X$ is an iterator as in the last +subtask) that starts with `2718`. + +
+Hints + +- You can reuse most code from the last subtask. +- Match against the new prefix, but stop when you find it. +- Display the index number in each loop iteration. + +
+
+Solution + +The first hash with prefix `2718` occurs at $i=70559$. + +```text +070559 | 2718e5ee6d05091ce6dad023e55ee19c +``` + +[Code Example](src/md5range-4.py) + +
+ +## Super basic web server + +Difficulty: 2/5 + +1. Program a Python web server that writes "Python is not so hard" in your Browser (or in `cURL`). + Use `http.server`. + +
+Hints + +- Use `http.server.SimpleHTTPRequestHandler` and `io.BytesIO`. +- Define your own class that inherits `SimpleHTTPRequestHandler`. +- You don't need to implement `do_GET()`. +- Implement your own `send_head()` method. This is the method that writes your response (not + completely on it's own, but unless you feel like inspecting standard libraries, just do what + I'm saying.). +- `send_head()` should take no arguments (other than `self`) and return some readable buffer. +- Don't forget to set the headers for HTTP before sending the body. +- Your OS might block hosting to ports < 1000. Try to host your web server to `localhost:8080`. + +
+
+Solution + +Take a look at the provided Code Example. + +[Code Example](src/miniweb.py) + +
diff --git a/src/md5.py b/src/md5.py index 9933b50..83950ba 100755 --- a/src/md5.py +++ b/src/md5.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import hashlib import sys -hashed = hashlib.md5(sys.argv[1].encode()) +to_hash = "foobar19" +hashed = hashlib.md5(to_hash.encode()) print(hashed.digest().hex()) diff --git a/src/md5range-4.py b/src/md5range-4.py new file mode 100755 index 0000000..d00438d --- /dev/null +++ b/src/md5range-4.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +import hashlib +BASE: str = "foobar" +MAX = 1000000 +SEARCH = "2718" + +count = 0 + +for i in range(0, MAX): + num: str = ("%06d" % i) + current = BASE + num + res = hashlib.md5(current.encode()).digest().hex() + if SEARCH == res[:4]: + count += 1 + print("%06d | %s" % (i, res)) + break + + +print(f"\nFound %d digests matching the search" % count) diff --git a/src/miniweb.py b/src/miniweb.py index fa5e2a7..223a3dc 100755 --- a/src/miniweb.py +++ b/src/miniweb.py @@ -2,10 +2,7 @@ import http.server import io -TEXT = """Hello world! - -If you're reading this, this web server is working! -""" +TEXT = "Python is not so hard" class MyHandler(http.server.SimpleHTTPRequestHandler): def send_head(self) -> io.BytesIO: @@ -20,4 +17,3 @@ class MyHandler(http.server.SimpleHTTPRequestHandler): addtrss = ("127.0.0.1", 8080) srv = http.server.HTTPServer(addtrss, MyHandler) srv.serve_forever() -