사용자 도구

사이트 도구


kb:base64encoding

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

kb:base64encoding [2014/11/10 19:50] (현재)
줄 1: 줄 1:
 +====== Base64 Encoding ======
 +MIME과 관련된 곳에서 자주 쓰이는 base64 인코딩/​디코딩 모듈이다. 바이너리를 문자열로,​ 문자열을 바이너리로 변환시켜주는 알고리즘이다. MIME과 관련된 것은 아니지만,​ 암호화와 관련해서 필요할 때가 있는데, Win32에서는 XP에서만 문자열 인코딩 관련 API가 있기 때문에 이렇게 따로 만들게 되었다.
 +
 +
 +====== C++ Implementation ======
 +<file cpp Base64.h>​
 +#ifndef __BASE64_H__
 +#define __BASE64_H__
 +
 +////////////////////////////////////////////////////////////////////////////////​
 +/// \class Base64
 +/// \brief 바이너리 값을 base64로 인코딩하거나,​ 또는 그 반대로 디코딩하는 일과 ​
 +/// 관련된 함수들을 모아놓은 클래스이다. ​
 +///
 +/// 예를 들어 '​ABCD'​라는 스트림은 총 32비트다. 이는 다음과 같이 매핑된다.
 +/// 
 +/// <pre>
 +/// ABCD
 +/// 
 +///  A (65)     B (66)     C (67)     D (68)   ​(None) (None)
 +/// 01000001 ​  ​01000010 ​  ​01000011 ​  ​01000100
 +/// 
 +/// 16 (Q)  20 (U)  9 (J)   3 (D)    17 (R) 0 (A)  NA (=) NA (=)
 +/// 010000 ​ 010100 ​ 001001 ​ 000011 ​  ​010001 000000 000000 000000
 +/// 
 +/// QUJDRA==
 +/// </​pre>​
 +///
 +/// 유닛 테스트를 위한 케이스를 들어보자면 다음과 같다.
 +///  - 빈 문자열 :       ​-> ​         ->
 +///  - 1 글자 ​   :  A    -> QQ==     -> A
 +///  - 2 글자 ​   :  AB   -> QUJD     -> AB
 +///  - 3 글자 ​   :  ABC  -> QUJD     -> ABC
 +///  - 4 글자 ​   :  ABCD -> QUJDRA== -> ABCD
 +////////////////////////////////////////////////////////////////////////////////​
 +
 +class Base64
 +{
 +private:
 +    unsigned char* m_Text; ​      ///<​ NULL로 끝나는 문자열 버퍼
 +    unsigned char* m_Binary; ​    ///<​ 바이너리 버퍼
 +    size_t ​        ​m_binarySize;​ ///< 바이너리 버퍼의 길이
 +
 +
 +public:
 +    /// \brief 생성자
 +    Base64();
 +
 +    /// \brief 소멸자
 +    ~Base64();
 +
 +
 +public:
 +    /// \brief 바이너리를 base64 문자열로 인코딩한다.
 +    const unsigned char* Encode(const unsigned char* binary, size_t binarySize);​
 +
 +    /// \brief base64 문자열을 바이너리로 디코딩한다.
 +    const unsigned char* Decode(const unsigned char* text, size_t& binarySize);​
 +
 +
 +private:
 +    /// \brief 3개의 8비트 바이너리를 4개의 6비트 문자열로 인코딩한다.
 +    void EncodeBlock(unsigned char in[3], unsigned char out[4], int len);
 +
 +    /// \brief 4개의 6비트 문자열을 3개의 8비트 바이너리로 디코딩한다.
 +    void DecodeBlock(unsigned char in[4], unsigned char out[3]);
 +
 +    /// \brief 복사 생성자는 금지
 +    Base64(const Base64&​) {}
 +
 +    /// \brief 대입 연산자는 금지
 +    Base64& operator = (const Base64&​) { return *this; }
 +};
 +
 +#endif //​__BASE64_H__
 +</​file>​
 +
 +<file cpp Base64.cpp>​
 +#include "​Base64.h"​
 +#include <​stdio.h>​
 +#include <​stdlib.h>​
 +#include <​vector>​
 +
 +namespace
 +{
 +    // 인코딩을 위한 테이블 (RFC1113)
 +    const char EncodeTable[] = 
 +        "​ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";​
 +
 +    // 디코딩을 위한 테이블
 +    const char DecodeTable[] = 
 +        "​|$$$}rstuvwxyz{$$$$$$$>?​@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";​
 +}
 +
 +/// \brief 생성자
 +Base64::​Base64()
 +: m_Binary(NULL),​ m_Text(NULL)
 +{
 +}
 +
 +/// \brief 소멸자
 +Base64::​~Base64()
 +{
 +    if (m_Binary != NULL) delete [] m_Binary;
 +    if (m_Text != NULL) delete [] m_Text;
 +}
 +
 +/// \brief 바이너리를 base64 문자열로 인코딩한다.
 +const unsigned char* Base64::​Encode(const unsigned char* binary, size_t binarySize)
 +{
 +    unsigned char in[3];
 +    unsigned char out[4];
 +    int len;
 +    int blocksout = 0;
 +    size_t current = 0;
 +    std::​vector<​unsigned char> intermediate;​
 +
 +    // 인코딩한다.
 +    while (current < binarySize)
 +    {
 +        len = 0;
 +
 +        for (int i = 0; i < 3; i++) 
 +        {
 +            in[i] = binary[current];​
 +            if (current < binarySize)
 +            {
 +                current++;
 +                len++;
 +            }
 +            else
 +            {
 +                in[i] = 0;
 +            }
 +        }
 +
 +        if (len) 
 +        {
 +            EncodeBlock(in,​ out, len);
 +            for (int i = 0; i < 4; i++) 
 +                intermediate.push_back(out[i]);​
 +        }
 +    }
 +
 +    // 벡터에 있는 값을 텍스트 버퍼에 복사하기 이전에,
 +    // 기존의 텍스트 버퍼를 삭제하고,​ 벡터의 크기만큼 메모리를 재할당
 +    if (m_Text != NULL) delete [] m_Text;
 +    m_Text = new unsigned char[intermediate.size()+1];​
 +    memset(m_Text,​ 0, sizeof(unsigned char) * (intermediate.size()+1));​
 +
 +    // 벡터에 있는 내용을 텍스트 버퍼에 복사
 +    for (size_t r=0; r<​intermediate.size();​ r++)
 +        m_Text[r] = intermediate[r];​
 +
 +    return m_Text;
 +}
 +
 +/// \brief base64 문자열을 바이너리로 디코딩한다.
 +const unsigned char* Base64::​Decode(const unsigned char* text, size_t& binarySize)
 +{
 +    unsigned char in[4];
 +    unsigned char out[3];
 +    unsigned char v;
 +    int i;
 +    int len;
 +    size_t current = 0;
 +    std::​vector<​unsigned char> intermediate;​
 +    size_t TextSize = strlen((const char*)text);​
 +
 +    while (current < TextSize) ​
 +    {
 +        for (i = 0, len = 0; i < 4 && current < TextSize; i++) 
 +        {
 +            v = 0;
 +
 +            while (current < TextSize && v == 0) 
 +            {
 +                v = text[current];​
 +                if (current < TextSize)
 +                    current++;
 +
 +                v = (unsigned char) ((v < 43 || v > 122) ? 0 : DecodeTable[v - 43]);
 +                if (v) { v = (unsigned char) ((v == '​$'​) ? 0 : v - 61); }
 +            }
 +
 +            if (current < TextSize) ​
 +            {
 +                len++;
 +                if (v) { in[i] = (unsigned char) (v - 1); }
 +            }
 +            else 
 +            {
 +                in[i] = 0;
 +            }
 +        }
 +
 +        if (len) 
 +        {
 +            DecodeBlock(in,​ out);
 +            for (i = 0; i < len - 1; i++) 
 +                intermediate.push_back(out[i]);​
 +        }
 +    }
 +
 +    // 중간 버퍼에 있는 값을 바이너리 버퍼로 옮겨야한다.
 +    // 기존의 바이너리 버퍼를 삭제하고,​ 벡터의 크기만큼 메모리를 재할당
 +    // 서비스로 +1 크기만큼의 버퍼를 만들어 끝에다 0을 집어넣어준다.
 +    if (m_Binary != NULL) delete [] m_Binary;
 +    m_Binary = new unsigned char[intermediate.size()+1];​
 +    memset(m_Binary,​ 0, sizeof(unsigned char) * (intermediate.size()+1));​
 +
 +    // 벡터에 있는 내용을 바이너리 버퍼에 복사
 +    for (size_t r=0; r<​intermediate.size();​ r++)
 +        m_Binary[r] = intermediate[r];​
 +
 +    // 사이즈 변수를 세팅
 +    binarySize = intermediate.size();​
 +
 +    return m_Binary;
 +}
 +
 +/// \brief 3개의 8비트 바이너리를 4개의 6비트 문자열로 인코딩한다.
 +void Base64::​EncodeBlock(unsigned char in[3], unsigned char out[4], int len)
 +{
 +    out[0] = EncodeTable[in[0] >> 2];
 +    out[1] = EncodeTable[((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)];
 +    out[2] = (unsigned char) (len > 1 ? EncodeTable[((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)] : '​='​);​
 +    out[3] = (unsigned char) (len > 2 ? EncodeTable[in[2] & 0x3f] : '​='​);​
 +}
 +
 +/// \brief 4개의 6비트 문자열을 3개의 8비트 바이너리로 디코딩한다.
 +void Base64::​DecodeBlock(unsigned char in[4], unsigned char out[3])
 +{
 +    out[0] = (unsigned char) (in[0] << 2 | in[1] >> 4);
 +    out[1] = (unsigned char) (in[1] << 4 | in[2] >> 2);
 +    out[2] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
 +}
 +</​file>​
 +
 +====== 링크 ======
 +  * [[http://​en.wikipedia.org/​wiki/​Base64 | Base64 on Wikipedia]]
 +----
 +  * see also [[Cryptography]]
  
kb/base64encoding.txt · 마지막으로 수정됨: 2014/11/10 19:50 (바깥 편집)