파일 업로드
  1. base64hub
  2. Base64 가이드
  3. Base64 표준과 RFC
레퍼런스

Base64 표준: PEM, MIME에서 RFC 4648까지

Base64에는 한 명의 발명자도, 하나의 명세도 없습니다. 1987년 보안 이메일에서 시작해 MIME에 채택되었고, 2003년에야 독립된 문서로 정리되었습니다. Base64를 정의한 문서들과 그 문서들이 만든 변형을 소개합니다.

연표

연도문서기여한 내용
1987RFC 989 (PEM, 1부)= 패딩을 쓰는 64자 “출력 가능 인코딩”, 암호화되지 않은 부분을 표시하는 *
1988, 1989RFC 1040, RFC 1113개정된 PEM 초안
1992RFC 1341 (MIME)이메일용 Content-Transfer-Encoding으로서의 Base64
1993RFC 1421 (PEM), RFC 1521 (MIME)정확히 64자인 PEM 줄, 개정된 MIME
1996RFC 2045 (MIME)지금도 쓰이는 MIME 정의: 최대 76자 줄
1997RFC 2152 (UTF-7)유니코드용 텍스트 인코딩 안의 Base64
2003RFC 3501 (IMAP4rev1)메일함 이름용으로 ,를 쓰는 수정 Base64
2003RFC 3548최초의 독립 명세: base64, base64url, base32, base16
2006RFC 4648RFC 3548을 대체, base32hex와 테스트 벡터 추가
2007RFC 4880 (OpenPGP)CRC-24 체크섬을 붙인 Radix-64 아머
2015RFC 7468PEM 방식 인증서와 키 파일에 대한 엄격한 규칙
2015RFC 7515 (JWS)토큰용 패딩 없는 Base64URL
2024RFC 9580 (OpenPGP)RFC 4880을 대체, 아머 체크섬 지원 중단

PEM: Base64가 시작된 곳

오늘날 쓰는 알파벳은 1987년 2월에 발표된 RFC 989 “Privacy Enhancement for Internet Electronic Mail”(인터넷 전자 메일 프라이버시 강화)에 처음 등장했습니다. 암호화된 메일은 출력 가능한 텍스트만 다루는 게이트웨이를 통과해야 했기 때문에, PEM에는 어떤 메일 시스템에서도 살아남는 문자로 바이너리 암호문을 쓰는 방법이 필요했습니다. PEM은 6비트씩 읽어 A-Z, a-z, 0-9, +, /에 대응시키고 패딩에 =를 썼습니다. RFC 989의 표는 이 사이트의 알파벳 표와 똑같습니다. 암호화되지 않은 부분을 표시하기 위해 *도 예약했지만, 이 기능은 살아남지 못했습니다.

PEM은 RFC 1040과 RFC 1113을 거쳐 RFC 1421(1993년 2월)에서 자리를 잡았고, 여기서 줄 길이가 정해졌습니다. “마지막 줄을 제외한 각 줄은 정확히 64개의 출력 가능 문자를 담고, 마지막 줄은 64개 이하를 담는다”. 이유로는 인쇄와 SMTP의 1000자 줄 제한을 들었습니다. 보안 메일 시스템으로서의 PEM은 자리 잡지 못했지만 그 파일 형식은 살아남았습니다. 모든 -----BEGIN CERTIFICATE----- 블록이 그 후손이며, 지금은 RFC 7468(2015)이 규칙을 명시합니다. 생성기는 정확히 64자에서 줄을 바꿔야 하고, 파서는 다른 폭도 받아들일 수 있습니다. 이런 파일은 인증서 디코더로 살펴볼 수 있습니다.

MIME: 모든 이메일 첨부 파일의 Base64

