알고리즘

Base64

uzguns 2024. 11. 22. 09:28

Base64, Base32, Base16은 바이너리 데이터를 텍스트 데이터로 인코딩하는 표준 방식으로, 바이너리 데이터를 안전하게 전송하거나 저장하기 위해 사용된다. 이는 주로 이메일, URL, 또는 파일 저장 시 인코딩에 사용된다.

 

Base64 는 64종류의 문자를 이용하기 때문에 인코딩 후에는 1문자당 6bit(64=2^6) 의 정보를 가진다.

  • Base64: 64개의 문자 (A–Z, a–z, 0–9, +, /) → 6bit
  • Base32: 32개의 문자 (A–Z, 2–7) → 5bit
    • 숫자 2–7을 사용하는 이유는 혼동을 피하기 위해 (0과 O, 1과 I 구분)
  • Base16: 16개의 문자 (0–9, A–F) → 4bit
특성 Base64 Base32 Base16
사용 문자 수 64 (A–Z, a–z, 0–9, +, /) 32 (A–Z, 2–7) 16 (0–9, A–F)
비트 처리 단위 6비트 5비트 4비트
출력 증가율 약 33% 증가 약 60% 증가 100% 증가
패딩 문자 = = 없음
목적 압축된 텍스트 변환 사람이 구분하기 쉬운 텍스트 간단한 텍스트 변환
주요 사용 사례 이메일(MIME), jwt, 웹 전송, url data QR 코드, 사람 읽기 가능 환경 디버깅, 해시값 출력

Base64 특징

     Value Encoding  Value Encoding  Value Encoding  Value Encoding
         0 A            17 R            34 i            51 z
         1 B            18 S            35 j            52 0
         2 C            19 T            36 k            53 1
         3 D            20 U            37 l            54 2
         4 E            21 V            38 m            55 3
         5 F            22 W            39 n            56 4
         6 G            23 X            40 o            57 5
         7 H            24 Y            41 p            58 6
         8 I            25 Z            42 q            59 7
         9 J            26 a            43 r            60 8
        10 K            27 b            44 s            61 9
        11 L            28 c            45 t            62 +
        12 M            29 d            46 u            63 /
        13 N            30 e            47 v
        14 O            31 f            48 w         (pad) =
        15 P            32 g            49 x
        16 Q            33 h            50 y
  • 64개의 문자와 패딩 문자 '=' 사용:
    • Base64는 ASCII 문자 65개를 사용
      • 대문자: A–Z (0–25)
      • 소문자: a–z (26–51)
      • 숫자: 0–9 (52–61)
      • 특수 문자: + (62), / (63)
      • 패딩 문자: = (부족한 데이터 채우기)
  • 6비트 단위로 처리:
    • 데이터를 6비트 단위로 나누어 각 6비트를 Base64 문자로 변환.
    • 입력 데이터는 24비트(3바이트) 단위로 처리됨.
    • 3바이트(24비트) → 4문자(6비트 × 4)로 인코딩.
  • 패딩 처리:
    • 입력 데이터의 길이가 3의 배수가 아닐 경우:
      • 부족한 비트를 0으로 채운 뒤 결과에 = 문자 추가.
      • 예: 입력이 1바이트일 경우 ==, 2바이트일 경우 = 추가.
  • 결과 문자열은 항상 4의 배수 길이:
    • 패딩(=)으로 결과 문자열의 길이를 4의 배수로 맞춤.

 

Base64 인코딩 과정

#include <iostream>
#include <string>
using namespace std;

// Base64 문자 테이블
const string base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

