Base32와 Base58은 왜 따로 있나
같은 바이트를 문자로 바꾸는 방식이 여러 개인 이유가 있습니다. 알파벳 설계 의도와 크기 차이를 정리했습니다.
바이너리 데이터를 문자로 바꾸는 방식은 Base64 하나로 충분해 보입니다. 그런데 인증 앱의 설정 키는 Base32이고, 비트코인 주소는 Base58입니다. 각각 다른 조건을 우선했기 때문입니다.
크기부터 비교
30바이트를 각 방식으로 인코딩하면 결과 길이가 이렇게 나옵니다.
| 방식 | 길이 | 원본 대비 | 사용하는 문자 |
|---|---|---|---|
| hex | 60 | 200% | 0-9 a-f (16개) |
| Base32 | 48 | 160% | A-Z 2-7 (32개) |
| Base58 | 40 | 133% | 영숫자 중 58개 |
| Base64 | 40 | 133% | A-Z a-z 0-9 + / (64개) |
문자 종류가 많을수록 짧아집니다. 그런데 짧은 것이 항상 낫지는 않습니다.
Base64는 짧지만 문자가 걸린다
3바이트를 4문자로 바꿉니다. 표준 알파벳의 마지막 두 문자가 +와 /인데, 이 둘이 URL과 파일 경로에서 다른 의미를 갖습니다. 패딩에 쓰는 =도 쿼리스트링에서 걸립니다.
그래서 변형이 있습니다.
- URL-safe Base64 —
+를-로,/를_로 바꾸고 패딩을 생략합니다. JWT가 이 방식을 씁니다 - 표준과 URL-safe는 서로 다른 문자열이므로, 디코딩할 때 어느 쪽인지 알아야 합니다
대소문자를 모두 쓰므로 사람이 받아 적거나 전화로 불러 주기에는 맞지 않습니다.
Base32는 사람이 다루기 위한 것
5바이트를 8문자로 바꿉니다. Base64보다 20% 정도 길어지는 대신 조건 하나를 얻습니다. 대문자와 숫자만 쓰므로 대소문자 구분이 없습니다.
RFC 4648의 알파벳은 A-Z와 2-7입니다. 숫자 0, 1, 8, 9가 빠져 있습니다. 0과 O, 1과 I를 혼동하지 않도록 뺀 것입니다.
이 성질이 필요한 자리가 있습니다.
- TOTP 설정 키 — 인증 앱에 손으로 입력할 수 있어야 합니다. QR을 못 읽을 때 대체 수단이 됩니다
- DNS 레코드 — 도메인 이름은 대소문자를 구분하지 않으므로 Base64를 쓸 수 없습니다
- 파일명 — 대소문자를 구분하지 않는 파일 시스템에서 안전합니다
ULID가 쓰는 Crockford Base32는 여기서 한 걸음 더 갑니다. 입력받을 때 O를 0으로, I와 L을 1로 자동 변환해 잘못 적은 값을 받아들입니다.
Base58은 눈으로 확인하기 위한 것
비트코인 주소에서 시작된 방식입니다. 영숫자 62개에서 네 개를 뺐습니다.
제외: 0 (숫자 영), O (대문자 오), I (대문자 아이), l (소문자 엘)
Base64에서 +와 /를 뺀 이유도 있습니다. 이 문자들은 더블클릭으로 문자열을 선택할 때 경계로 인식되어 주소 전체가 한 번에 선택되지 않습니다.
대신 구조가 다릅니다. Base32와 Base64는 정해진 바이트 수를 정해진 문자 수로 바꾸지만, Base58은 전체를 하나의 큰 정수로 보고 58로 나눕니다.
- 블록 경계가 없어 앞에서부터 나눠 처리할 수 없습니다. 긴 데이터에는 맞지 않습니다
- 인코딩 길이가 입력 값에 따라 조금씩 달라집니다
- 앞자리의
0x00바이트는 나눗셈에서 사라지므로 별도로1을 붙여 표시합니다
주소나 키처럼 짧고 사람이 옮겨 적는 값에 맞춘 설계입니다.
무엇을 언제 쓰나
| 조건 | 선택 |
|---|---|
| 기계끼리 주고받고 크기가 중요 | Base64 |
| URL이나 파일명에 넣음 | URL-safe Base64 |
| 사람이 입력하거나 불러 줌 | Base32 |
| 대소문자를 구분하지 않는 환경 | Base32 |
| 짧은 식별자를 눈으로 대조 | Base58 |
| 바이트 단위로 확인해야 함 | hex |
hex는 가장 길지만 한 바이트가 정확히 두 글자로 대응되어 원본과 대조하기 쉽습니다. 디버깅용으로 쓰는 이유입니다.
어느 쪽도 암호화가 아니다
세 방식 모두 규칙만 알면 되돌릴 수 있습니다. 키가 없고 비밀도 없습니다. 값이 읽기 어려워 보이는 것과 보호되는 것은 다릅니다.
인코딩 방식을 구분하는 데는 문자 구성이 단서가 됩니다.
+,/,=가 보이면 Base64- 전부 대문자와
2-7이면 Base32 0,O,I,l이 하나도 없는 영숫자면 Base58
확인 순서
- 디코딩이 실패하면 알파벳을 봅니다. 표준 Base64와 URL-safe를 바꿔 시도합니다
- 길이가 4의 배수가 아니면 패딩이 잘렸을 수 있습니다
- Base32 값을 입력받는다면 소문자와 공백을 정규화합니다. 사용자는 구분해서 입력하지 않습니다
- 디코딩한 결과가 의미 있는 바이트인지 확인합니다
tools.onuel.dev에서 Base64, Base32, Base58, hex에 같은 값을 넣으면 길이와 문자 구성 차이가 바로 보입니다. 받은 값이 어느 방식인지 모를 때는 Base32 디코딩과 Base58 디코딩을 차례로 시도해 볼 수 있습니다.
- #인코딩
- #Base32
- #Base58