Compare commits
40 Commits
curses-sto
...
master
Author | SHA1 | Date |
---|---|---|
Christoph J. Scherr | f79b8b5d4d | |
Christoph J. Scherr | 4241cf5260 | |
Christoph J. Scherr | 564b0cd011 | |
Christoph J. Scherr | 95866bca81 | |
Christoph J. Scherr | a80c723a32 | |
Christoph J. Scherr | 3465c56c2e | |
Christoph J. Scherr | f12c1141eb | |
Christoph J. Scherr | 2e39e89f37 | |
Christoph J. Scherr | 502851d027 | |
Christoph J. Scherr | bc159a2d24 | |
Christoph J. Scherr | bf9a01d7ba | |
Christoph J. Scherr | 61dbf7a500 | |
Christoph J. Scherr | 778abfa7cc | |
Christoph J. Scherr | 8e31d1063f | |
Christoph J. Scherr | 883e9c94ec | |
Christoph J. Scherr | e296d8f97d | |
Christoph J. Scherr | afade771fa | |
Christoph J. Scherr | 06194f0903 | |
Christoph J. Scherr | 7d1c18101a | |
Christoph J. Scherr | 2e23190dfe | |
Christoph J. Scherr | 07f2a5d728 | |
Christoph J. Scherr | 0a7021255c | |
Christoph J. Scherr | d7dbefc851 | |
Christoph J. Scherr | 90535e3237 | |
Christoph J. Scherr | 25ddac10df | |
Christoph J. Scherr | 7f7cd3677d | |
Christoph J. Scherr | 0a8f6e5b53 | |
Christoph J. Scherr | 5ce6e095bc | |
Christoph J. Scherr | 55ddaafdc7 | |
Christoph J. Scherr | f0ec2e26ce | |
Christoph J. Scherr | 3106a55d8e | |
Christoph J. Scherr | 2297220759 | |
Christoph J. Scherr | fa615d8321 | |
Christoph J. Scherr | ecfc98be04 | |
Christoph J. Scherr | 426c456e1c | |
Christoph J. Scherr | 2d4141937a | |
Christoph J. Scherr | d3483e229e | |
Christoph J. Scherr | 207673382f | |
Christoph J. Scherr | 2c7f6fc759 | |
Christoph J. Scherr | 7c437fb759 |
4
TODO.md
4
TODO.md
|
@ -1,4 +0,0 @@
|
|||
# Things i would like to add to this repository
|
||||
Caesar-encryption, decryption, brute force
|
||||
calculate determinante (german, idk the english word) of a matrix
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
This is a list of tasks that would be cool to add.
|
||||
|
||||
* Tasks
|
||||
** Basic
|
||||
*** Files
|
||||
- (-) Hex dumper
|
||||
- (x) Dump basic files with format
|
||||
- (x) Dump basic files with chars
|
||||
- (x) Be able to dump larger files or put out an error
|
||||
- (x) Stop reading when read gets blocked /somehow/
|
||||
Simple syscall
|
||||
- (x) Wait for new input when the file is lazy
|
||||
- (x) Install script to system
|
||||
Using update-alternatives is the most handy
|
||||
- (x) Accept input from stdin when no file is given
|
||||
- (x) Print error when no file and stdin is given
|
||||
- ( ) Process only first N or last N Bytes
|
||||
- ( ) Write a complete task for this stuff
|
||||
*** Networking
|
||||
- ( ) Mini curl
|
||||
*** Packaging
|
||||
- ( ) Installing a package to your system
|
||||
- ( ) Building a library
|
||||
|
||||
** Cryptography
|
||||
*** Signature
|
||||
- ( ) Check a signature with OpenSSL
|
|
@ -0,0 +1,489 @@
|
|||
# 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. I try to avoid unrealistic tasks.
|
||||
|
||||
In case you have somehow gotten this document from another source,
|
||||
[this](https://git.cscherr.de/PlexSheep/py-basic/src/branch/master/Tasks.md) is the original
|
||||
source, where the links should hopefully work. If something does not work feel free to contact
|
||||
me at [software@cscherr.de](mailto:admin@cscherr.de).
|
||||
|
||||
## MD5 Hashchecker
|
||||
|
||||
### A. Produce a single MD5 Hash
|
||||
|
||||
Difficulty: 1/5
|
||||
|
||||
1. Hash the string `foobar19` with the MD5 hashing algorithm.
|
||||
|
||||
<details>
|
||||
<summary>Hints</summary>
|
||||
|
||||
- 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.
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Solution</summary>
|
||||
|
||||
The MD5 hash of `foobar19` is `fa5c65d5438f849387d3fdda2be4dd65`.
|
||||
|
||||
[Example Code](src/md5.py)
|
||||
|
||||
</details>
|
||||
|
||||
### B. 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$?
|
||||
|
||||
<details>
|
||||
<summary>Testvectors</summary>
|
||||
|
||||
Last 5 Matches
|
||||
|
||||
```text
|
||||
999384 | 009671fd23fa783df1fff63516e5d115
|
||||
999751 | 00ec2ade58f75c44b7300294497f7fb1
|
||||
999844 | 009cfd7949b577a3311d9db3ee49c15d
|
||||
999852 | 006fe04f7d3f710f93d3e6324506154a
|
||||
999902 | 00c063364ddffa1bdf338dfcf0319424
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Hints</summary>
|
||||
|
||||
- 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.
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Solution</summary>
|
||||
|
||||
There are 3889 hashes for `foobar000000` to `foobar999999` that produce an MD5 Hash that starts
|
||||
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$ |
|
||||
|
||||
</details>
|
||||
|
||||
### C. 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 produces an MD5 hash that starts with `2718`.
|
||||
|
||||
<details>
|
||||
<summary>Hints</summary>
|
||||
|
||||
- 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.
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Solution</summary>
|
||||
|
||||
The first hash with prefix `2718` occurs at $i=70559$.
|
||||
|
||||
```text
|
||||
070559 | 2718e5ee6d05091ce6dad023e55ee19c
|
||||
```
|
||||
|
||||
[Code Example](src/md5range-4.py)
|
||||
|
||||
</details>
|
||||
|
||||
## Super basic web server
|
||||
|
||||
Difficulty: 3/5
|
||||
|
||||
1. Program a Python web server that writes "Python is not so hard" in your Browser (or in `cURL`).
|
||||
Use `http.server`.
|
||||
|
||||
<details>
|
||||
<summary>Hints</summary>
|
||||
|
||||
- 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`.
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Solution</summary>
|
||||
|
||||
Take a look at the provided Code Example.
|
||||
|
||||
[Code Example](src/miniweb.py)
|
||||
|
||||
</details>
|
||||
|
||||
## Random Password generator
|
||||
|
||||
Difficulty: 2/5
|
||||
|
||||
1. Generate a string of 16 random alphanumeric characters.
|
||||
2. When starting your script, take a number for a CLI Argument. Generate a random string of this
|
||||
length.
|
||||
3. **Bonus**
|
||||
- How many possible strings consisting of 16 alphanumeric characters can exist?
|
||||
- Add the possibility for a second argument `-v` that indicates your script should be more
|
||||
verbose.
|
||||
- print the security bits ($log_2(L)$ where $L$ is the total number of possibilities) when the
|
||||
`-v` flag is applied
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
$ python ./randomString.py 60
|
||||
n51uxDLu3BnxZ1D00gYKYRcG2jh1Y6uulHgrJ0TK3w5FtWl6wm8U0azNtxw0
|
||||
# ^^^^ the above is 60 characters ^^^^
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Hints</summary>
|
||||
|
||||
- Use `random.choice` to generate a random character
|
||||
- build your own alphabet string
|
||||
- Use `sys.argv` to access the CLI Arguments
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Solution</summary>
|
||||
|
||||
Take a look at the provided Code Example.
|
||||
|
||||
[Code Example](src/randomString.py)
|
||||
|
||||
**Bonus**
|
||||
|
||||
There are 62 alphanumeric characters (A-Z), (a-z), (0-9).
|
||||
|
||||
With $N$ characters, there are $62^N$ possible variants.
|
||||
For $N=16$ that's $62^{16} = 47.672.401.706.823.533.450.263.330.816$ possible variants.
|
||||
|
||||
Security people measure security in Bits ($2^x$). You can calculate the bits of security with the
|
||||
logarithm base 2.
|
||||
|
||||
$S = log_2(62^N)$.
|
||||
|
||||
We can immediately see that longer passwords are *exponentially* more secure than
|
||||
more complex passwords (passwords that make use of complicated characters). For each bit, the
|
||||
security of the password is doubled.
|
||||
|
||||
For our example of $N=16$ we can calculate the security of the password like this:
|
||||
|
||||
$S=log_2(62^{16}) \approx 95.27$
|
||||
|
||||
That number of security bits is pretty good for passwords. However it does not cost you anything to
|
||||
just make your passwords longer than that, and give attackers no chance to break them by brute
|
||||
force.
|
||||
|
||||
</details>
|
||||
|
||||
## String Parsing with Regular Expressions
|
||||
|
||||
Difficulty: 2/5
|
||||
|
||||
<details>
|
||||
<summary>Text</summary>
|
||||
|
||||
The text is large, read it [here](data/metasyntactic.md) and find the raw text for your program
|
||||
[here](https://git.cscherr.de/PlexSheep/py-basic/raw/branch/master/data/metasyntactic.md).
|
||||
|
||||
</details>
|
||||
|
||||
1. Use a regular expression (regex) to find all words that start with a lowercase character with a
|
||||
following vowel character, in which no 'x', z' or 'y' follows the vowel in the given Text.
|
||||
It is not allowed to store the text in source code, you must load it from an outside source,
|
||||
such as a file.
|
||||
|
||||
Examples:
|
||||
|
||||
| Original | is Match? |
|
||||
|----------|-----------|
|
||||
| foo | yes |
|
||||
| foobar | yes |
|
||||
| tayfoo | no |
|
||||
| baz | no |
|
||||
| qux | no |
|
||||
| Foo | no |
|
||||
| bAR | yes |
|
||||
| far | yes |
|
||||
|
||||
A hint that you don't want to miss:
|
||||
|
||||
Use [regex101.com](https://regex101.com) if you are not already a REGEX expert.
|
||||
|
||||
<details>
|
||||
<summary>Hints</summary>
|
||||
|
||||
- use `open()` to open your file for reading.
|
||||
- use the `read()` method to read the file out.
|
||||
- Use the `re` library
|
||||
- Use `\b` to match a word boundary
|
||||
- Use ranges `[5-9]`
|
||||
- You can set a higher precedence by putting things in braces `(ABC)`.
|
||||
- You can connect two expressions with `A|B` to use either `A` or `B`
|
||||
- Use global mode.
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Solution</summary>
|
||||
|
||||
There should be $374$ matches.
|
||||
|
||||
A regex that matches the requirements is `\b[a-z][AEIOUaeiou]([a-w]|[A-W])`.
|
||||
|
||||
[Code Example](src/tasks/regex.py)
|
||||
|
||||
</details>
|
||||
|
||||
## Primitive Cryptography
|
||||
|
||||
This section covers some ancient and / or primitive methods of Cryptography.
|
||||
These are relatively easy to code and give a basic understanding of used
|
||||
concepts.
|
||||
|
||||
### A. The Caesar Cipher
|
||||
|
||||
Difficulty: 2/5
|
||||
|
||||
<details>
|
||||
<summary>Text</summary>
|
||||
|
||||
```text
|
||||
Gxhobf bl t kxytvmhk, tgw lhfxmbfxl kxwtvmhk, bg max mktwbmbhg hy Obf (pabva bmlxey wxkboxl ykhf
|
||||
Lmxobx). Bm bl ghm t kxpkbmx unm t vhgmbgntmbhg tgw xqmxglbhg hy Obf. Ftgr vehgxl tgw wxkbotmboxl
|
||||
xqblm, lhfx oxkr vexoxk—unm ghgx tkx Obf. Gxhobf bl unbem yhk nlxkl pah ptgm max zhhw itkml hy
|
||||
Obf, tgw fhkx.
|
||||
````
|
||||
|
||||
</details>
|
||||
|
||||
1. The text above has been cyphered with the Caesar cipher, a timeless,
|
||||
classical algorithm that abstracts the meaning of text away and arguably
|
||||
an early form of encryption. Your task is to decipher it back into readable
|
||||
text.
|
||||
2. **Bonus**
|
||||
- What if you didn't just try all possible combinations? How could you find
|
||||
the key without trying until you find it?
|
||||
|
||||
**The cipher**
|
||||
|
||||
For the Caesar cipher, all letters are shifted by the value of the key.
|
||||
|
||||
**Examples**
|
||||
|
||||
`foo Bar` becomes `gpp Cbs` when shifted by $1$.
|
||||
|
||||
Try to find out the rest for yourself.
|
||||
|
||||
<details>
|
||||
<summary>Hints</summary>
|
||||
|
||||
- You can use the `ascii` codes of the letters to your advantage.
|
||||
- You need to distinguish between lower and upper case.
|
||||
- To roll back from back from a too high index back into the range of real
|
||||
letters. To do that you can use the modulo operation, which computes the
|
||||
remainder of a division by x. This is actually finite field arithmetic,
|
||||
but don't get so deep into the math.
|
||||
- It is handy to have a command line argument for key and source text.
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Solution</summary>
|
||||
|
||||
I ciphered the text with the key $19$. The original, deciphered text is:
|
||||
|
||||
<details>
|
||||
<summary>Text</summary>
|
||||
|
||||
```text
|
||||
Neovim is a refactor, and sometimes redactor, in the tradition of Vim (which itself derives from
|
||||
Stevie). It is not a rewrite but a continuation and extension of Vim. Many clones and derivatives
|
||||
exist, some very clever—but none are Vim. Neovim is built for users who want the good parts of
|
||||
Vim, and more.
|
||||
````
|
||||
|
||||
</details>
|
||||
|
||||
To decipher, you just apply the shifting of number backwards, or with the key
|
||||
$-19$ (that's the same thing!).
|
||||
|
||||
[Code Example](src/caesar.py)
|
||||
|
||||
**Bonus**
|
||||
One other way you could try to *recover* the key with is by statistical
|
||||
analysis. Western languages (like English, German, etc.) have some letters,
|
||||
words, combinations of letters, that are more common than others. These follow
|
||||
a [statistical distribution](https://en.wikipedia.org/wiki/Letter_frequency).
|
||||
The letter that is by far the most common in English is `e`.
|
||||
|
||||
With this information, you could count the occurrences for each letter and find
|
||||
that the graph of frequencies looks the same -- only shifted by a couple
|
||||
letters. That difference is your key.
|
||||
|
||||
Another way to try to recover the key is by looking at obvious words. The second
|
||||
word in the cipher text is a single `t`. How many (common) words do you know
|
||||
that only have one letter? I only know `a`. If we calculate the difference,
|
||||
again, we get $19$, which is the key.
|
||||
|
||||
</details>
|
||||
|
||||
## Making a Hexeditor
|
||||
|
||||
In this section, we're building a little hexeditor. You will be able to install
|
||||
it on your system and use it instead of the `hexdump` and `xxd` built into most
|
||||
Linux distributions.
|
||||
|
||||
Hexdumping is actually really simple, all you have to do is read a file and
|
||||
print it's direct content interpreted as numbers in hexadecimal. Apply some
|
||||
fancy string formatting and we're done!
|
||||
|
||||
The editing part is a lot harder. It requires us to build a functioning TUI -
|
||||
Terminal User Interface, as working with command line arguments or regular
|
||||
reading from stdin won't help us much for editing a file. (if that's your thing,
|
||||
use `ed`.).
|
||||
|
||||
Note: If you're looking for a great, fully featured hexeditor, I'd recommend
|
||||
`bvi` ("binary vi"), which is packaged by most distributions.
|
||||
|
||||
-> `apt-get install bvi` <-
|
||||
|
||||
Note: I have no Idea how to install a python script as executable on windows, I
|
||||
don't like windows either, so no support for installing stuff on windows.
|
||||
|
||||
### A. Hexdumper
|
||||
Difficulty: 3/5
|
||||
|
||||
1. Dump the data of [data/metasyntactic.md](./data/metasyntactic.md) -- In
|
||||
Hexadecimal.
|
||||
2. Make the dumped Bytes look pretty, something like the example below:
|
||||
3. Make use of command line arguments to add a help option (triggered with `-h` or
|
||||
`--help`) and a `-C` or `--chars` option that adds another section that
|
||||
prints the bytes interpreted as text. Those bytes that have no text
|
||||
representation should be displayed as `.`. You may use the `argparse` library
|
||||
to work with the arguments.
|
||||
|
||||
<details>
|
||||
<summary>Hexdump Example Display</summary>
|
||||
|
||||
`data/metasyntactic.md` should look like this when hexdumped:
|
||||
|
||||
```text
|
||||
Line Data
|
||||
=================================================
|
||||
0000000 | 6f4e 6574 203a 6854 7369 6920 2073 6874
|
||||
0000010 | 2065 6957 696b 6570 6964 2061 6170 6567
|
||||
0000020 | 6620 726f 6d20 7465 7361 6e79 6174 7463
|
||||
0000030 | 6369 7620 7261 6169 6c62 7365 6920 206e
|
||||
0000040 | 6e45 6c67 7369 2c68 3220 3230 2d33 3930
|
||||
0000050 | 302d 2e35 4620 6e69 2064 6874 0a65 7075
|
||||
0000060 | 7420 206f 6164 6574 6f20 6972 6967 616e
|
||||
0000070 | 206c 685b 7265 5d65 6828 7474 7370 2f3a
|
||||
0000080 | 652f 2e6e 6977 696b 6570 6964 2e61 726f
|
||||
0000090 | 2f67 6977 696b 4d2f 7465 7361 6e79 6174
|
||||
00000a0 | 7463 6369 765f 7261 6169 6c62 2965 0a2e
|
||||
00000b0 | 230a 4d20 7465 7361 6e79 6174 7463 6369
|
||||
00000c0 | 7620 7261 6169 6c62 0a65 230a 2023 6f54
|
||||
00000d0 | 6c6f 0a73 460a 6f72 206d 6957 696b 6570
|
||||
00000e0 | 6964 2c61 7420 6568 6620 6572 2065 6e65
|
||||
00000f0 | 7963 6c63 706f 6465 6169 540a 6968 2073
|
||||
0000100 | 7261 6974 6c63 2065 7369 6120 6f62 7475
|
||||
0000110 | 6d20 7465 7361 6e79 6174 7463 6369 7620
|
||||
...
|
||||
```
|
||||
|
||||
And like this when hexdumped with `-C`:
|
||||
|
||||
```text
|
||||
Line Data Text
|
||||
======================================================================
|
||||
0000000 | 6f4e 6574 203a 6854 7369 6920 2073 6874 |Note: This is th|
|
||||
0000010 | 2065 6957 696b 6570 6964 2061 6170 6567 |e Wikipedia page|
|
||||
0000020 | 6620 726f 6d20 7465 7361 6e79 6174 7463 | for metasyntact|
|
||||
0000030 | 6369 7620 7261 6169 6c62 7365 6920 206e |ic variables in |
|
||||
0000040 | 6e45 6c67 7369 2c68 3220 3230 2d33 3930 |English, 2023-09|
|
||||
0000050 | 302d 2e35 4620 6e69 2064 6874 0a65 7075 |-05. Find the.up|
|
||||
0000060 | 7420 206f 6164 6574 6f20 6972 6967 616e | to date origina|
|
||||
0000070 | 206c 685b 7265 5d65 6828 7474 7370 2f3a |l [here](https:/|
|
||||
0000080 | 652f 2e6e 6977 696b 6570 6964 2e61 726f |/en.wikipedia.or|
|
||||
0000090 | 2f67 6977 696b 4d2f 7465 7361 6e79 6174 |g/wiki/Metasynta|
|
||||
00000a0 | 7463 6369 765f 7261 6169 6c62 2965 0a2e |ctic_variable)..|
|
||||
00000b0 | 230a 4d20 7465 7361 6e79 6174 7463 6369 |.# Metasyntactic|
|
||||
00000c0 | 7620 7261 6169 6c62 0a65 230a 2023 6f54 | variable..## To|
|
||||
00000d0 | 6c6f 0a73 460a 6f72 206d 6957 696b 6570 |ols..From Wikipe|
|
||||
00000e0 | 6964 2c61 7420 6568 6620 6572 2065 6e65 |dia, the free en|
|
||||
00000f0 | 7963 6c63 706f 6465 6169 540a 6968 2073 |cyclopedia.This |
|
||||
...
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Hints</summary>
|
||||
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Solution</summary>
|
||||
|
||||
[Code Example](./src/hexdumper.py)
|
||||
|
||||
</details>
|
||||
|
||||
### B. Packaging your hexdumper
|
||||
|
||||
1. Install `pip`, on debian based systems you can do that with `apt-get install
|
||||
python3-pip`.
|
|
@ -0,0 +1,167 @@
|
|||
Note: This is the Wikipedia page for metasyntactic variables in English, 2023-09-05. Find the
|
||||
up to date original [here](https://en.wikipedia.org/wiki/Metasyntactic_variable).
|
||||
|
||||
# Metasyntactic variable
|
||||
|
||||
## Tools
|
||||
|
||||
From Wikipedia, the free encyclopedia
|
||||
This article is about metasyntactic variables in computer science and programming. For metasyntactic
|
||||
variables as used in formal logic, see Metavariable (logic). For usage in spoken languages, see
|
||||
Placeholder name.
|
||||
|
||||
A metasyntactic variable is a specific word or set of words identified as a placeholder in computer
|
||||
science and specifically computer programming. These words are commonly found in source code and are
|
||||
intended to be modified or substituted before real-world usage. For example, foo and bar are used in
|
||||
over 330 Internet Engineering Task Force Requests for Comments, the documents which define
|
||||
foundational internet technologies like HTTP (web), TCP/IP, and email protocols.[1][2]
|
||||
|
||||
By mathematical analogy, a metasyntactic variable is a word that is a variable for other words,
|
||||
just as in algebra letters are used as variables for numbers.[1]
|
||||
|
||||
Metasyntactic variables are used to name entities such as variables, functions, and commands whose
|
||||
exact identity is unimportant and serve only to demonstrate a concept, which is useful for teaching
|
||||
programming.
|
||||
Common metasyntactic variables
|
||||
|
||||
Due to English being the foundation-language, or lingua franca, of most computer programming
|
||||
languages, these variables are commonly seen even in programs and examples of programs written for other spoken-language audiences.
|
||||
|
||||
The typical names may depend however on the subculture that has developed around a given programming
|
||||
language.
|
||||
|
||||
## General usage
|
||||
|
||||
Metasyntactic variables used commonly across all programming languages include foobar, foo, bar,
|
||||
baz, qux, quux, corge, grault, garply, waldo, fred, plugh, xyzzy, and thud; several of these words
|
||||
are references to the game Colossal Cave Adventure.[1][3]
|
||||
|
||||
A complete reference can be found in a MIT Press book titled The Hacker's Dictionary.
|
||||
|
||||
## Japanese
|
||||
|
||||
In Japanese, the words hoge (ほげ)[4] and fuga (ふが) are commonly used, with other common words
|
||||
and variants being piyo (ぴよ), hogera (ほげら), and hogehoge (ほげほげ).[5][circular reference]
|
||||
The origin of hoge as a metasyntactic variable is not known, but it is believed to date to the early
|
||||
1980s.[5]
|
||||
|
||||
## French
|
||||
|
||||
In France, the word toto is widely used, with variants tata, titi, tutu as related placeholders.
|
||||
One commonly-raised source for the use of toto is a reference to the stock character used to tell
|
||||
jokes with Tête à Toto.[citation needed]
|
||||
|
||||
## Turkish
|
||||
|
||||
In Turkey, the words hede and hödö (usually spelt hodo due to ASCII-only naming constraints of
|
||||
programming languages) are well-known metasyntactic variables stemmed from popular humorous cartoon
|
||||
magazines of the 90's like LeMan. The words don't mean anything, and specifically used in place of
|
||||
things that don't mean anything. The terms have been popularized to the masses by the actor and
|
||||
stand-up comedian Cem Yılmaz in the late 90's and early 2000's.[6]
|
||||
|
||||
## Usage examples
|
||||
A screenshot of a metasyntactic variable FOO assigned and echoed in an interactive shell session.
|
||||
|
||||
## C
|
||||
See also: C programming language
|
||||
|
||||
In the following example the function name foo and the variable name bar are both metasyntactic
|
||||
variables. Lines beginning with // are comments.
|
||||
|
||||
```c
|
||||
// The function named foo
|
||||
int foo(void)
|
||||
{
|
||||
// Declare the variable bar and set the value to 1
|
||||
int bar = 1;
|
||||
|
||||
return bar;
|
||||
}
|
||||
```
|
||||
|
||||
## C++
|
||||
See also: C++
|
||||
|
||||
Function prototypes with examples of different argument passing mechanisms:[7]
|
||||
|
||||
```cpp
|
||||
void Foo(Fruit bar);
|
||||
void Foo(Fruit* bar);
|
||||
void Foo(const Fruit& bar);
|
||||
|
||||
Example showing the function overloading capabilities of the C++ language
|
||||
|
||||
void Foo(int bar);
|
||||
void Foo(int bar, int baz);
|
||||
void Foo(int bar, int baz, int qux);
|
||||
```
|
||||
|
||||
## Python
|
||||
|
||||
Spam, ham, and eggs are the principal metasyntactic variables used in the Python programming
|
||||
language.[8] This is a reference to the famous comedy sketch, "Spam", by Monty Python, the eponym
|
||||
of the language.[9] In the following example spam, ham, and eggs are metasyntactic variables and
|
||||
lines beginning with # are comments.
|
||||
|
||||
```python
|
||||
# Define a function named spam
|
||||
def spam():
|
||||
|
||||
# Define the variable ham
|
||||
ham = "Hello World!"
|
||||
|
||||
# Define the variable eggs
|
||||
eggs = 1
|
||||
|
||||
return
|
||||
```
|
||||
|
||||
## IETF Requests for Comments
|
||||
|
||||
Both the IETF RFCs and computer programming languages are rendered in plain text, making it
|
||||
necessary to distinguish metasyntactic variables by a naming convention, since it would not be
|
||||
obvious from context.
|
||||
|
||||
Here is an example from the official IETF document explaining the e-mail protocols (from RFC 772 -
|
||||
cited in RFC 3092):
|
||||
|
||||
```text
|
||||
All is well; now the recipients can be specified.
|
||||
|
||||
S: MRCP TO:<Foo@Y> <CRLF>
|
||||
R: 200 OK
|
||||
|
||||
S: MRCP TO:<Raboof@Y> <CRLF>
|
||||
R: 553 No such user here
|
||||
|
||||
S: MRCP TO:<bar@Y> <CRLF>
|
||||
R: 200 OK
|
||||
|
||||
S: MRCP TO:<@Y,@X,fubar@Z> <CRLF>
|
||||
R: 200 OK
|
||||
|
||||
Note that the failure of "Raboof" has no effect on the storage of
|
||||
mail for "Foo", "bar" or the mail to be forwarded to "fubar@Z"
|
||||
through host "X".
|
||||
```
|
||||
|
||||
(The documentation for texinfo emphasizes the distinction between metavariables and mere variables
|
||||
used in a programming language being documented in some texinfo file as: "Use the @var command to
|
||||
indicate metasyntactic variables. A metasyntactic variable is something that stands for another
|
||||
piece of text. For example, you should use a metasyntactic variable in the documentation of a
|
||||
function to describe the arguments that are passed to that function. Do not use @var for the names
|
||||
of particular variables in programming languages. These are specific names from a program, so
|
||||
@code is correct for them."[10])
|
||||
|
||||
Another point reflected in the above example is the convention that a metavariable is to be
|
||||
uniformly substituted with the same instance in all its appearances in a given schema. This is in
|
||||
contrast with nonterminal symbols in formal grammars where the nonterminals on the right of a
|
||||
production can be substituted by different instances.[11]
|
||||
Example data
|
||||
SQL
|
||||
|
||||
It is common to use the name ACME in example SQL Databases and as placeholder company-name for the
|
||||
purpose of teaching. The term 'ACME Database' is commonly used to mean a training or example-only
|
||||
set of database data used solely for training or testing. ACME is also commonly used in
|
||||
documentation which shows SQL usage examples, a common practice with in many educational texts as
|
||||
well as technical documentation from companies such as Microsoft and Oracle.[12][13][14]
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
|
||||
def internal(text: str, key: int) -> str:
|
||||
cyphertext: str = ""
|
||||
for c in text:
|
||||
if ord(c) >= 65 and ord(c) <= 90: # uppercase letters
|
||||
ci = ord(c) - ord('A')
|
||||
add = ord('A')
|
||||
#print(f"{c} is uppercase")
|
||||
elif ord(c) >= 97 and ord(c) <= 122: # uppercase letters
|
||||
ci = ord(c) - ord('a')
|
||||
add = ord('a')
|
||||
#print(f"{c} is lowercase")
|
||||
else:
|
||||
#print(f"not a letter: {c} ({ord(c)})")
|
||||
# character is not a letter, just skip it
|
||||
cyphertext += c
|
||||
continue
|
||||
ci += key
|
||||
ci %= 26 # only 23 letters in the alphabet
|
||||
#print(f"ci for {c}: {ci}")
|
||||
cyphertext += chr(ci + add)
|
||||
|
||||
return cyphertext
|
||||
|
||||
|
||||
if len(sys.argv) <= 2 or len(sys.argv) >= 5:
|
||||
print("Takes two arguments: <SOURCE> <KEY> [-e]")
|
||||
exit(1)
|
||||
|
||||
source: str = sys.argv[1]
|
||||
target: str = ""
|
||||
key = int(sys.argv[2])
|
||||
|
||||
if len(sys.argv) >= 4 and sys.argv[3] == "-e":
|
||||
print("encrypting...")
|
||||
target = internal(source, -key)
|
||||
|
||||
|
||||
else:
|
||||
print("decrypting...")
|
||||
target = internal(source, key)
|
||||
|
||||
print("=" * 80)
|
||||
print("%s" % target)
|
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
def fib(n):
|
||||
fibs = [0, 1]
|
||||
for i in range(2, n+1):
|
||||
fibs.append(fibs[i-1] + fibs[i-2])
|
||||
print(fibs)
|
||||
return fibs[n]
|
||||
fib(int(sys.argv[1]))
|
|
@ -0,0 +1,9 @@
|
|||
import sys
|
||||
def small_gaussian_sum(n: int) -> int:
|
||||
return int((n**2 + n) / 2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if sys.argv.__len__() < 2:
|
||||
print("provide a natural number as arg")
|
||||
else:
|
||||
print(small_gaussian_sum(int(sys.argv[1])))
|
|
@ -0,0 +1,34 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
def greek(path: str):
|
||||
"""replace all semicolons in the given file with Greek question marks"""
|
||||
contents: str = ""
|
||||
with open(path, "r") as file:
|
||||
contents = file.read()
|
||||
contents = contents.replace(";", "\u037e")
|
||||
with open(path, "w") as file:
|
||||
file.write(contents)
|
||||
file.flush()
|
||||
|
||||
def main():
|
||||
"""
|
||||
Turn all semicolons ';' of the target files into Greek question marks ';'.
|
||||
|
||||
For compilers and interpreters, this is a completely different character,
|
||||
but to humans, it looks the same. The Rust compiler is smart enough to warn
|
||||
us that it only looks like a semicolon. Use more Rust.
|
||||
"""
|
||||
if sys.argv.__len__() < 2:
|
||||
print("provide filepaths as arguments")
|
||||
|
||||
paths: list[str] = []
|
||||
for index, arg in enumerate(sys.argv):
|
||||
if os.path.exists(arg) and os.path.isfile(arg) and index > 0:
|
||||
paths.append(arg)
|
||||
|
||||
for path in paths:
|
||||
greek(path)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,156 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import io
|
||||
import fcntl # only for non blocking IO, if you dont know what it is, you can ignore it or study up
|
||||
import select # to check if the file has data
|
||||
|
||||
# 2**30 bytes aka 1 Mebibyte
|
||||
MAX_SIZE: int = 0x100000
|
||||
|
||||
|
||||
|
||||
def humanbytes(B):
|
||||
"""Return the given bytes as a human friendly KB, MB, GB, or TB string."""
|
||||
B = float(B)
|
||||
KB = float(1024)
|
||||
MB = float(KB ** 2) # 1,048,576
|
||||
GB = float(KB ** 3) # 1,073,741,824
|
||||
TB = float(KB ** 4) # 1,099,511,627,776
|
||||
|
||||
if B < KB:
|
||||
return '{0} {1}'.format(B,'Bytes' if 0 == B > 1 else 'Byte')
|
||||
elif KB <= B < MB:
|
||||
return '{0:.2f} KB'.format(B / KB)
|
||||
elif MB <= B < GB:
|
||||
return '{0:.2f} MB'.format(B / MB)
|
||||
elif GB <= B < TB:
|
||||
return '{0:.2f} GB'.format(B / GB)
|
||||
elif TB <= B:
|
||||
return '{0:.2f} TB'.format(B / TB)
|
||||
|
||||
def main():
|
||||
"""Dump a file"""
|
||||
# arg parsing
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="hd",
|
||||
description="Dumps data as hex"
|
||||
)
|
||||
parser.add_argument("file", nargs='?', type=argparse.FileType('rb'), default=sys.stdin)
|
||||
parser.add_argument("-c", "--chars", action="store_true")
|
||||
parser.add_argument("-f", "--force", action="store_true") # ignore set limits
|
||||
args = parser.parse_args()
|
||||
|
||||
# open file
|
||||
try:
|
||||
# Tl;Dr, use this unless you want to do some lower level stuff
|
||||
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
||||
#file = open(args.file, "rb")
|
||||
|
||||
|
||||
# the above is sufficient for most regular uses
|
||||
#
|
||||
# some "files" are "lazy" and block the reading process until they have
|
||||
# content, like network connections, fifos, sockets, and so on.
|
||||
|
||||
# the following is a lower level approach to handling these. We
|
||||
# basically call a part of the libc, telling it to open the file
|
||||
# nonblocking. If something blocks, it will simply refuse.
|
||||
#
|
||||
# as far as i know, this only works on UNIX (like) systems. Windows
|
||||
# is the only major exception.
|
||||
|
||||
# make a syscall that will open our file in readonly mode, nonblocking.
|
||||
# if it did not exist and we write to it, it would be created with the
|
||||
# perms: 644 (like `chmod 644 myfile`)
|
||||
fd = args.file.fileno()
|
||||
# now we make the fd into the high level python class `file`
|
||||
file = os.fdopen(fd, "rb")
|
||||
# i read somewhere that file.readline() does not work like this, but as
|
||||
# we are reading binary data anyways, I don't care.
|
||||
# check if the file is readable
|
||||
if not select.select([file, ], [], [], 0.0)[0]:
|
||||
print("no data from stdin, are you trying to dump a file?")
|
||||
parser.print_usage()
|
||||
sys.exit(1)
|
||||
if not file.peek(1):
|
||||
print("File is blocked, trying to wait...")
|
||||
file = open(args.file, "rb")
|
||||
except Exception as e:
|
||||
print(f"Could not open file '{args.file}': {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# check if the file has a reasonable size to dump
|
||||
try:
|
||||
file.seek(0, os.SEEK_END)
|
||||
flen = file.tell()
|
||||
file.seek(0, os.SEEK_SET)
|
||||
except io.UnsupportedOperation:
|
||||
# some kinds of "files" like stdin are not seekable
|
||||
flen = 0
|
||||
if 0 != flen > MAX_SIZE:
|
||||
print(f"""The file you are trying to dump is larger than 1M.\n\
|
||||
Actual size: {humanbytes(flen)}\nrefusing to dump""")
|
||||
if (0 != flen > MAX_SIZE) and not args.force:
|
||||
print(f"The file you are trying to dump is larger than {humanbytes(MAX_SIZE)}.\n\n\
|
||||
Actual size: {humanbytes(flen)}\n\nrefusing to dump. You can force dump the file with --force.")
|
||||
sys.exit(2)
|
||||
# print header
|
||||
if args.chars:
|
||||
print("Line Data Text")
|
||||
print('=' * 68)
|
||||
else:
|
||||
print(f"Line Data")
|
||||
print('=' * 48)
|
||||
|
||||
# every line should contain 16 bytes, so we need a loop that get's 16 bytes
|
||||
# and then works with them
|
||||
next: bytes = bytes(16)
|
||||
index: int = 0
|
||||
while len(next) == 16:
|
||||
next = file.read(16)
|
||||
if len(next) == 0:
|
||||
# no data left to read
|
||||
break
|
||||
|
||||
line: str = f"{index:07x} | "
|
||||
|
||||
# actual hexdumping
|
||||
for i in range(16):
|
||||
if i % 2 == 0:
|
||||
if len(next) > i+1:
|
||||
line += f"{next[i]:02x}{next[i+1]:02x} "
|
||||
elif len(next) > i:
|
||||
line += f"{next[i]:02x} "
|
||||
else:
|
||||
line += " "
|
||||
else: continue
|
||||
|
||||
# if chars is enabled, print chars
|
||||
if args.chars:
|
||||
line += "| "
|
||||
for b in next:
|
||||
# special case for newline
|
||||
if b == 0x0a:
|
||||
line+= '' # official unicode symbol representing newlines
|
||||
# only print regular characters
|
||||
elif b > 0x20 and b < 0x7e:
|
||||
line += chr(b)
|
||||
elif b == 0x20:
|
||||
line += '\u2420'
|
||||
else:
|
||||
line += '.'
|
||||
|
||||
print(line)
|
||||
index += 16
|
||||
|
||||
file.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# when called directly (like executed from shell)
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
# no need for an exception when the user presses ctrl c.
|
||||
sys.exit(0)
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
import hashlib
|
||||
import sys
|
||||
to_hash = "foobar19"
|
||||
hashed = hashlib.md5(to_hash.encode())
|
||||
print(hashed.digest().hex())
|
|
@ -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)
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
import hashlib
|
||||
BASE: str = "foobar"
|
||||
MAX = 1000000
|
||||
SEARCH = "00"
|
||||
|
||||
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[:2]:
|
||||
count += 1
|
||||
print("%06d | %s" % (i, res))
|
||||
|
||||
|
||||
print(f"\nFound %d digests matching the search" % count)
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env python3
|
||||
import http.server
|
||||
import io
|
||||
|
||||
TEXT = "Python is not so hard"
|
||||
|
||||
class MyHandler(http.server.SimpleHTTPRequestHandler):
|
||||
def send_head(self) -> io.BytesIO:
|
||||
body = TEXT.encode()
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "text/html; charset=utf-8")
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
self.end_headers()
|
||||
|
||||
return io.BytesIO(body)
|
||||
|
||||
address = ("127.0.0.1", 8080)
|
||||
srv = http.server.HTTPServer(address, MyHandler)
|
||||
srv.serve_forever()
|
||||
|
||||
# To query your web server go to http://localhost:8080
|
||||
# OR from CLI and with headers:
|
||||
# $ curl localhost:8080 -v
|
|
@ -7,7 +7,7 @@ import time
|
|||
def report_progress(filename, progress):
|
||||
"""progress: 0-10"""
|
||||
stdscr.addstr(0, 0, "Moving file: {0}".format(filename))
|
||||
stdscr.addstr(1, 0, "Total progress: [{1:10}] {0}%".format(progress * 10, "#" * progress))
|
||||
stdscr.addstr(1, 0, "Total progress: [{1:20}] {0}%".format(progress * 5, "#" * progress))
|
||||
stdscr.refresh()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -16,7 +16,7 @@ if __name__ == "__main__":
|
|||
curses.cbreak()
|
||||
|
||||
try:
|
||||
for i in range(10):
|
||||
for i in range(20):
|
||||
report_progress("file_{0}.txt".format(i), i+1)
|
||||
time.sleep(0.5)
|
||||
finally:
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
#!/usr/bin/env python3
|
||||
import random
|
||||
import string
|
||||
import math
|
||||
import sys
|
||||
|
||||
alphabet = string.ascii_lowercase
|
||||
alphabet += string.ascii_uppercase
|
||||
alphabet += "0123456789"
|
||||
|
||||
def get_random_string(length):
|
||||
# choose from all lowercase letter
|
||||
letters = string.ascii_lowercase
|
||||
result_str = ''.join(random.choice(letters) for i in range(length))
|
||||
result_str = ''.join(random.choice(alphabet) for i in range(length))
|
||||
return result_str
|
||||
|
||||
print(get_random_string(20))
|
||||
print(get_random_string(int(sys.argv[1])))
|
||||
if len(sys.argv) >= 3 and sys.argv[2] == "-v":
|
||||
security = math.log2(len(alphabet)**int(sys.argv[1]))
|
||||
print(f"The alphabets size is {len(alphabet)}")
|
||||
print(f"Security bits: {security}")
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
import re
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print("takes only a file path as argument")
|
||||
exit(1)
|
||||
|
||||
textfile = open(sys.argv[1])
|
||||
text = textfile.read()
|
||||
|
||||
regex = r"\b[a-z][AEIOUaeiou]([a-w]|[A-W])"
|
||||
matches = re.finditer(regex, text, re.MULTILINE)
|
||||
counter = 0
|
||||
for i, match in enumerate(matches, start=1):
|
||||
print(f"{i:03} | \"{match}\"")
|
||||
counter += 1
|
||||
print(f"found {counter}.")
|
|
@ -0,0 +1 @@
|
|||
terminaltexteffects==0.11.0
|
|
@ -0,0 +1,20 @@
|
|||
from terminaltexteffects.effects.effect_burn import Burn
|
||||
text = """
|
||||
Beautiful is better than ugly.
|
||||
Explicit is better than implicit.
|
||||
Beautiful is better than ugly.
|
||||
Beautiful is better than ugly.
|
||||
Beautiful is better than ugly.
|
||||
Beautiful is better than ugly.
|
||||
Beautiful is better than ugly.
|
||||
Explicit is better than implicit.
|
||||
Explicit is better than implicit.
|
||||
Explicit is better than implicit.
|
||||
Explicit is better than implicit.
|
||||
Explicit is better than implicit.
|
||||
"""
|
||||
effect = Burn(text)
|
||||
with effect.terminal_output() as terminal:
|
||||
for frame in effect:
|
||||
terminal.print(frame)
|
||||
|
Loading…
Reference in New Issue