파일 업로드
  1. base64hub
  2. 기타 진법
  3. Base45

Base45 인코더 및 디코더 (RFC 9285)

텍스트를 입력하면 QR 코드가 영숫자 모드로 저장하는 45개 문자로 만든 RFC 9285 Base45가 나옵니다. 방향을 뒤집으면 HC1: 건강 증명서의 접두사 뒷부분 같은 Base45를 디코딩할 수 있습니다.

무료 가입 없음, 제한 없음 로컬 업로드 없음 RFC 9285 RFC 예시 모두 재현 업데이트 2026. 10. 27.
입력 0바이트 0 B출력 0

브라우저에서 처리됩니다. 이 페이지는 데이터를 어디로도 보낼 수 없습니다 – 확인 방법

Base45 인코딩과 디코딩 방법

  1. 입력 · 텍스트에 텍스트를 입력하거나 붙여넣으세요. 출력 · Base45 (RFC 9285) 에 Base45 문자열이 나타납니다.
  2. 압축된 바이트 같은 바이너리 데이터라면 먼저 변환 전을 Hex나 Base64로 설정하세요.
  3. 디코딩하려면 방향 전환에서 Base45 (RFC 9285) → 텍스트를 누르고 문자열을 붙여넣으세요. 결과가 바이너리라면 변환 후에서 Hex나 Base64를 고르세요. 건강 증명서는 바이너리입니다.
  4. 출력 복사는 공백을 그대로 유지합니다. 바이트 저장은 디코딩한 바이트를 파일로 내려받습니다.

Base45의 원리

RFC 9285는 입력을 2바이트씩 읽습니다. 각 쌍은 0부터 65535까지의 수 n이며, 이를 n = c + d × 45 + e × 45²를 만족하는 45진법 숫자 세 개 c, d, e로, 가장 낮은 자리부터 씁니다. 마지막에 남은 1바이트는 숫자 두 개가 됩니다. 알파벳은 QR 코드 영숫자 문자 집합을 순서대로 쓴 것입니다.

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:

RFC의 예시이며, 이 도구로 모두 재현됩니다.

입력Base45
ABBB8
Hello!!%69 VD92EX0
base-45UJCLQE7W581
ietf!QED8WEX0

디코딩할 때는 관대한 디코더라면 건너뛸 수 있는 두 가지를 검사합니다. 길이 3n + 1은 어떤 입력에서도 나올 수 없고, 65535를 넘는 묶음(GGW나 ZZZ 등)은 범위를 벗어납니다. 둘 다 오류가 됩니다.

Base45가 QR 코드에 맞는 이유

종이 위에서는 Base45가 낭비처럼 보입니다. 2바이트당 3자는 50% 오버헤드로, Base64의 33%보다 큽니다. 차이는 QR 코드가 텍스트를 저장하는 방식에 있습니다. 영숫자 모드에서 QR 코드는 이 45개 문자 두 개를 11비트에 담습니다. 따라서 Base45 세 글자는 16비트 데이터에 16.5비트가 들어, 오버헤드가 약 3%입니다.

Base64는 소문자가 필요해서 영숫자 모드를 쓸 수 없습니다. 문자당 8비트인 바이트 모드로 들어가야 하므로 QR 코드 안에서 33% 오버헤드가 생깁니다. 같은 데이터라면 Base45 QR 코드가 더 작거나 더 많이 담습니다.

EU 디지털 코로나19 증명서(HC1:) 디코딩하기

EU 디지털 코로나19 증명서의 QR 코드에는 HC1:로 시작하는 문자열이 들어 있습니다. 페이로드는 여러 층으로 되어 있으며, 이 페이지는 그중 하나를 처리합니다.

  1. HC1: 접두사를 지우세요. H, C, 1, :는 모두 올바른 Base45 문자이므로, 접두사를 남겨 두면 데이터로 디코딩되어 그 뒤의 모든 것이 망가집니다.
  2. 나머지를 여기서 Base45로 디코딩하세요. 이때 변환 후는 Base64로 설정합니다.
  3. 결과의 압축을 푸세요. 바이트 78(Base64로 eJ나 eN)로 시작하는 zlib 데이터입니다. Base64를 gzip, zlib 디코더에 붙여넣으세요.
  4. CBOR을 파싱하세요. 압축을 푼 바이트는 CBOR로 된 COSE_Sign1 구조로, 헤더, 증명서 필드가 담긴 페이로드, 서명으로 이루어집니다. 여기에는 CBOR 디코더가 필요한데, 이 사이트에는 없습니다.

디코딩하면 내용을 볼 수 있지만 서명은 검증되지 않습니다. 증명서가 진짜인지 확인하려면 발급 국가의 공개 키와 COSE 검증기가 필요합니다.

Python에서 Base45

Python 표준 라이브러리에는 Base45 모듈이 없습니다. 인코더는 RFC를 그대로 따릅니다.

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

def b45encode(data: bytes) -> str:
    out = []
    for i in range(0, len(data) - 1, 2):
        n = data[i] * 256 + data[i + 1]
        c, n = n % 45, n // 45
        d, e = n % 45, n // 45
        out += ALPHABET[c], ALPHABET[d], ALPHABET[e]
    if len(data) % 2:
        c, d = data[-1] % 45, data[-1] // 45
        out += ALPHABET[c], ALPHABET[d]
    return "".join(out)

b45encode(b"ietf!")    # 'QED8WEX0'

PyPI의 base45 패키지는 양방향을 모두 제공합니다. Python의 바이트 처리는 Python 페이지를 참고하세요.

자주 묻는 질문

Base45 출력에 왜 공백이 들어 있나요?

공백은 QR 영숫자 문자 집합의 45개 문자 중 하나이므로, Base45에서는 값이 36인 평범한 숫자입니다. Hello!!는 %69 VD92EX0으로 인코딩됩니다. 복사할 때 공백을 유지하고, 폼이나 셸이 공백을 잘라 내지 않게 하세요.

여기서 EU 디지털 코로나19 증명서를 디코딩할 수 있나요?

일부만 됩니다. 이 페이지는 Base45 단계를 처리합니다. 그 뒤의 데이터는 서명된 COSE 구조 안의 zlib 압축 CBOR이므로 압축 해제 단계와 CBOR 디코더가 필요합니다. 단계는 이 페이지에 정리했습니다.

Base45를 URL에 넣어도 안전한가요?

아니요. 공백, %, +, /가 알파벳에 있고, 모두 URL에서 의미를 갖습니다. 문자열을 퍼센트 인코딩하거나 URL에는 Base64URL을 쓰세요.

Base45 문자열이 왜 거부되나요?

올바른 Base45의 길이는 3n자나 3n + 2자이고, 3자 묶음은 각각 65535 이하여야 합니다. 길이가 3n + 1이거나 GGW 같은 묶음이 있으면 오류입니다. 남아 있는 HC1: 접두사가 흔한 원인입니다.