> For the complete documentation index, see [llms.txt](https://simon-6.gitbook.io/simoncyber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://simon-6.gitbook.io/simoncyber/ctf-writeups/picoctf-2025/cryptography/chacha-slide-hard.md).

# ChaCha Slide (Hard)

### The Challenge&#x20;

<figure><img src="/files/BrMYTWQ9Jqr2mdAUFWyX" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/5VJCCLMTeY3WqHn6cbFw" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/zUmCvM2wnRhDNzmi38Og" alt=""><figcaption><p>The Source Code</p></figcaption></figure>

<figure><img src="/files/4yGIkfxSG98Y6a3HfqCU" alt=""><figcaption></figcaption></figure>

***

Before moving on, ChaCha20-Poly1305 is a modern authenticated encryption algorithm that combines two cryptographic primitives:

**ChaCha20,** A fast stream cipher that encrypts data.&#x20;

**Poly1305** - A MAC (Message Authentication Code) that authenticates the encrypted data.

I was surprised on how secure ChaCha20-Poly1305 actually is, so I'm a bit skeptical approaching this challenge. Our goal was to find the The next thing was to analyze the source code.&#x20;

***

```
key = shasum(shasum(secrets.token_bytes(32)) + flag.encode())
```

This gets a key from checking it with shasum twice and combining 32 random bytes with the flag.&#x20;

The encryption function takes the message and essentially adds 28 bytes. It then add it's tag (16) as a identifier and I guess the nonce to add more uniqueness.

The decrypt function extracts the bytes to store into the tag, nonce, and cipher text variables. The ciphertext and the tag is then used to decrypt and to check integrity (with the tag). It then returns the plain text for us to read.&#x20;

{% hint style="info" %}
The cipher is the encryption object itself, it holds the key and is a instance of the algorithm. While ciphertext, is the encrypted data you get from running plaintext into the cipher.&#x20;
{% endhint %}

### The Vulnerability&#x20;

Everything looks fine, but I'm a little bit suspicious about the nonce. Essentially, from I'm seeing is that the same 12 bytes from nonce, is being used to first encrypt the message, but is then reused to decrypt the message. The reason why this is a vulnerability is because ChaCha20-Poly1305 is a stream cipher.&#x20;

### Stream Ciphers

Stream Ciphers use XOR operation to decrypt and encrypt. Basically, they have the plain text and some key stream (like what we had with nonce).

> In stream cipher, one byte is encrypted at a time while in block cipher \~128 bits are encrypted at a time. Initially, a key(k) will be supplied as input to pseudorandom bit generator and then it produces a random 8-bit output which is treated as keystream.

A good example from WikiPedia explained the XOR concept really well.&#x20;

<figure><img src="/files/jWMGTDW94EwT9iMAHZtJ" alt=""><figcaption></figcaption></figure>

### (Almost) Cracking it

The cipher is created like we mentioned in the example: Ciphertext = Plaintext ⊕ Keystream(key, nonce). However, you may noticed the key stream is the same, as they didn't generate a **new** keystream to encrypt the next message. Hence, we can compare the two cipher text, and in a way cancel the keystream.

```
C1 ⊕ C2 = (P1 ⊕ Keystream) ⊕ (P2 ⊕ Keystream)
        = P1 ⊕ P2  // Keystream cancels out!
```

```
Plaintext: 'Did you know that ChaCha20-Poly1305 is an authenticated encryption algorithm?'
Plaintext (hex): 44696420796f75206b6e6f7720746861742043686143686132302d506f6c793133303520697320616e2061757468656e7469636174656420656e6372797074696f6e20616c676f726974686d3f
Ciphertext (hex): 945bed47a19353a53b7165997c6d37655b082f0170ff653d615693de2a0ab9370c3e3b68e836ba68d7d8490be0867aff0629a9a59a5d1d59fbe89bbb2c7e5e14704e8014f61775b50941e5e9460830501af4196ee3d4171843809f3f44578c855709c606ea1fbf8604


Plaintext: 'That means it protects both the confidentiality and integrity of data!'
Plaintext (hex): 54686174206d65616e732069742070726f746563747320626f74682074686520636f6e666964656e7469616c69747920616e6420696e74656772697479206f66206461746121
Ciphertext (hex): 845ae813f89143e43e6c2a8728392f76405c090a65cf2d3e3c12d6ae310ea5265c61602ee821ff67cd914912fd9a66b1132eaee487560d1cf9f491bd2c2e451b3f44c101fb510f6ed52b6558d452197428aa10a22931578c855709c606ea1fbf8604

```

Since I'm no way even in close to being able to write my own scripts, I searched online.

{% embed url="<https://github.com/tl2cents/AEAD-Nonce-Reuse-Attacks>" %}

This document describes on how to crack it, but to be honest I'll still need to learn more to even be able to use it. So for now\... this will be unsolved.&#x20;
