# Play Nice

Category: Cryptography


## Description
Not all ancient ciphers were so bad... The flag is not in standard format.

## What is the playfair cipher?

We were given souce code called `playfair.py`, from this we can tell that the cipher used will be a playfair cipher! But what is that? A detailed explenation can be found [here](https://en.wikipedia.org/wiki/Playfair_cipher). I know about this cipher from NetOnCTF 2021, I have writeups on challenges from it [here](https://github.com/xnomas/NetOn-Writeups-2021). But lets get into the nitty gritty.

Tha basics that we need is an alphabet, size of our matrix and some ciphertext:
This could be an example matrix. And this matrix is our key! (also notice one typical thing, we left out one letter `V`. Most often you will see `I` or `J` left out) We use it to decrypt and encrypt text. Now, instead of taking you through all of the ins and outs of encryption and decryption, here are the basic concepts if decrypting text:

If we want to decrypt the text `QKDUKFHS` here is how we do it:
1. Split into pairs = `QK, DU, KF, HS`
2. Go through the pairs
3. If the letters are on the same line, shift left
4. If the letters are in the same column, shift up
5. Else form a rectangle, with the letters being one of the top or bottom edges. Get the first letter under the left top and first letter above right bottom (example to follow)

So here we go:
QK = Form a rectangle:


So Q turns into P and K into L; QK = PL
DU = Form a rectangle:


D turns into A, U turns into Y; DU = AY

KF = In the same column, shift up!
K turns into F, F turns into A; KF = FA
HS = Form a rectangle:


H turns into I, S turns into R; HS = IR

Great, now onto solving the challenge.

## Takeaways from playfair.py

There are just a few important parts to note:
This is the size of our matrix.
def generate_square(alphabet):
assert len(alphabet) == pow(SQUARE_SIZE, 2)
matrix = []
for i, letter in enumerate(alphabet):
if i % SQUARE_SIZE == 0:
row = []
if i % SQUARE_SIZE == (SQUARE_SIZE - 1):
return matrix
And the function that generates our matrix, which looks like this:
[['n', '5', 'v', 'g', 'r', 'u'],
['7', 'e', 'h', 'z', '1', 'k'],
['l', 'j', 'a', '8', 's', '9'],
['3', '4', '0', 'm', '2', 'w'],
['c', 'x', 'b', 'd', '6', 'p'],
['q', 'f', 'i', 't', 'o', 'y']]
And then when we connect to the remote service, we get this ciphertext:

## Decoding

You can use an online decoder, like [this one](https://www.dcode.fr/playfair-cipher). But I decided to practice and code it.
alphabet = 'n5vgru7ehz1klja8s9340m2wcxbd6pqfitoy'
matrix = generate_square(alphabet)

index = {}
for i in range(6):
for x in range(6):
index[matrix[i][x]] = [matrix[x].index(matrix[x][i]),x]
Here we generate the matrix, from that I made a dictionary containing all the characters of the alphabet, with their corresponding index.
def split_by_two(text):
splits = []
for i in range(0,len(text),2):

return splits

ciphertext = 'hnjm2e4t51v16gsg104i4oi9wmrqli'
splits = split_by_two(ciphertext)
plaintext = ''
Then I just simply split the cipher text into pairs.
for s in splits:
plaintext += get_rectangle(s,index,matrix)

print(f'Decrypted: {plaintext}')
And finally for each pair I find either the rectangle, or the column/row (those are in the get_rectangle function). I don't think I need to go too into detail of the `rectangle` code, since we went over how decryption works. Run and get this:
Decrypted: 7v8441mfrerhdr8rh20f2fya20noaq
Now just connect with netcat and here we go:
nc mercury.picoctf.net 19354
Here is the alphabet: n5vgru7ehz1klja8s9340m2wcxbd6pqfitoy
Here is the encrypted message: hnjm2e4t51v16gsg104i4oi9wmrqli
What is the plaintext message? 7v8441mfrerhdr8rh20f2fya20noaq
Congratulations! Here's the flag: dbc8bf9bae7152d35d3c200c46a0fa30
The flag is just the flag, no `picoCTF{}`.

Original writeup (https://github.com/xnomas/PicoCTF-2021-Writeups/blob/main/Play_nice/README.md).