A stock list nobody else should read
Symmetric encryption scrambles a message with a secret key, and the same key unscrambles it. It keeps stored and sent data unreadable to anyone who does not hold the key.
A pharmacy sends its stock list to a warehouse across the internet. Many machines pass it on. Encryption means those machines see only scrambled bytes.
By the end of this lesson
Note
I can explain how one shared key encrypts and decrypts a message.
Key words
| Word | What it means |
|---|---|
| Plaintext | the message in a form anyone can read |
| Ciphertext | the scrambled message |
| Key | the secret value that controls the scrambling |
| Symmetric | the same key encrypts and decrypts |
| Brute force | trying every possible key until one works |
| Nonce | a number used once with a key and never repeated |
The cells students fill in are left blank in this preview.
A shift cipher moves every letter along
The oldest ciphers shift each letter along the alphabet. With a key of 3, a becomes d, b becomes e, and x wraps round to a.
This is a toy. It is useful only to learn the ideas, and you are about to break it. Never use it to protect anything.
Worked example: shifting four letters by 3
| Letter | Place (a is 0) | Place plus 3 | After wrapping at 26 | New letter |
|---|---|---|---|---|
| a | 0 | 3 | 3 | d |
| t | 19 | 22 | 22 | w |
| x | 23 | 26 | 0 | a |
| z | 25 | 28 | 2 | c |
The cells students fill in are left blank in this preview.
Shift a message by a key
message = "attack at dawn"
key = 3
secret = ""
for letter in message:
if letter == " ":
secret = secret + letter
else:
place = (ord(letter) - 97 + key) % 26
secret = secret + chr(place + 97)
# Change key to 10 and press Run.
print(secret)
Encrypt attackatdawn with key 3
python3 -c "print(''.join(chr((ord(c) - 97 + 3) % 26 + 97) for c in 'attackatdawn'))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Decrypt it by shifting back 3
python3 -c "print(''.join(chr((ord(c) - 97 - 3) % 26 + 97) for c in 'dwwdfndwgdzq'))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A short key falls to brute force
A shift cipher has only 25 useful keys. An attacker tries all 25 and reads the one that makes sense. This is a brute force attack.
Every extra bit in a key doubles the number of keys. That is why key length matters. The next Run prints 25 lines, one for each key.
Try all 25 keys on the scrambled message
python3 -c "for k in range(1, 26): print(k, ''.join(chr((ord(c) - 97 - k) % 26 + 97) for c in 'dwwdfndwgdzq'))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Worked example: how many keys a length allows
| Key length | Number of keys | Verdict |
|---|---|---|
| 8 bits | 256 | Tried in a blink |
| 32 bits | 4,294,967,296 | Tried in minutes |
| 56 bits (the old DES) | 72,057,594,037,927,936 | Broken: retired |
| 128 bits (AES) | 340,282,366,920,938,463,463,374,607,431,768,211,456 | Safe from brute force |
| 256 bits (AES) | More than a 1 followed by 77 zeros | Safe from brute force |
The cells students fill in are left blank in this preview.
Count the keys of a 128-bit key
python3 -c "print(2 ** 128)"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A common mistake
Warning
Many people think a cipher is safe while its method stays secret. The method is not the secret. The key is. Good ciphers are public and tested by experts for years. Never write your own cipher. Use a vetted library.
Modern ciphers mix bits: use AES
Computers scramble bits, not letters. A basic step is XOR: two equal bits give 0 and two different bits give 1. XOR with a key, then XOR with the same key again, and the message comes back.
That is the idea inside real ciphers. A real one repeats it in many rounds that mix the bits thoroughly.
XOR hello with a short key (a toy)
python3 -c "print(bytes(a ^ b for a, b in zip(b'hello', b'KEYKE')).hex())"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
XOR again with the same key
python3 -c "print(bytes(a ^ b for a, b in zip(bytes.fromhex('232035272a'), b'KEYKE')))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
AES in a good mode protects and checks
AES is the standard block cipher. It scrambles 16 bytes at a time with a key of 128, 192 or 256 bits. A mode says how it handles a longer message.
Choose an authenticated mode such as AES-GCM, or ChaCha20-Poly1305. It also detects tampering. Give each message its own nonce. A repeated nonce with one key breaks the security.
Worked example: which choice to make
| Choice | Advice | Reason |
|---|---|---|
| AES-GCM | Use | Hides the data and detects changes |
| ChaCha20-Poly1305 | Use | Same, and fast without special hardware |
| AES in ECB mode | Avoid | Equal blocks give equal ciphertext |
| A repeated nonce | Avoid | Leaks the data |
| DES, 56-bit | Retired | Key is too short |
The cells students fill in are left blank in this preview.
Make a random 128-bit key, count its characters
python3 -c "import secrets; print(len(secrets.token_hex(16)))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.