Skip to content

Commit 6c5a7cb

Browse files
committed
first commit of beginner crypto
1 parent e6354b2 commit 6c5a7cb

File tree

4 files changed

+203
-0
lines changed

4 files changed

+203
-0
lines changed

_posts/2021-08-24-beginner-crypto.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
layout: post
3+
title: "Maple Bacon Beginner crypto"
4+
author: rctcwyvrn
5+
hide: "true"
6+
---
7+
8+
Modern cryptography has a few main categories,
9+
1. Securing messages via encryption
10+
2. Acquiring keys via key exchange
11+
3. Ensuring the integrity of messages via signing and hashing
12+
13+
Normally beginner cryptography challenges involve simple alphabetic substituion ciphers, which are fine but also completely irrelevant in the modern day. I think that's a shame because there exist easy beginner challenges that are also _breaking real world cryptography_.
14+
15+
Why is that?
16+
17+
Modern cryptography is excellent and extremely secure, however it it has a major flaw.
18+
19+
**Cryptography is extremely brittle and easy to misuse.**
20+
21+
Algorithms can go from "it will take you til the heat death of the universe to crack" to "I can break this in 30 seconds with a 100 line python script" if you don't know what you're doing. This makes writing cryptography code extremely perilous, but it also makes for extremely fun CTF challenges!
22+
23+
Let's begin!
24+
25+
AES-CTR, modern encryption
26+
---
27+
What is AES-CTR? The name has two parts, the cipher (AES) and the mode (CTR).
28+
29+
AES is the [Advanced Encryption Standard](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) and it's the standard (haha) modern encryption primitive. You don't need to know how it works, just that it does one simple job. Given a 16 byte key and a 16 byte message it will secure that message and give you a 16 byte ciphertext. It has many strong security properties and it's passed the test of time (unlike many other ciphers).
30+
31+
CTR refers to the mode of operation. Most messages are not exactly 16 bytes long, and you want to be able to encrypt variable length messages. Different modes of operation give you ways to deal with variable length messages.
32+
33+
To explain CTR it's best to start with the one time pad. Did you know there exists a cipher that is **impossible** to crack? Not like it will take you a million years but that even given infinite time it is _impossible_ to break. It's called the [one time pad](https://en.wikipedia.org/wiki/One-time_pad) and it's incredibly simple. Just XOR your message with a stream of perfectly random bytes.
34+
35+
Why it's perfectly secure is actually pretty simple is left as an exercise to the reader but it brings this powerful idea that XOR is actually a very secure way to encrypt your messages, and it's this idea that is crucial for how CTR mode works. There's also a big hint in it's name, one time pad, you can only use this stream of bytes _once_ if you want it to be secure.
36+
37+
So now lets talk CTR.
38+
39+
What CTR mode does is it uses AES to create a stream of random bytes that you can then use to XOR against your message to encrypt it. How it does this is by asking AES to encrypt a series of numbers (ie 21, 22, 23, 24...) and this generates a bunch of random bytes which you can use for XOR. What number it starts from (21 in the example above) is determined by something called a nonce, and it's used because you can only use that stream of bytes _once_, after that you must choose a new nonce and get a new keystream.
40+
41+
AES-CTR isn't used on it's own very often, but it's older sibling [AES-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode), which uses CTR mode for encryption, is used very often. It's a part of ethernet, wifi, TLS/HTTPS, SSH just to name a few.
42+
43+
I said that CTR is only secure if you use a new nonce every time, but why exactly does CTR fail if you don't pick a new nonce? What happens if you're a naive web developer and you just choose AES-GCM because that's what stackoverflow told you to use?
44+
45+
Let's find out!
46+
47+
The challenge: Repeated nonce CTR
48+
---
49+
Ok so what happens if you use the same nonce and key for multiple messages?
50+
51+
Well AES-CTR will encrypt the same counter with the same key, meaning each message will be encrypted with identical keystreams.
52+
53+
So if we have messages `m1`, `m2`, `m3`, and keystream `K`, the three ciphertexts will be
54+
- `c1 = m1 XOR K`
55+
- `c2 = m2 XOR K`
56+
- `c3 = m3 XOR K`
57+
58+
Well what's the problem? Well consider the first byte of the three ciphertexts.
59+
60+
The first byte of `c1` will be the first byte of `m1` xor'd with the first byte of `K`, and same for `c2` and `c3`.
61+
62+
But we know two important pieces of information here
63+
1. All the messages contain english text
64+
2. There are only 256 possible values of the first byte of `K`
65+
66+
So what we can do is:
67+
1. Guess the value of the first byte of `K`, call it `g`
68+
2. XOR the first bytes of `c1` `c2` `c3` with `g` and see what we get
69+
3. If we get english characters for all three, we can be pretty sure that `g` is right, otherwise we try another guess for `g`
70+
71+
You may have noticed that this isn't very consistent, there could be many possible `g` where all three are english characters, but imagine instead of only 3 ciphertexts we have 10, or 20, or 1000. The more we have the higher confidence we have that `g` is correct.
72+
73+
How do we score english characters? You have two options
74+
1. Of the 256 possible byte values, the vast majority of them will ascii decode to garbage, so as long as it's a letter, number, punctuation, or whitespace you can give it a +1, and a -1 otherwise. Maybe with some extra tuning to say letter > whitespace > number > punctuation or something like that.
75+
2. We know from analysis of writing that certain letters are more common in english writing than other letters, so we can score letters based on their frequency in the sentences. This is generally more accurate than method 1 but of course is more complicated.
76+
77+
(Note: I tested both, they should both work)
78+
79+
Now you try!
80+
- [gen.py](/assets/challenges/beginner-crypto/gen.py) was used to encrypt `secret.txt` to generate [secret.enc](/assets/challenges/beginner-crypto/secret.enc)
81+
- `secret.txt` contains the flag along with enough english text to make this attack feasible
82+
83+
Hint: Beware of uppercase/lowercase!
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from Crypto.Cipher import AES # pip install pycryptodome
2+
import os
3+
4+
# Encrypt a single 16 byte block with AES
5+
def aes_enc(block, key):
6+
assert len(block) == 16 and len(key) == 16
7+
aes = AES.new(key, AES.MODE_ECB)
8+
return aes.encrypt(block)
9+
10+
# Decrypt a single 16 byte block with AES
11+
def aes_dec(block, key):
12+
assert len(block) == 16 and len(key) == 16
13+
aes = AES.new(key, AES.MODE_ECB)
14+
return aes.decrypt(block)
15+
16+
# Convert an int into 8 little endian bytes
17+
def i2b(x):
18+
return x.to_bytes(8, byteorder="little")
19+
20+
# Pad some bytes to 16 bytes, you don't need to know the details about how this works. It's PKCS#7 if you're curious
21+
def pad(in_bytes):
22+
num_bytes = (16 - len(in_bytes)) % 16
23+
append = bytes([num_bytes])
24+
for i in range(num_bytes):
25+
in_bytes+=append
26+
return in_bytes
27+
28+
# Remember ^ is integer xor in python
29+
def xor(a, b):
30+
pairs = zip(a,b)
31+
return bytes([x ^ y for (x,y) in pairs])
32+
33+
def aes_ctr_mode_enc(plaintext, nonce, key):
34+
nonce = i2b(nonce) # nonces are typically numbers from random number generators
35+
# but we want bytes so we can use it with our cipher
36+
37+
keystream = bytes() # the random bytes we're going to xor our plaintext message with
38+
block_count = 0
39+
while len(keystream) < len(plaintext): # while we still need more keystream
40+
block = nonce + i2b(block_count) # make the next counter block
41+
block = pad(block) # pad the block to 16 bytes
42+
keystream += aes_enc(block, key) # generate 16 random bytes for the keystream using AES
43+
block_count += 1 # increment the counter
44+
return xor(plaintext, keystream) # finally do the xor to encrypt the message
45+
46+
47+
NONCE = 1337 # uh oh
48+
KEY = os.urandom(16)
49+
50+
if __name__ == "__main__":
51+
output = []
52+
with open("secret_3.txt") as f:
53+
lines = f.readlines()
54+
for line in lines:
55+
plaintext = line.encode() # convert from string to bytes
56+
ciphertext = aes_ctr_mode_enc(plaintext, NONCE, KEY) # Nonce reuse! Each line will be using the same keystream!
57+
output.append(ciphertext.hex())
58+
59+
with open("secret.enc", "w") as f:
60+
for line in output:
61+
f.write(line + "\n")
62+
63+
print("Done!")
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2d5081b7e99a2f09a770852762b1a15c48de4ea98862e8842e3f904d9402140a49797bb36993
2+
035e9fbcfe80382e9261c67e52b6e7220fac32f5936bfbcc2015
3+
4312c2da
4+
3a50cfbdfa903e5cbf7998206aacf218088d6fa9882781cd357e9f47c1045b4c447c78bf2ce14eeee6261e4a56a0c8
5+
1d50cfb8fe893e5bb831906e6faabc1e01de69aada6ba79f3872c94b910341012f
6+
4312c2da
7+
22509db5f6db320cb8649c6e69b0be121bde75a58e27a980386bc502821f5a1f407b68fa3dec48bce662035f47a7a151e132ec
8+
4e5a83b9efd77b0fae75d12a62ffb7141c8d6ba39e27bc88306f8650c1195a0f4c7c75fb3cf74ebcf2724a434fb6ad4aea75ec
9+
0b4bcfb4f497340eae319c2f6ab1b35d08926fbd8f66e6cd0e7c8c4e84025d1f546d79bf2ffc48f1e2681e5a43f4a64de675ec
10+
085e9ab3f2992e0feb789f6e62adbc1c1b9b28ecb46ebb817d7c864c851959094b6c69f269f05ebcf163044a40b5b651fc75ec
11+
0f1f8cbff59f3211ae7f853b60ffa4141d9f63ec8966b8843871c702a405140a447b75f320ea53efa7750f4b0ebba651e075ec
12+
03509db2f2db2a09a262d12d62b2bf120d9126a39e6ea7cd3c7a8747801e1a4c607475eb69fc5df9f3260d5d4fa2ab5cee75ec
13+
0d4a82f0e8943815a262df6e5ebabf0d0c8c26a99d62bccd396a8051c111404c517d70f33cea1afdf3261f5d40b5e25be03bec
14+
0a5682b5f58f2e11e531a1217faba6141d9174ec886fa7833e6a9a02851f580357386cea3bec49bce96904010e98ad4aea38ec
15+
4e569fa3ee967b18a47d9e3c2dacbb09499f6ba98e27ab82336c8c419515401957363cc928eb53e9f42607405cb6ab18ea3bec
16+
0752cfbeee95385cad70842d64bda70e499f26bc9f6ba488336b8c519005514c567168bf28f45fe8a776055d5aa0ab4ce027ec
17+
401faea4bb973e1fbf64826e78adbc1c499a73a58927ab823369884e8d19474c467772e928f556f5f4261e4a42b8b74baf3cec
18+
0a1f86beef9e2918be7cd13868b3bb0947de44a09b69ac84293f9d5793005d1f057b69ed3aec49bcee684a474fb7e250ee37ec
19+
074b8ea3e89e7b0ca770852b6cffb6140a8a73a18973e6cd7d5a874b8c50520d467170f63af049bce0740b5947b0a318e130ec
20+
1f4a8af0f894350aaa7d9d277effb35d0a8c67bfda74ad802d7a9b0cc125581857717ffa3ab94cf5f3670f0f4fa1a14ce027ec
21+
4e5a9af0fa8e3c09ae3fd1036caaa0141ade67b99d72adcd337a98578450531e446e75fb28b953f2a9263e4a42b8b74baf3aec
22+
1c5c86f0fa987b1dbe7285217fffb3080e8b63ec9766bd9f346cc94394174109057679ee3cfc14bcd4690e4e42b1b118e130ec
23+
1f4a8af0e8943f1da774826e78abf2181d9767a1da74a1997d7e844795505a0556743cef3ceb4fefa9262b4c0ea4ae59ec30ec
24+
1c5e9bf0ed9e2808a273842278b2f2110c9d72b98927a58c286d8051c105581857717ffa3ab95feee8754a4640f4a14dfd26ec
25+
1b4ccfa4ee892b15b83fd10064acbe5d1f9b6aec8a75ad99346a84028d155718506b3cee3cf857bcee624a434bbbe251e17bec
26+
4e698abefe953a08a262d12d7fbea15d1a9b62ec9c62a4842e3f8c458404141a407475eb67b97ff0ee724a5a42b8a355ec3aec
27+
1c4f8aa2bb9f321ba578823d64b2f21e1b9f75ec8e6ea68e347b9c4c9550580347776eeb20ea14bccb63050f58b1ae18e927ec
28+
075188b9f7973a5cae62856e78b3be1c049d69be8a62bacd38788c56c11e410049793cf928fa53f0ee75030f4ba0ab59e27bec
29+
4e6c9aa3eb9e3518a262822b2daabe091b9765a98927af9f3c69804680505005466c69f269ff4fefe4634a5a5afae27eea20ec
30+
09568ea4bb95321ea331822b69ffa20805886fa29b75e89d2f70804cc117460d537178fe69f15ff2e3740f5d47a0e254ea36ec
31+
1a4a9cfebbab2e0ebe62d13d68b2a2181bde63ab9f73e88928769a0280041418407470ea3ab71aceee751f5c0ea7a75caf23ec
32+
1b539fa5ef9a2f19eb7e952762ffa709499b68a59727aa813c718d4b95504203496d68ef28ed1af1e663094a40b5b118f93aec
33+
024a9ba0fa8f755ceb4184227bb6bc1c1bde75ad8a6ead837d7a9d028d19531949793cea25f55bf1e469185f4ba6e255ee39ec
34+
0b4c9ab1ff9a7b0cb97e98202db3bb1f0c8c69ec9472a68e733fae5080065d0844386dea20ea1afeeb67044b47a0e24cfa27ec
35+
1e569cf0f88e290fbe62d12763f1f22e069a67a09f74e898293f8c57c1035101057172eb2cfe5feea770035b4fb1e252fa26ec
36+
1a50cfb5fc9e2f52eb509d277caab310498863bf8e6eaa98316a84028c1f460e4c387ef328f75ef5f326095a5ca7b74baf27ec
37+
074c9aa3bb9a2f5cbe7d853c64bcb70e47de47ec9666ab982e3f9f4792045d0e507469f269ea5ff8a767184c5bf4ac57e17bec
38+
4e7e82b5efdb2b09b964826e6aadb30b009a67ec8b72a19e7d7d85438f145d18056c69ed39f049bce473185c5ba7e251e175ec
39+
065e8cf0f39a3915bf70823d68f1f22d1b9f63bf9f69bccd2e7a84528402140a406d7bf628ed1af2ee64020f5db1a618ff20ec
40+
024986befa897b0cb97e98202db8a01c1f9762adda6fad83396d8c5088041a4c647579eb69fa55f1ea690e400ebab754e334ec
41+
4e598eb3f297320fa2319f3b61b3b310498863a49364bd813c3f80529205594c44363cc928eb53e9f4260e5a47a7e259fb75ec
42+
0d5081a3fe982f19bf64836e61b0a01804de62a39462abc37d519c4c825055004c6969fa3db958f5e563044b5bb9e25de13cec
43+
031f89b1f8923715b878826e6aadb30b009a67e2da4aa981386c9c438511140a447579ec69f859bcf373185f47a7e25de830ec
44+
1d4b8ea3bb923508ae76943c2dbab5181dde67a09376bd882931c96480055705476d6fbf20f74ef9f5621f420ea4ad4bfa30ec
45+
1c5acfbcf4893e11eb78813d78b2f219069269beda74a199733fbd5088034005546d79bf27ec56f0e6260b4347a5b75dfb75ec
46+
0b5186bdbb8f340ebf7e836e6cabf21c1c9d72a38827bd9f337ec94c941e5742055573ed2bf01af9e96f070f40a1ac5baf33ec
47+
0f4a8cb9f98e285caa31812b61b3b7131d9b75bd8f62e89e346bc9438c15404c55776eeb3df04ef3f5284a0f6fb0ab48e626ec
48+
0d5681b7bb9e3515a631943b2daba70f199775ec9f60ad9e297e9a02910251184c6d71bf28fc54f9e6684a5f46b5b05dfb27ec
49+
0f11cf99f5db3d19b97c942079aabf5d199175b99f75adcd286d8743c11e510f056c75f12af05ee9e9724a5f5cb5a74bea3bec
50+
1a1f9cb5f68b3e0eeb77943b6ab6b30949906fae9229e8a8283f8f438219580556716fbf3afc5ebce86203400eb9ad4aed3cec
51+
401faebeef9e7b15a5319f276fb7f210088b74a58927ab982f6c9c51cf506403566d79ed2cb95bffa7731e0f4dbbac4bea24ec
52+
1b5e9bf0e89e360cae63d13864a9b70f1b9f26a29b6ae881347d8c508e505e19566c73b169da55f2f463095b4ba0b74aaf34ec
53+
0a569fb9e8983212ac31942264abf2191c9775ec8e75a19e2976985784504703497475fc20ed4ff8ee684a4147b6aa18fc3cec
54+
1a11cf83fa8b3219a531972f78bcbb1f1c8d26a98e27a582317a9a568815140d46387afa3cfe53fdf326194a4af4ae5dec21ec
55+
1b4cc1f0df923a11eb7c902b6ebabc1c1ade73a08e75a18e347a9a028c191409427d68b169ca5ff8a76f0e0f5db1af48ea27

blog.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ <h1>Blog</h1>
1111
<h3><a href="{{ post.external_url }}">{{ post.title }}</a></h3>
1212
</li>
1313
{% else %}
14+
{% unless post.hide %}
1415
<li>
1516
<h3><a href="{{ post.url }}">{{ post.title }}</a></h3>
1617
</li>
18+
{% endunless %}
1719
{% endif %}
1820
{% endfor %}
1921
</ul>

0 commit comments

Comments
 (0)