MIME(1992년 RFC 1341, 1993년 RFC 1521, 1996년 RFC 2045)은 이메일에 이미지와 문서를 넣을 방법이 필요했고, PEM의 인코딩을 빌려 왔습니다. RFC 2045는 지금도 이메일의 기준이며, PEM과 두 가지가 다릅니다.

  • 인코딩된 줄은 76자를 넘어서는 안 되며, CRLF로 구분합니다.
  • “base64로 인코딩된 데이터에서 base64 알파벳 밖의 문자는 무시한다.” 디코더는 줄 바꿈, 공백, 그 밖에 알파벳에 속하지 않는 모든 것을 건너뜁니다.

이 두 번째 규칙 때문에 많은 디코더가 올바르지 않은 문자를 조용히 버립니다. MIME 방식의 출력은 MIME Base64 인코더로 만들 수 있고, 첨부 파일의 구조는 이메일 속 Base64를 참고하세요.

RFC 3548과 RFC 4648: 모두를 위한 하나의 기준

2003년까지 Base64를 쓰는 모든 프로토콜은 MIME이나 PEM을 참조했고, 원하든 원하지 않든 그 줄 길이 규칙과 관대한 디코딩 규칙을 물려받았습니다. RFC 3548(2003년 7월)은 base64, base64url, base32, base16을 독립된 인코딩으로 정의했습니다. RFC 4648(2006년 10월)은 약간의 변경과 함께 이를 대체했습니다. 인코딩된 데이터의 정렬 순서를 유지하는 base32hex와 테스트 벡터 세트를 추가했습니다.

BASE64("")       = ""
BASE64("f")      = "Zg=="
BASE64("fo")     = "Zm8="
BASE64("foo")    = "Zm9v"
BASE64("foobar") = "Zm9vYmFy"

RFC 4648의 규칙은 이를 참조하는 명세가 달리 정하지 않는 한 MIME보다 엄격합니다.

  • 줄 바꿈: 구현은 줄 바꿈을 넣어서는 안 됩니다(3.1절).
  • 패딩: 구현은 = 패딩을 넣어야 합니다(3.2절).
  • 알파벳 밖의 문자: 디코더는 이를 거부해야 합니다(3.3절).
  • 정규 인코딩: 인코더는 쓰지 않는 비트를 0으로 설정해야 하며, 디코더는 그렇지 않은 입력을 거부할 수 있습니다(3.5절). 이 규칙이 없으면 SGk/Pg==와 SGk/Ph==가 둘 다 Hi?>로 디코딩됩니다.

“이 문서를 참조하는 명세가 명시적으로 달리 정하지 않는 한"이라는 문구가 많은 일을 합니다. 이 덕분에 JWS는 패딩을 빼고 MIME은 76자 줄을 유지하면서도 둘 다 “RFC 4648 Base64"를 쓴다고 할 수 있습니다. 같은 RFC의 나머지 두 인코딩은 Base32와 Base16 도구가 구현합니다.

다른 표준에서 정의한 변형

JWS와 JWT: 패딩 없는 Base64URL

RFC 7515(2015년 5월)는 BASE64URL(x)를 5절의 알파벳에서 “끝의 ‘=’ 문자를 모두 생략한” 것으로 정의하며, 줄 바꿈이나 공백은 없습니다. JWT, JWE, JWK를 비롯한 JOSE 계열 대부분이 이를 씁니다. 자세한 내용은 JWT 속 Base64에 있습니다.

IMAP: 쉼표를 쓰는 수정 UTF-7

IMAP 메일함 이름은 7비트 문자열이므로, RFC 3501(5.1.3절)은 ASCII가 아닌 폴더 이름을 “수정 UTF-7"로 인코딩합니다. ASCII가 아닌 문자가 이어진 부분을 UTF-16으로 바꾸고, / 대신 ,를 써서 패딩 없이 Base64로 인코딩한 뒤 &와 -로 감쌉니다. RFC 자체의 예시 &U,BTFw-는 중국어 이름 台北이고, 독일어 폴더 Entwürfe는 Entw&APw-rfe가 됩니다. 일반 UTF-7(RFC 2152)은 같은 이름을 Entw+APw-rfe로 씁니다.