string encodeBase64(const string& input) {
    string encoded;
    int val = 0, valBits = 0; // 비트 값을 저장할 변수와 누적 비트 길이
    const int paddingBits = 6; // Base64는 6비트 단위로 처리

    for (unsigned char c : input) {
        val = (val << 8) | c; // 기존 비트를 8칸 왼쪽으로 밀고 새로운 비트를 추가
        valBits += 8;         // 현재 비트 길이 누적

        while (valBits >= paddingBits) { // 6비트 단위로 처리
            encoded += base64Chars[(val >> (valBits - paddingBits)) & 0x3F]; // 상위 6비트를 추출
            valBits -= paddingBits; // 처리된 비트 길이를 감소
        }
    }

    if (valBits > 0) { // 남은 비트를 처리 (패딩 필요)
        encoded += base64Chars[(val << (paddingBits - valBits)) & 0x3F]; // 남은 비트를 왼쪽으로 밀고 추가
    }

    // 패딩 문자 '=' 추가
    while (encoded.size() % 4 != 0) {
        encoded += '=';
    }

    return encoded;
}

int main() {
    string input;
    cout << "Enter the string to encode: ";
    getline(cin, input);

    string encoded = encodeBase64(input);
    cout << "Encoded Base64: " << encoded << "\n";

    return 0;
}
  1. 입력 데이터를 3바이트 단위로 읽음.
  2. 3바이트를 24비트로 결합.
  3. 이 24비트를 6비트씩 4개의 그룹으로 나눔.
  4. 각 6비트를 Base64 문자로 변환하여 결과 문자열에 추가.
  5. 부족한 데이터는 0으로 채우고, =로 패딩 처리.

 

Base64 디코딩 과정

#include <iostream>
#include <string>
#include <map>
#include <algorithm> // reverse 함수 사용
using namespace std;

// Base64 문자 → 값 매핑을 저장할 전역 변수
map<char, int> base64Map;

// 24비트 데이터를 입력받아 8비트 단위로 문자열로 변환하는 함수
string decode24BitTo8Bit(int data) {
    string decoded;
    for (int i = 16; i >= 0; i -= 8) { // 24비트를 8비트 단위로 분리
        char byte = (data >> i) & 0xFF; // 상위 8비트를 추출
        if (byte != 0) decoded += byte; // 유효한 값만 추가
    }
    return decoded;
}

// Base64 디코딩 함수
string decodeBase64(const string& input) {
    string result;
    int data = 0, charCount = 0;

    for (char ch : input) {
        if (ch == '=') continue; // Padding 문자 무시
        data = (data << 6) | base64Map[ch]; // 6비트씩 이동 후 추가
        charCount++;

        if (charCount == 4) { // 4문자(24비트) 단위로 처리
            result += decode24BitTo8Bit(data);
            data = 0;          // 다음 24비트를 위해 초기화
            charCount = 0;     // 문자 카운터 초기화
        }
    }

    return result;
}

int main() {
    // Base64 문자 → 값 매핑 초기화
    for (char i = 'A'; i <= 'Z'; i++) base64Map[i] = i - 'A';       // A-Z: 0-25
    for (char i = 'a'; i <= 'z'; i++) base64Map[i] = i - 'a' + 26;  // a-z: 26-51
    for (char i = '0'; i <= '9'; i++) base64Map[i] = i - '0' + 52;  // 0-9: 52-61
    base64Map['+'] = 62;
    base64Map['/'] = 63;

    // 입력받은 Base64 문자열 디코딩
    string input;
    cin >> input;

    string decoded = decodeBase64(input);
    cout << decoded << "\n";

    return 0;
}
  1. 4문자 단위로 처리:
    • Base64 문자열을 읽어 6비트 값으로 변환.
  2. 24비트 복원:
    • 변환된 6비트 값들을 다시 결합하여 24비트(3바이트) 복원.
  3. 패딩 무시:
    • = 문자는 디코딩 과정에서 무시되며, 복원된 바이트 수에 따라 결과를 생성.

 

Base64 URL 및 파일 이름 Safe Alphabet

  • Base64를 URL 및 파일 이름에서 안전하게 사용할 수 있도록 변형한 버전.
  • 일반 Base64와 동일하나, 일부 문자를 대체:
    • + → -
    • / → _
  • 패딩 문자 =는 URL에서 퍼센트 인코딩(%3D)이 필요하므로 생략 가능.

 

References