Biterra Labs preview / Intro to Cryptography

Encoding (Base64 and Hex)

Before ciphers and encryption, you need encoding. Encoding is not encryption. It is a way to write the same bytes as text so they can travel through systems that expect text.

In CTFs, a lot of "crypto" is one or two clean decodes.

Core idea

Start by identifying how the data is written. A string is encoding-shaped when its characters, length, or padding match a known format:

These clues identify the outer representation, not what the bytes mean. Base64 or hex can contain readable text, encrypted data, compressed data, or a file. Decode one layer, inspect the result, and then decide what the bytes are.

Encoding vs encryption

If the characters and padding match a known encoding, test that representation before assuming encryption.

Quick comparison

PatternLikely formatWhyFirst test
Yml0Y3Rme3tleGFtcGxlfX0=Standard Base64Uses letters and digits and ends with = paddingDecode once with Base64
eyJyb2xlIjoidmlld2VyIn0URL-safe or unpadded Base64Looks Base64-shaped but omits padding; URL-safe values may also use - and _Add padding if required and use a URL-safe decoder
6269746374667b7b6578616d706c657d7dHexUses only 0-9 and a-f, has even length, and splits into byte pairsDecode once as hex

These patterns suggest a format; they do not prove it. Decode one layer and inspect the result before choosing another operation.

Base64

Standard Base64 uses A-Z, a-z, 0-9, +, /, and = padding. It turns binary into text for things like cookies, JSON, and email. URL-safe Base64 (sometimes called base64url) uses - and _ instead of + and /, and may omit the = padding.

Base64 clues

If the string matches these clues, decode it once and inspect the result.

Decode Base64

Bash
echo Yml0Y3Rme3tleGFtcGxlfX0= | base64 -d
JavaScript
atob("Yml0Y3Rme3tleGFtcGxlfX0=")
Python
import base64

base64.b64decode("Yml0Y3Rme3tleGFtcGxlfX0=")

The Bash command works with GNU coreutils and current macOS; older macOS versions use base64 -D. Browser atob(...) handles the standard alphabet but not - and _. In Python, use base64.urlsafe_b64decode(...) for URL-safe input and add = padding until the length is a multiple of 4 if required.

In CyberChef, add From Base64 to the recipe.

Hex

Hex writes each byte as two characters from 0-9 and a-f (or A-F). You will see it in dumps, some challenge files, and hash output.

Hex clues

Split the example into pairs to see the bytes:

Text
62 69 74 63 74 66 7b 7b 65 78 61 6d 70 6c 65 7d 7d

A long hex string is "hex-shaped." After one decode it might be readable text, another encoding, a hash, or binary. The decode tells you which.

Decode hex

Bash
echo 6269746374667b7b6578616d706c657d7d | xxd -r -p
JavaScript
const hex = "6269746374667b7b6578616d706c657d7d";
const bytes = Uint8Array.from(
  hex.match(/../g).map(byte => Number.parseInt(byte, 16)),
);

new TextDecoder().decode(bytes);
Python
bytes.fromhex("6269746374667b7b6578616d706c657d7d").decode()

Use .decode() when the resulting bytes contain text.

In CyberChef, add From Hex to the recipe. You can also inspect individual values with a hex-to-ASCII converter.

After decoding

The output decides your next move:

ResultWhat it may meanNext move
Readable text or a complete flagThe encoding layer is removedRead it and stop if the task is solved
Another Base64- or hex-shaped stringThe challenge may contain another encoding layerClassify and decode the new layer once
A file signature such as PK or \x89PNGThe decoded bytes belong to a fileSave the bytes and inspect the file type
Unreadable bytesThe decode may be wrong, or the result may be compressed, encrypted, or binary dataRecheck the format and challenge clues before trying another operation

Worked example

A challenge gives you:

Text
NmM2MTc5NjU3MjczNWY2MTcyNjU1ZjYzNmM3NTY1NzM=

Work through the evidence in order:

  1. The alphabet and final = make standard Base64 a reasonable first test.
  2. Decode Base64 once and inspect the result:
Text
6c61796572735f6172655f636c756573
  1. The new value uses only hex digits, has even length, and splits into pairs. Decode it as hex:
Text
layers_are_clues

Each operation was supported by the current value. You did not decide in advance to "decode twice"; you classified the output after the first decode.

Common mistakes

Useful resources

Self-check

A cookie contains:

Text
eyJyb2xlIjoidmlld2VyIn0

It has letters and numbers but no =, +, or /. Is Base64 still a reasonable first test?

Answer: yes. URL-safe Base64 may omit padding. Add = until the length is a multiple of 4 if the decoder complains, then see whether the bytes look like JSON or other text.

Next

National Treasure Fragment

Before you start

Classify the representation first.

  • what alphabet or padding do you see?
  • is one clean decode likely to turn this into readable text?
  • if it becomes another structured layer, what will you inspect next?

Download National Treasure Fragment