◈ 이 글은 강의를 위하여 제가 직접 작성한 내용입니다. 따라서 퍼가실 경우, 출처를 명확히 해주시기 바랍니다!!
◈ This ariticle was written by me for teaching. So if you want to copy this article, please clarify the source!!
◈ This ariticle was written by me for teaching. So if you want to copy this article, please clarify the source!!
BASE64란? 바이너리 데이터를 텍스트로 표현하기 위한 표현법.
기본원리: 바이너리 데이터를 3bytes(24bits)단위로 나눈 후, 6bits씩 쪼개서 4bytes로 변환을 한다.
=> 바이너리 데이터는 1byte가 8bit이기 때문에 이를 문자로 표현하면 특수기호를 포함해서 사람이 알아볼 수 없는 형태가 된다.
하지만 이를 1byte가 6bit인 base64로 바꾸게 되면, 문자로 표현할 경우, 알파벳과 숫자, 그리고 +, / 만으로 모두 표현할 수 있게 된다.
(전체 64개의 문자 + 패드문자 =, 합해서 총 65개의 문자로 표현하게 된다.)
이는 공백과 같은 특수문자를 token으로 사용하여 전송하는 곳에서 데이터를 온전하게 전송하기 위해 사용된다.
주된 사용처 : 이메일에서의 첨부파일전송.
기본원리: 바이너리 데이터를 3bytes(24bits)단위로 나눈 후, 6bits씩 쪼개서 4bytes로 변환을 한다.
=> 바이너리 데이터는 1byte가 8bit이기 때문에 이를 문자로 표현하면 특수기호를 포함해서 사람이 알아볼 수 없는 형태가 된다.
하지만 이를 1byte가 6bit인 base64로 바꾸게 되면, 문자로 표현할 경우, 알파벳과 숫자, 그리고 +, / 만으로 모두 표현할 수 있게 된다.
(전체 64개의 문자 + 패드문자 =, 합해서 총 65개의 문자로 표현하게 된다.)
이는 공백과 같은 특수문자를 token으로 사용하여 전송하는 곳에서 데이터를 온전하게 전송하기 위해 사용된다.
주된 사용처 : 이메일에서의 첨부파일전송.
우선 하나의 변수에서 비트별로 데이터를 쪼개서 사용하는 방법을 알아보자.
// 데이터 비트 쪼개기. #includeusing namespace std; void main( ) { int num; // 오른쪽 16비트에 100 저장하기. num = (num&0xffff0000) + (100&0xffff); // 왼쪽 16비트에 200 저장하기. num = (num&0xffff) | ((200&0xffff) << 16); // 오른쪽 16비트의 값 꺼내오기. int right = num & 0xffff; // 왼쪽 16비트의 값 꺼내오기. int left = (num >> 16) & 0xffff; cout << num << endl; cout << right << endl; cout << left << endl; // origin의 왼쪽 6비트를 dd의 오른쪽 6비트로 복사하시오. char origin = 250; // 11111010 char copy = (origin>>2)&0x3f; // 00111110 -> 62 // origin의 최상위비트가 1이므로 오른쪽 쉬프트를 하면 1이 채워진다. // 그러므로 & 0x3f를 하지않으면 원하는 결과가 나오지 않는다. cout << (int)copy << endl; // copy의 4,5번째 비트의 값을 꺼내서 출력. char res = (copy & (3<<3)) >> 3; // 00111110 & 00011000 cout << (int)res << endl; }
위의 내용을 기반으로 BASE64에 대한 코드를 작성한다.
// BASE64란? 바이너리 데이터를 텍스트로 표현하기 위한 표현법. // 기본원리: 바이너리 데이터를 3bytes(24bits)단위로 나눈 후, 6bits씩 쪼개서 4bytes로 변환을 한다. // 바이너리 데이터는 1byte가 8bit이기 때문에 이를 문자로 표현하면 특수기호를 포함해서 // 사람이 알아볼 수 없는 형태가 된다. 하지만 이를 1byte가 6bit인 base64로 바꾸게 되면, // 문자로 표현할 경우, 알파벳과 숫자, 그리고 +, / 만으로 모두 표현할 수 있게 된다. // (전체 64개의 문자 + 패드문자 =, 합해서 총 65개의 문자로 표현하게 된다.) // 이는 공백과 같은 특수문자를 token으로 사용하여 전송하는 곳에서 데이터를 온전하게 전송하기 위해 사용된다. // 주된 사용처 : 이메일에서의 첨부파일전송. // >> Encode Routine. // 11001100 10101010 00100101, 11011010 10011001 // 110011/00 1010/1010 00/100101/, 110110/10 1001/1001 // 00110011 00001010 00101000 00100101, 00110110 00101001 00100100 PAD // 51 10 40 37 54 41 36 = // 11001100 10101010 00100101, 11011010 // 110011/00 1010/1010 00/100101/, 110110/10 // 00110011 00001010 00101000 00100101, 00110110 00100000 PAD PAD // 51 10 40 37 54 32 = = #include#include using namespace std; #define MAX_CHAR 1024 #define BIT_6 0x3F #define BIT_4 0x0F #define BIT_2 0x03 #define PAD 64 const char BASE64TABLE[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; long BASE64RTABLE(char ch) { int base64length = strlen(BASE64TABLE); for(int i=0; i < base64length; i++) { if(ch == BASE64TABLE[i]) { if(i == PAD) return 0; else return i; } } return -1; } long Base64EncodeSize(char* str); long Base64DecodeSize(char* str); void Base64Encode(char* src, char* dest, int countofdest); void Base64Decode(char* src, char* dest, int countofdest); void main() { char origin[MAX_CHAR]; char* encode = NULL; char* decode = NULL; cout << "인코딩할 문자열을 입력하십시오." << endl; cin.getline(origin, _countof(origin)); int encode_size = Base64EncodeSize(origin); encode = new char[encode_size]; Base64Encode(origin, encode, encode_size); cout << "[인코딩된 문자열]" << endl; cout << encode << endl; int decode_size = Base64DecodeSize(encode); decode = new char[decode_size]; Base64Decode(encode, decode, decode_size); cout << "[디코딩된 문자열]" << endl; cout << decode << endl; delete [] encode; delete [] decode; system("PAUSE"); } long Base64EncodeSize( char* str ) { float size = strlen(str)*sizeof(char)/3.0f; if(size > (int)size) size = int(size)+1.0f; return long(size*4 + 1); // +1 : null 문자를 위해 추가. } long Base64DecodeSize( char* str ) { float size = strlen(str)*sizeof(char)/4.0f; // base64 텍스트는 4로 나누어 떨어져야 한다. assert((size == (int)size) && "invalid base64 encoded text."); return ((int)size*3 + 1); // +1 : null 문자를 위해 추가. } void Base64Encode( char* src, char* dest, int countofdest ) { int need_size = Base64EncodeSize(src); assert(countofdest >= need_size && "dest buffer size is too small."); int src_size = strlen(src); int count = 0; // 현재까지 인코딩한 바이트 수. int idx = 0; // dest 배열 인덱스. while( src_size - count >= 3 ) // src_size - count : 남은 바이트 수. { char* start = src+count; // 인코딩을 시작할 위치. char i = 0; // [0]12345678 -> 00123456 i = ((start[0] >> 2) & BIT_6); dest[idx++] = BASE64TABLE[i]; // [0]12345678 -> 00000078 -> 00780000 + [1]12345678 -> 00001234 = 00781234 i = ((start[0] & BIT_2) << 4) + ((start[1] >> 4) & BIT_4); dest[idx++] = BASE64TABLE[i]; // [1]12345678 -> 00005678 -> 00567800 + [2]12345678 -> 00000012 = 00567812 i = ((start[1] & BIT_4) << 2) + ((start[2] >> 6) & BIT_2); dest[idx++] = BASE64TABLE[i]; // [2]12345678 -> 00345678 i = (start[2] & BIT_6); dest[idx++] = BASE64TABLE[i]; count += 3; // 인코딩한 바이트 수 증가. } // 원본 데이터가 3바이트로 나누어 떨어지지 않을 경우, if(src_size - count > 0) { char* start = src+count; char i = 0; // 1바이트가 남았거나 2바이트가 남았거나 둘 다 맨 앞의 6비트는 꺼내올 수 있다. i = ((start[0] >> 2) & BIT_6); dest[idx++] = BASE64TABLE[i]; // 2바이트가 남은 경우, if( src_size - count == 2 ) { i = ((start[0] & BIT_2) << 4) + ((start[1] >> 4) & BIT_4); dest[idx++] = BASE64TABLE[i]; i = ((start[1] & BIT_4) << 2); dest[idx++] = BASE64TABLE[i]; dest[idx++] = BASE64TABLE[PAD]; } // 1바이트가 남은 경우, else { i = ((start[0] & BIT_2) << 4); dest[idx++] = BASE64TABLE[i]; dest[idx++] = BASE64TABLE[PAD]; dest[idx++] = BASE64TABLE[PAD]; } } dest[idx] = '\0'; } void Base64Decode( char* src, char* dest, int countofdest ) { int need_size = Base64DecodeSize(src); assert(countofdest >= need_size && "dest buffer size is too small."); int src_size = strlen(src); int count = 0; // 현재까지 디코딩한 바이트 int idx = 0; // dest 배열 인덱스. while( src_size - count > 0 ) { char* start = src+count; int v1 = BASE64RTABLE(start[0]); int v2 = BASE64RTABLE(start[1]); int v3 = BASE64RTABLE(start[2]); int v4 = BASE64RTABLE(start[3]); // [v1]00123456 -> 12345600 + [v2]00123456 -> 00000012 = 12345612 dest[idx++] = (v1 << 2) + (v2 >> 4); // [v2]00123456 -> 34560000 + [v3]00123456 -> 00001234 = 34561234 dest[idx++] = (v2 << 4) + (v3 >> 2); // [v3]00123456 -> 56000000 + [v4]00123456 = 56123456 dest[idx++] = (v3 << 6) + v4; count += 4; } dest[idx] = '\0'; }