C++ 에서 Base64 Encoding / Decoding 방법입니다.
우선 Base64에 대한 위키백과의 설명입니다.
컴퓨터 분야에서 쓰이는 Base 64 (베이스 육십사)란 8비트 이진 데이터(예를 들어 실행 파일이나, ZIP 파일 등)를 문자 코드에 영향을 받지 않는 공통 ASCII 영역의 문자들로만 이루어진 일련의 문자열로 바꾸는 인코딩 방식을 가리키는 개념이다.
원래 Base 64를 글자 그대로 번역하여 보면 64진법이란 뜻이다. 특별히 64진법이 컴퓨터에서 흥미로운 것은, 64가 2의 제곱수(64 = 26)이며, 2의 제곱수들에 기반한 진법들 중에서 화면에 표시되는 ASCII 문자들을 써서 표현할 수 있는 가장 큰 진법이기 때문이다. 즉, 다음 제곱수인 128진법에는 128개의 기호가 필요한데 화면에 표시되는 ASCII 문자들은 128개가 되지 않는다.
그런 까닭에 이 인코딩은 전자 메일을 통한 이진 데이터 전송 등에 많이 쓰이고 있다. Base 64에는 어떤 문자와 기호를 쓰느냐에 따라 여러 변종이 있지만, 잘 알려진 것은 모두 처음 62개는 알파벳 A-Z, a-z와 0-9를 사용하고 있으며 마지막 두 개를 어떤 기호를 쓰느냐의 차이만 있다.
이진 데이터를 다른 플랫폼으로 전송할 때, 다른 플랫폼에서 인코딩 방식에 따라서 누락되는 데이터가 발생할 수 있습니다.
때문에 이를 ASCII로 변환하여 전송한 뒤, 전송받은 플랫폼에서 해당 데이터를 다시 디코딩하는 방식으로 데이터를 안전하게 전송하기 위해 사용하는 방법이 BASE64 입니다.
C에서는 거의 사용되지 않고, Web 과 관련된 분야에서 주로 사용됩니다. 이유는 네트워크 패킷 전송할 때, 이진 데이터 손실이 빈번하게 발생하기 때문입니다.
저는 C base의 기계와 nodejs서버 환경 간 데이터를 주고받는 플랫폼을 개발한 경험이 있어 (Embedded Web Server)이를 개발하는 과정에서 사용하게 되었습니다.
우선 Encoding 소스부터 보겠습니다.
*------ Base64 Encoding Table ------*/
static const char MimeBase64[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
};
int base64_encode(char *text, int numBytes, char **encodedText)
{
unsigned char input[3] = { 0,0,0 };
unsigned char output[4] = { 0,0,0,0 };
int index, i, j, size;
char *p, *plen;
plen = text + numBytes - 1;
size = (4 * (numBytes / 3)) + (numBytes % 3 ? 4 : 0) + 1;
(*encodedText) = (char*)malloc(size);
j = 0;
for (i = 0, p = text; p <= plen; i++, p++) {
index = i % 3;
input[index] = *p;
if (index == 2 || p == plen) {
output[0] = ((input[0] & 0xFC) >> 2);
output[1] = ((input[0] & 0x3) << 4) | ((input[1] & 0xF0) >> 4);
output[2] = ((input[1] & 0xF) << 2) | ((input[2] & 0xC0) >> 6);
output[3] = (input[2] & 0x3F);
(*encodedText)[j++] = MimeBase64[output[0]];
(*encodedText)[j++] = MimeBase64[output[1]];
(*encodedText)[j++] = index == 0 ? '=' : MimeBase64[output[2]];
(*encodedText)[j++] = index < 2 ? '=' : MimeBase64[output[3]];
input[0] = input[1] = input[2] = 0;
}
}
(*encodedText)[j] = '\0';
return size;
}
MimeBase64 :
- Binary -> ASCII로 변환하기 위해 참고하는 Table.
Input Parameter 1 : char *text,
- 여기엔 인코딩할 이진 데이터가 들어있는 문자열 포인터 변수를 넣어준다.
Input Parameter 2 : int numBytes
- 여기엔 인코딩할 이진 데이터가 들어있는 문자열 포인터의 크기를 넣어준다.
Input Parameter 3 : char **encodedText
- 여기엔 인코딩한 문자열이 담길 변수의 주소가 넘어와야 한다.
다음은 Decoding 소스입니다.
/*------ Base64 Decoding Table ------*/
static int DecodeMimeBase64[256] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
};
int base64_decode(char * text, unsigned char * dst, int numBytes)
{
const char* cp;
int space_idx = 0, phase;
int d, prev_d = 0;
unsigned char c;
space_idx = 0;
phase = 0;
for (cp = text; *cp != '\0'; ++cp) {
d = DecodeMimeBase64[(int)*cp];
if (d != -1) {
switch (phase) {
case 0:
++phase;
break;
case 1:
c = ((prev_d << 2) | ((d & 0x30) >> 4));
if (space_idx < numBytes)
dst[space_idx++] = c;
++phase;
break;
case 2:
c = (((prev_d & 0xf) << 4) | ((d & 0x3c) >> 2));
if (space_idx < numBytes)
dst[space_idx++] = c;
++phase;
break;
case 3:
c = (((prev_d & 0x03) << 6) | d);
if (space_idx < numBytes)
dst[space_idx++] = c;
phase = 0;
break;
}
prev_d = d;
}
}
return space_idx;
}
DecodeMimeBase64 :
- ASCII -> Binary 로 변환하기 위해 참고하는 Table.
Input Parameter 1 : char *text,
- 여기엔 디코딩할 문자열 포인터 변수를 넣어준다.
Input Parameter 2 : unsigned char * dst
- 여기엔 디코딩한 결과가 담길 문자열 포인터를 넣어준다.
Input Parameter 3 : int numBytes
- 여기엔 디코딩할 문자열의 길이가 들어간다.
'Dev > [C, C++]' 카테고리의 다른 글
[C,C++] Eliminate Function (문자열 중 특정 문자 찾아서 제거하는 함수) (2) | 2020.03.24 |
---|