Base64
Base64 uses a character set of 64 unique characters, which makes it compact, URL-safe and printable, at the cost of being harder for a human to read than hex or decimal.
There are some intricacies with the format, however. Because of how it works, the last few bits are sometimes unused (66% of the time), which means multiple different base64 strings can decode to the same underlying data.
This is the Base64 alphabet defined in RFC 4648. There are more variants listed in the Wikipedia page for Base64.
| Index | Char | Index | Char | Index | Char | Index | Char | |||
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | A | 16 | Q | 32 | g | 48 | w | |||
| 1 | B | 17 | R | 33 | h | 49 | x | |||
| 2 | C | 18 | S | 34 | i | 50 | y | |||
| 3 | D | 19 | T | 35 | j | 51 | z | |||
| 4 | E | 20 | U | 36 | k | 52 | 0 | |||
| 5 | F | 21 | V | 37 | l | 53 | 1 | |||
| 6 | G | 22 | W | 38 | m | 54 | 2 | |||
| 7 | H | 23 | X | 39 | n | 55 | 3 | |||
| 8 | I | 24 | Y | 40 | o | 56 | 4 | |||
| 9 | J | 25 | Z | 41 | p | 57 | 5 | |||
| 10 | K | 26 | a | 42 | q | 58 | 6 | |||
| 11 | L | 27 | b | 43 | r | 59 | 7 | |||
| 12 | M | 28 | c | 44 | s | 60 | 8 | |||
| 13 | N | 29 | d | 45 | t | 61 | 9 | |||
| 14 | O | 30 | e | 46 | u | 62 | + | |||
| 15 | P | 31 | f | 47 | v | 63 | / | |||
| = (padding) |
Encoding and decoding
The plaintext:
fslakternPlaintext is converted to binary. The binary is split into octets (groups of 8), so one octet equals one plaintext byte:
01100110 01110011 01101100 01100001 01101011 01110100 01100101 01110010 01101110Bits are split into sextets (groups of 6):
011001 100111 001101 101100 011000 010110 101101 110100 011001 010111 001001 101110Each sextet is converted to an integer which is the index to a character in the base64 character set. One sextet can be at most
111111(63or2^6 - 1) which translates to/.25 39 13 44 24 22 45 52 25 2 9 46Look up each index in the base64 character set and join all resulting characters to a base64 string
ZnNsYWt0ZXJuLast step is to add padding if the resulting base64 isn’t of length divisible by
4. This only happens in cases where the length of the input isn’t divisible by3. Recall that3input characters (3octets or24bits) are encoded as4output characters (4sextets or24bits).
Alignment and unused bits
Base64 encoding works in groups of 3 bytes (24 bits), split into 4 chunks of 6 bits each (called sextets). If the input length isn’t a multiple of 3 bytes, the final sextet will be partially filled and padded with zero bits. These unused bits don’t affect decoding.
Example hi (2 chars):
hias bits:ASCII: h i Bits: 01101000 01101001Split into 6-bit groups (sextets)
011010 000110 1001..Pad the last sextet with zeroes
011010 000110 100100Convert sextets into base64 indices
26 6 36Look up in base64 charset:
a G kAdd padding to make the output length a multiple of 4 characters
aGk=
Those final two unused bits in the last sextet can be any of 00, 01, 10, or 11, and the decoded plaintext will be identical, because the decoder ignores them.
This is how a machine would do it. But if we wanted we could populate the last 2 bits of the last sextet with 01, 10 or 11, and the resulting base64 would be:
00end:aGk=01end:aGl=10end:aGm=11end:aGn=
All four decode to hi, because the decoder ignores those last two bits. So don’t rely on base64 to prove uniqueness. Strip the padding first and the input length is divisible by 3 (3 bytes × 8 bits per byte = 24 bits = 6 bits per sextet × 4 base64 characters), which removes the ambiguity.
See examples on Wikipedia