Skip to content
PBPasteBench

Base64 is not encryption

It has no key, hides nothing, and makes data a third larger. Here is what it is actually for, and the mistakes that follow from confusing the two.

·5 min read

Base64 turns readable text into something that looks scrambled, and that appearance does a lot of damage. It has no key, no secret, and no security property of any kind. Anyone who sees a Base64 string can read it in one step, and the fact that it looks encrypted is precisely why people keep misusing it.

What it actually does

Base64 solves a transport problem. Some channels — email headers, URLs, JSON string fields, XML attributes — only reliably carry printable ASCII. Raw binary sent through them gets mangled by anything that interprets a byte as a control character.

So Base64 re-expresses arbitrary bytes using 64 safe characters: A–Z, a–z, 0–9, plus + and /. It reads three bytes (24 bits) at a time and emits four characters of six bits each.

Three bytes in, four characters out. That is a 33 percent size increase, every time. Base64 makes data bigger, which is another reason it is not a compression or storage format.

The padding characters

When the input does not divide evenly into three-byte groups, the final group is padded and marked with one or two = characters:

"any"    → "YW55"       (3 bytes, no padding)
"any1"   → "YW55MQ=="   (4 bytes, two =)
"any12"  → "YW55MTI="   (5 bytes, one =)

Those equals signs are part of the format. Stripping them because they look untidy breaks strict decoders. If you have ever seen “invalid base64” on a string that looked fine, missing padding is a good first suspect.

Where the confusion causes real harm

Storing credentials

HTTP Basic authentication sends user:password Base64 encoded. This encodes nothing secret — it is one decode away from plaintext, which is why Basic auth is only acceptable over TLS. A config file with a Base64 password in it is a config file with a plaintext password in it.

“Obfuscating” data in a client

Base64 in a cookie, a URL parameter, or a hidden form field protects nothing. Anyone can decode and re-encode it, which means anyone can also change it. If your server trusts a Base64 value it received from a browser, it trusts a value the user controls entirely.

Confusing it with hashing

Base64 is reversible by design. A hash is not reversible at all — that is its entire purpose. If you need to verify something without storing the original, you need a hash, and for passwords specifically you need a deliberately slow one like bcrypt or Argon2. Our hash generator shows the difference plainly: the same input always produces the same digest, and no tool can turn that digest back.

What to use instead

  • Hiding data in transit: TLS. Not something you implement — something you turn on.
  • Hiding data at rest: real encryption with a managed key, such as AES-GCM.
  • Verifying something is unchanged: a hash, or an HMAC if an attacker could also change the hash.
  • Getting binary through a text channel: Base64. This is the job it is good at.

The URL-safe variant

Standard Base64 uses + and /, both of which mean something else in a URL. The URL-safe variant swaps them for - and _ and usually drops the padding. This is what JWTs use, which is why a token pasted into a standard decoder sometimes fails.

If you want to see any of this directly, our Base64 encoder round-trips text in both directions and handles the padding for you. Watch a password go in and come straight back out — it is the clearest possible demonstration that nothing was hidden.

Tools mentioned