decoder.tools

Base45 Decoder

Decode Base45, the QR-code-friendly encoding defined in RFC 9285, into text and bytes.

INPUT
OUTPUT

The result appears here as you type.

Decoding runs in your browser. What you paste is not sent to a server.

A Base45 decoder converts a string written in the 45-character alphabet of RFC 9285 back into bytes. Every 3 characters become 2 bytes.

Example

This is the test vector from RFC 9285:

Input
%69 VD92EX0
Output
Hello!!

Note that the space in the input is part of the data. In Base45 a space is a valid character, not a separator.

What is Base45?

QR codes have an alphanumeric mode that can only store 45 characters: 0–9, A–Z, space and $ % * + - . / :. Characters in that mode take fewer bits each than in byte mode, so the same data fits in a smaller code. Base45 was designed to fit binary data into exactly that character set.

The encoding takes 2 bytes at a time, treats them as a number from 0 to 65535, and writes that number in base 45 using three characters, least significant first. A single trailing byte becomes two characters.

The best-known use is the EU Digital COVID Certificate. Its QR code text starts with HC1:, followed by Base45. The decoded bytes are zlib-compressed, and inside is a COSE-signed CBOR document. So decoding a certificate takes three steps: Base45 decode, inflate with zlib, then parse CBOR.

How to use the Base45 decoder

  1. Paste the Base45 text. If it starts with a prefix like HC1:, remove the prefix first.
  2. Read the result. Short test strings decode to text; real certificate payloads decode to binary.
  3. For a certificate, check the hex view: zlib data starts with 78. Copy the hex into the Gzip / zlib decompressor with Input is: Hex and Format: zlib / deflate to unpack it.

Decode Base45 in code

Python
A = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"

def b45decode(s: str) -> bytes:
    out = bytearray()
    for i in range(0, len(s), 3):
        chunk = [A.index(c) for c in s[i:i + 3]]
        n = sum(v * 45 ** k for k, v in enumerate(chunk))
        out += n.to_bytes(2 if len(chunk) == 3 else 1, "big")
    return bytes(out)

print(b45decode("%69 VD92EX0").decode())  # Hello!!

Base45 at a glance

SpecificationRFC 9285
Alphabet0–9 A–Z, space and $ % * + - . / :
Ratio3 characters per 2 bytes
Main useQR codes in alphanumeric mode, EU Digital COVID Certificates

Frequently asked questions

Why use Base45 instead of Base64 in a QR code?

Base64 needs lowercase letters, which forces the QR code into byte mode. Base45 stays inside the alphanumeric mode, which packs characters more tightly, so the same data produces a smaller, easier-to-scan code.

How do I read an EU COVID certificate?

Remove the HC1: prefix, decode the rest as Base45, inflate the result with zlib, and then parse the CBOR/COSE structure. This tool handles the first step and the gzip tool handles the second. The CBOR step needs a CBOR decoder.

Is the space character really part of the data?

Yes. The space is character number 36 in the Base45 alphabet. Removing or collapsing spaces changes the data, so paste the string exactly as it is.

Last reviewed · found a mistake? contact@decoder.tools · view as markdown