Text to Base64
Text to Base64 is two steps: the text becomes UTF-8 bytes, which sets the length, and every three bytes become four Base64 characters.
Base64
- Length 4 x ceil(19 / 3) = 4 x 7 = 28.
- 28 characters
- Bytes encoded From 14 characters. UTF-8 spends one byte on each ASCII character and two to four on everything else, and Base64 encodes the bytes, so the byte count is the one that sets the length.
- 19 bytes of UTF-8
- Padding 19 bytes leave 1 over after the groups of three. One byte fills two characters, and two = complete the group of four.
- == (2)
- Size increase
- 47%
- Alphabet RFC 4648 section 4. Values 62 and 63 are + and /, which have meanings in a URL.
- standard, + and /
| Group | Bytes (hex) | Six-bit groups | Indexes | Base64 |
|---|---|---|---|---|
| 1 | 43 61 66 | 010000 110110 000101 100110 | 16, 54, 5, 38 | Q2Fm |
| 2 | C3 A9 20 | 110000 111010 100100 100000 | 48, 58, 36, 32 | w6kg |
| 3 | E2 98 95 | 111000 101001 100010 010101 | 56, 41, 34, 21 | 4piV |
| 4 | 20 66 6F | 001000 000110 011001 101111 | 8, 6, 25, 47 | IGZv |
| 5 | 72 20 E2 | 011100 100010 000011 100010 | 28, 34, 3, 34 | ciDi |
| 6 | 82 AC 33 | 100000 101010 110000 110011 | 32, 42, 48, 51 | gqwz |
How the Base64 Decode and Encode works
Encoding text to Base64 is two conversions, and the first is easy to miss. Base64 encodes bytes, so the text has to become bytes before anything else happens, and the encoding that does it matters as much as the Base64 that follows.
On the web that encoding is UTF-8. It writes the 128 ASCII characters as one byte each and everything else as two to four bytes: é is C3 A9, ☕ is E2 98 95, and € is E2 82 AC. The example this encoder opens with, Café ☕ for €3!, is 14 characters and 19 bytes. JavaScript's btoa() skips this step: it reads each character as one byte, so it throws an error on ☕ and €, and on é it encodes the Latin-1 byte E9 rather than UTF-8. The result looks like Base64 and decodes to the wrong text anywhere that expects UTF-8, which is almost everywhere.
The second conversion is the Base64 itself. Every three bytes, 24 bits, are cut into four 6-bit numbers from 0 to 63, and each number picks one of 64 characters: A-Z for 0 to 25, a-z for 26 to 51, 0-9 for 52 to 61, then + and /. The 19 bytes here are six full groups of three and one byte over. The full groups give 24 characters, the leftover byte gives two more, and two = signs pad the last group to four, for 28 characters in all: 4 x ceil(19 / 3).
The options change only the spelling. URL-safe swaps + and / for - and _, so the result can go in a link or a file name without escaping. Turning off padding drops the trailing = signs, as JSON Web Tokens do. Wrapping splits the output into lines of 76 characters, which is what MIME email requires; leave it off for anything else, because a line break inside a JSON string or an HTML attribute breaks it.
What Base64 does not do is hide anything. It is reversible by anyone with no key, so encoding a password or an API key in Base64 protects it from nobody.
Base64 Decode and Encode FAQ
Why is my Base64 different from another encoder's?
Usually the text encoding. An encoder that reads one byte per character (JavaScript's btoa, or Latin-1) gives a different result from UTF-8 for any accented letter or symbol. The other causes are the alphabet (+ and / against - and _), padding, and line breaks, which this encoder lets you set.
How long will the Base64 be?
4 x ceil(n / 3) characters for n bytes of UTF-8, with padding. The example is 19 bytes and 28 characters. Count bytes rather than characters: an emoji is one character and four bytes.
Should I wrap the output at 76 characters?
Only for MIME email, where RFC 2045 requires it. Anywhere else (JSON, HTML, a URL, an environment variable) leave it off, because a line break inside the value breaks it.
Can I encode a file?
This encoder takes text. A file is bytes rather than text, so encode it with a tool that reads files: base64 -i file on macOS or base64 -w 0 file on Linux, or certutil -encode on Windows.