OpenPGP: CRC-24를 붙인 Radix-64

OpenPGP의 ASCII 아머는 MIME Base64에 체크섬 줄을 더한 것입니다. RFC 4880은 바이너리 데이터에 대한 CRC-24(생성 다항식 0x864CFB, 초깃값 0xB704CE)를 정의하며, 이를 Base64로 인코딩하고 앞에 =를 붙입니다. GnuPG는 12바이트 Hello world!에 대해 다음을 만듭니다.

-----BEGIN PGP ARMORED FILE-----
Comment: Use "gpg --dearmor" for unpacking

SGVsbG8gd29ybGQh
=s4Gu
-----END PGP ARMORED FILE-----

RFC 4880은 최대 76자 줄을 허용하며, GnuPG는 64자로 씁니다. RFC 9580(2024년 7월)은 형식을 유지하지만 CRC-24 줄은 “생성하지 않는 것이 좋다(SHOULD NOT)“고 하고, 이 줄이 없거나 틀렸다는 이유로 구현이 블록을 거부해서는 안 된다고 말합니다.

Base64 변형 표

변형인덱스 62와 63패딩줄 길이정의된 곳
표준 Base64+ /필수없음RFC 4648, 4절
Base64URL- _선택, 참조하는 명세에 따름없음RFC 4648, 5절
JWS / JWT- _쓰지 않음없음RFC 7515
MIME+ /필수최대 76, CRLFRFC 2045
PEM+ /필수정확히 64RFC 1421, RFC 7468
OpenPGP 아머+ /필수최대 76 (GnuPG: 64)RFC 4880, RFC 9580
UTF-7+ /없음해당 없음RFC 2152
IMAP 수정 UTF-7+ ,없음해당 없음RFC 3501
bcrypt알파벳 ./A-Za-z0-9없음해당 없음사실상 표준 (OpenBSD)
crypt(3) 해시알파벳 ./0-9A-Za-z없음해당 없음사실상 표준 (Unix)

마지막 두 행에서는 알파벳 전체의 순서가 바뀝니다. 이 둘은 알파벳 페이지에서 다룹니다. 다른 많은 형식은 위의 행 중 하나를 아무것도 바꾸지 않고 참조합니다. HTTP Basic 인증(RFC 7617), data URI(RFC 2397), XML Schema의 base64Binary, Subresource Integrity 해시는 모두 패딩이 있는 표준 Base64를 씁니다.

자주 묻는 질문

Base64를 정의하는 RFC는 무엇인가요?

RFC 4648(2006년 10월)이 일반적인 기준입니다. base64, base64url, base32, base32hex, base16을 정의합니다. MIME 버전은 RFC 2045에, PEM의 원래 버전은 RFC 1421에 있습니다.

MIME 줄은 왜 76자이고 PEM 줄은 64자인가요?

두 제한 모두 줄을 SMTP의 1000자 제한보다 훨씬 짧게 유지하기 위한 것입니다. PEM은 RFC 1421에서 64자로 정했고, MIME은 자체 명세에서 “76자 이하"를 택했습니다. RFC 4648은 참조하는 표준이 요구하지 않는 한 인코더가 줄 바꿈을 아예 넣어서는 안 된다고 말합니다.

Base64URL은 공식 표준인가요?

네. RFC 4648의 5절 “Base 64 Encoding with URL and Filename Safe Alphabet"이며, RFC 3548에 처음 등장했습니다. JWS(RFC 7515)는 이를 패딩 없이 씁니다.

PGP 블록 끝의 =XXXX 줄은 무엇인가요?

디코딩된 데이터의 CRC-24 체크섬을 다시 Base64로 쓴 것입니다. RFC 9580(2024)은 새 구현이 이를 출력하지 않는 것이 좋고, 이 줄 때문에 블록을 거부해서는 안 된다고 말합니다.

계속 읽기