발전하는 춘배

Base64 encoding과 Hex encoding 방식, 인코딩 아웃풋의 크기 본문

CS

Base64 encoding과 Hex encoding 방식, 인코딩 아웃풋의 크기

춘배0 2024. 8. 29. 13:56

개요

프로젝트를 진행하던 중, `crypto.randomBytes(64).toString("base64");` 로 생성한 salt를 mysql 데이터베이스의 CHAR(64)에 insesrt하려 했더니 Data too long for column 'salt'라면서 에러가 났다. chat-gpt에게 원인을 물어보니 다음과 같았다.

  1. `crypto.randomBytes(64)`는 64 바이트의 랜덤 데이터를 생성한다.
  2. 바이트 데이터를 base64로 인코딩하면, 일반적으로 인코딩된 문자열의 길이는 원본 데이터 크기의 약 1.33배가 된다.
  3. 따라서, 64 바이트의 데이터를 base64로 인코딩하면, 결과 문자열의 길이는 약 86자(ceil(64 * 4 / 3) = 86)가 된다.
  4. CHAR(64)는 최대 64자의 문자열만 저장할 수 있으므로, 86자의 문자열을 저장하려 할 때 길이 초과로 인해 오류가 발생한다.

그래서 salt를 CHAR(86)로 바꾸어 주었는데도 같은 에러가 나타나서 알아 보았더니, 다음과 같은 추가 사항이 있었다.

  1. base64인코딩은 항상 4의 배수로 패딩되므로 패딩 문자 ==이 추가되어 88자의 문자열이 된다.

그래서 CHAR(88)로 설정했더니 데이터가 딱 맞게 들어가서 해결되었다.

이 과정에서 Base64의 인코딩 방식이 어떻길래 1.33배가 되는 지 궁금해졌고, 다른 인코딩 옵션이었던 Hex 방식과의 차이가 궁금해져서 정리해보고자 한다.


Base64 Encoding

Base64 인코딩은 다음과 같은 과정을 거친다.

  1. 3바이트(= 24비트) 단위로 데이터 분할
    • 24비트 버퍼에 한 바이트씩 세 바이트를 넣는다.
    • 총 바이트가 모자라서 버퍼에 세 바이트가 들어가지 않은 경우 버퍼의 남은 부분을 패딩 비트 0으로 채워넣는다.
  2. 6비트 단위로 쪼개기
    • 버퍼에 있는 24비트를 4개의 6비트 조각으로 나눈다.
  3. 인코딩
    • 각 6비트 조각을 Base64 인코딩 표를 사용해 문자로 변환한다.
    • 6비트는 2^6 = 64가지의 정보를 담을 수 있으므로 인코딩 표에는 64개의 문자(A-Z, a-z, 0-9, +, /)가 정의되어 있다.
    • 버퍼에 입력된 바이트가 하나라면 출력 중 두 개의 바이트만 사용되고 ==의 패딩 문자가 생긴다.
    • 버퍼에 입력된 바이트가 둘이라면 출력 중 세 개의 바이트만 사용되고 =의 패딩 문자가 생긴다.
  4. 결과
    • 3바이트의 원본 데이터가 Base64 인코딩을 거치면 4개의 문자로 변환된다.
    • 즉 3바이트는 4바이트로 인코딩된다.

이러한 이유로 Base64 Encoding 시 원본 데이터의 4/3배 크기로 인코딩 되며, 패딩 문자에 의해 최종 바이트는 항상 4의 배수가 된다.


Hex Encoding

Hex는 16진수를 의미한다. 즉 4비트 단위로 인코딩이 이루어진다.

  1. 4비트 단위로 쪼개기
    • 원본 바이너리 데이터를 4비트씩 쪼갠다.
  2. 인코딩
    • 4비트는 2^4 = 16가지의 정보를 담을 수 있으므로 0~9, A~F로 변환한다.
  3. 결과
    • 4비트가 1바이트(= 8비트)의 문자로 변환된다.

따라서 Hex 인코딩을 거치면 크기는 원본 데이터의 2배가 된다.


참고 자료

Base64 인코딩 1

Base64 인코딩 2

Hex 인코딩

반응형