Base45 인코딩과 디코딩 방법
- 입력 · 텍스트에 텍스트를 입력하거나 붙여넣으세요. 출력 · Base45 (RFC 9285) 에 Base45 문자열이 나타납니다.
- 압축된 바이트 같은 바이너리 데이터라면 먼저 변환 전을 Hex나 Base64로 설정하세요.
- 디코딩하려면 방향 전환에서 Base45 (RFC 9285) → 텍스트를 누르고 문자열을 붙여넣으세요. 결과가 바이너리라면 변환 후에서 Hex나 Base64를 고르세요. 건강 증명서는 바이너리입니다.
- 출력 복사는 공백을 그대로 유지합니다. 바이트 저장은 디코딩한 바이트를 파일로 내려받습니다.
Base45의 원리
RFC 9285는 입력을 2바이트씩 읽습니다. 각 쌍은 0부터 65535까지의 수 n이며, 이를 n = c + d × 45 + e × 45²를 만족하는 45진법 숫자 세 개 c, d, e로, 가장 낮은 자리부터 씁니다. 마지막에 남은 1바이트는 숫자 두 개가 됩니다. 알파벳은 QR 코드 영숫자 문자 집합을 순서대로 쓴 것입니다.
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:
RFC의 예시이며, 이 도구로 모두 재현됩니다.
| 입력 | Base45 |
|---|---|
AB | BB8 |
Hello!! | %69 VD92EX0 |
base-45 | UJCLQE7W581 |
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:로 시작하는 문자열이 들어 있습니다. 페이로드는 여러 층으로 되어 있으며, 이 페이지는 그중 하나를 처리합니다.
HC1:접두사를 지우세요.H,C,1,:는 모두 올바른 Base45 문자이므로, 접두사를 남겨 두면 데이터로 디코딩되어 그 뒤의 모든 것이 망가집니다.- 나머지를 여기서 Base45로 디코딩하세요. 이때 변환 후는 Base64로 설정합니다.
- 결과의 압축을 푸세요. 바이트
78(Base64로eJ나eN)로 시작하는 zlib 데이터입니다. Base64를 gzip, zlib 디코더에 붙여넣으세요. - 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: 접두사가 흔한 원인입니다.