Base64 编解码

Base64编码简介

  Base64用来将binary的字节序列数据编码成ASCII字符序列构成的文本。其使用的字符包括大小写字母各26个,加上10个数字,和加号“+”,斜杠“/”,一共64个字符。另外还使用等号“=”用来作为后缀。
  Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。如果剩下的字符不足3个字节,则用0填充,最后的输出字符时使用‘=‘作为结尾,因此编码后输出的文本末尾可能会出现1或2个‘=‘。
  为了保证所输出的编码字符都是可读的,Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64。

Base64编码表
码值    字符    码值    字符    码值    字符    码值    字符
0    A    16    Q    32    g    48    w
1    B    17    R    33    h    49    x
2    C    18    S    34    i    50    y
3    D    19    T    35    j    51    z
4    E    20    U    36    k    52    0
5    F    21    V    37    l    53    1
6    G    22    W    38    m    54    2
7    H    23    X    39    n    55    3
8    I    24    Y    40    o    56    4
9    J    25    Z    41    p    57    5
10    K    26    a    42    q    58    6
11    L    27    b    43    r    59    7
12    M    28    c    44    s    60    8
13    N    29    d    45    t    61    9
14    O    30    e    46    u    62    +
15    P    31    f    47    v    63    /

C++实现

#ifndef __BASE64_UTILS__
#define __BASE64_UTILS__

#include <string>

using std::string;

class Base64Utils
{
public:
    Base64Utils(void);
    ~Base64Utils(void);

    /**
        将一个字节数组中的数据转为一个 base64 格式的数组
    */
    static string Encode(const unsigned char* pEncodeData, int nLength);

    /**
        nLength 为 0 时返回需要 pOutBuffer 需要分配的大小; 否则解码数据, 并存入 pOutBuffer 指向的内存中.
        返回值: 失败时返回0. 否则返回反解码后的字符的个数
    */
    static int Decode(const string& strBase64, unsigned char* pOutBuffer, int nLength);

    /** 解析为一个字符串(由调用者确定解出的字符中不包含‘\0‘才能能调用此函数,否则返回的结果可能不是期望的值) */
    static string DecodeToString(const string& strBase64);

    /** 检查一个字符是否是 base64 编码的字符 */
    static bool CheckBase64(unsigned char bas64Char);

protected:
    template <class T> static T min(T left, T right);
};

#endif __BASE64_UTILS__
#include "Base64Utils.h"

// Base64 编码所用的字符, 其顺序由 base64 协议规定
static const string BASE64_ENCODE_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// 将 ascii 码表中, 对应的 Base64 字符的改成 Base64 字符表中的索引值, 以便解码时进行转行转换
static const unsigned char BASE64_DECODE_TABLE[] =
{
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    62, // ‘+‘
    0, 0, 0,
    63, // ‘/‘
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // ‘0‘-‘9‘
    0, 0, 0, 0, 0, 0, 0,
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // ‘A‘-‘Z‘
    0, 0, 0, 0, 0, 0,
    26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // ‘a‘-‘z‘
};

static const unsigned char BASE64_END_CHARACTER = ‘=‘;

Base64Utils::Base64Utils(void)
{
}

Base64Utils::~Base64Utils(void)
{
}

template <class T> T Base64Utils::min(T left, T right)
{
    return (left < right) ? left : right;
}

bool Base64Utils::CheckBase64(unsigned char bas64Char)
{
    return (BASE64_ENCODE_TABLE.find(bas64Char) != -1) ? true : false;
}

string Base64Utils::Encode(const unsigned char* pEncodeData, int nLength)
{
    string strBase64;

    int i = 0;
    for (; i + 2 < nLength; i += 3)
    {
        strBase64.push_back(BASE64_ENCODE_TABLE.at((pEncodeData[i] >> 2) & 0x3f));
        strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i] & 0x03) << 4) | ((pEncodeData[i + 1] >> 4) & 0x0f)));
        strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i + 1] & 0x0f) << 2) | ((pEncodeData[i + 2] >> 6) & 0x03)));
        strBase64.push_back(BASE64_ENCODE_TABLE.at(pEncodeData[i + 2] & 0x3f));
    }

    if (i < nLength)
    {
        strBase64.push_back(BASE64_ENCODE_TABLE.at((pEncodeData[i] >> 2) & 0x3f));
        if (i + 1 < nLength)
        {
            strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i] & 0x03) << 4) | ((pEncodeData[i + 1] >> 4) & 0x0f)));
            strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i + 1] & 0x0f) << 2)));
        }
        else
        {
            strBase64.push_back(BASE64_ENCODE_TABLE.at(((pEncodeData[i] & 0x03) << 4)));
            strBase64.push_back(BASE64_END_CHARACTER);
        }
        strBase64.push_back(BASE64_END_CHARACTER);
    }

    return strBase64;
}

int Base64Utils::Decode(const string& strBase64, unsigned char* pOutBuffer, int nLength)
{
    nLength = abs(nLength);
    int nBase64 = strBase64.length();
    /** 不符合 base64 字符串长度要求的字符串, 不是 base64 编码格式的字符串, 返回 0 */
    if ((nBase64 == 0) || ((nBase64 % 4) != 0))
    {
        return 0;
    }

    int nNeedSize = nBase64 * 3 / 4;
    if (strBase64.at(nBase64 - 1) == BASE64_END_CHARACTER)
        nNeedSize--;
    if (strBase64.at(nBase64 - 2) == BASE64_END_CHARACTER)
        nNeedSize--;

    if (0 == nLength)
    {
        return nNeedSize;
    }

    nNeedSize = min(nNeedSize, nLength);

    const int nSizeOfDecode = sizeof(BASE64_DECODE_TABLE);
    int index = 0;
    int k = 0;
    unsigned char byteValue;
    unsigned char base64Char;
    unsigned char base64Arr[4] = {0};
    for (int i = 0; i < nBase64; i++)
    {
        base64Char = strBase64.at(i);
        if (base64Char == BASE64_END_CHARACTER) // 遇到结速符
        {
            break;
        }

        /**
            如果 base64字符为编码表中第一个字符, 其解码后值一定为 0
            否则, 到解码表中查找对应的值, 如果找到, 并且值不为 0, 才是符合的 base64 编码的字符.
            如果不是 base64 编码表中的字符, 则解码失败, 设置返回值为 0
        */
        if (base64Char == BASE64_ENCODE_TABLE.at(0))
        {
            byteValue = 0;
        }
        else
        {
            if (base64Char < nSizeOfDecode)
            {
                byteValue = BASE64_DECODE_TABLE[base64Char];
            }
            if (byteValue == 0)
            {
                nNeedSize = 0;
                break;
            }
        }

        base64Arr[k++] = byteValue;

        if (k == 4)
        {
            if (index >= nNeedSize)
                break;
            pOutBuffer[index++] = ((base64Arr[0] & 0x3f) << 2) | ((base64Arr[1] & 0x30) >> 4);
            if (index >= nNeedSize)
                break;
            pOutBuffer[index++] = ((base64Arr[1] & 0x0f) << 4) | ((base64Arr[2] & 0x3c) >> 2);
            if (index >= nNeedSize)
                break;
            pOutBuffer[index++] = ((base64Arr[2] & 0x03) << 6) | ((base64Arr[3] & 0x3f));
            k = 0;
        }
    }

    if ((k != 0) && (index < nNeedSize))
    {
        for (; k < 4; k++)
        {
            base64Arr[k] = 0;
        }
        if (index < nNeedSize)
            pOutBuffer[index++] = ((base64Arr[0] & 0x3f) << 2) | ((base64Arr[1] & 0x30) >> 4);
        if (index < nNeedSize)
            pOutBuffer[index++] = ((base64Arr[1] & 0x0f) << 4) | ((base64Arr[2] & 0x3c) >> 2);
        if (index < nNeedSize)
            pOutBuffer[index++] = ((base64Arr[2] & 0x03) << 6) | ((base64Arr[3] & 0x3f));
    }

    return nNeedSize;
}

string Base64Utils::DecodeToString(const string& strBase64)
{
    string strResult;
    int nSize = Decode(strBase64, NULL, 0);
    if (nSize == 0)
    {
        return strResult;
    }
    unsigned char* pOutBuffer = new unsigned char[nSize + 1];
    if (!pOutBuffer)
    {
        return strResult;
    }
    pOutBuffer[nSize] = 0;
    nSize = Decode(strBase64, pOutBuffer, nSize);
    if (nSize != 0)
    {
        strResult = reinterpret_cast<char*>(pOutBuffer);
    }
    delete[] pOutBuffer;
    pOutBuffer = NULL;
    return strResult;
}

测试代码

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "Base64Utils.h"

int _tmain(int argc, _TCHAR* argv[])
{
    unsigned char pBuffer[] = "[email protected]#$%^&*()_+{}:\"?></.,;‘[]\\";

    //unsigned char pBuffer[] = {‘a‘, ‘b‘, 0, ‘c‘};
    int nCount = sizeof(pBuffer);
    printf("count=%d\n", nCount);
    for (int i = 1; i <= nCount; i++)
    {
        string str(&pBuffer[0], &pBuffer[i]);
        printf("----------  input %d ------------\n", i);
        printf("%s\n", str.c_str());
        string strBase64My = Base64Utils::Encode(pBuffer, i);
        printf("%s\n", strBase64My.c_str());

        int nOutSize = Base64Utils::Decode(strBase64My, NULL, 0);
        printf("need buffer : %d\n", nOutSize);

        //printf("decode:%s\n", Base64Utils::DecodeToString(strBase64My).c_str());

        //if (strBase64My.length() > 2)
        //{
        //    strBase64My.replace(strBase64My.begin() + 2, strBase64My.begin() + 3, 1, ‘,‘);
        //    printf("%s\n", strBase64My.c_str());
        //}

        int j = nOutSize;
        for (; j > 0; j--)
        {
            unsigned char* pOutBuffer = new unsigned char[j + 1];
            memset(pOutBuffer, 0, j + 1);
            //pOutBuffer[j] = 0;
            j = Base64Utils::Decode(strBase64My, pOutBuffer, j);
            printf("[%d]%s\n", j, pOutBuffer);
            delete[] pOutBuffer;
            pOutBuffer = NULL;
        }
    }
    system("pause");
    return 0;
}
时间: 2025-01-01 04:06:52

Base64 编解码的相关文章

openssl命令行Base64编解码

openssl对base64编解码的规范支持较差,用它编解码的结果别的语言如php处理很不方便,注意的几点整理如下 1,如果php加密结果做base64编码长度小于64,则需要添加一个换行符openssl才能解码: 2,php需要对base64编码结果每隔64个字符插入一个换行符,openssl才能解码.(原因是openssl默认bufsize缓冲区大小16k,但是一旦涉及base64的计算缓冲区只有80字节,一旦编码结果超过80字节则会计算失败,base64编解码无法更改缓冲区大小) 示例代码

ios Base64编解码工具类及使用

为了避免明码传递http内容,可以用base64编码后传输,收到方再解码,也方便了2进制数据的字符串式传输. 对于ios来说,google给提供了一个很好的工具类,方便进行base64编解码,当然也可以用openssl来进行,但这东西相对来 说比较麻烦.google给提供了3个文件就够了. 官网地址是: http://code.google.com/p/google-toolbox-for-mac/ 这里面有很多宝贝,如果自己找很难找到这3个文件,所以我加到附件里.解压后放到ios工程中即可使用

Java实现BASE64编解码

Java实现BASE64编解码 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs BASE64和其它类似的编码算法通经常使用于转换二进制数据为文本数据,其目的是为了简化存储或传输.更详细地说,BASE64算法主要用于转换二进制数据为ASCII字符串格式.Java语言提供了一个很好的BASE64算法的实现,即Apache Commons Codec工具包.本文将简要地讲述如何使用BASE64以及它是如何工作的. 以下我们用BASE64对字符串进行编码:

Delphi 自带的 Base64 编解码函数

今天帮别人解决一个关于 Base64 编解码的问题,竟然发现 Delphi 自带了 Base64 编解码的单元,叫 EncdDecd,这名字很拗口而且不直观,估计这是一直很少人关注和知道的原因. 这个单元提供两套四个公开函数: 对流的编解码:procedure EncodeStream(Input, Output: TStream); // 编码procedure DecodeStream(Input, Output: TStream); // 解码 // 对字符串的编解码:function E

Base64编解码Android和ios的例子,补充JNI中的例子

1.在Android中java层提供了工具类:android.util.Base64; 里面都是静态方法,方便直接使用: 使用方法如下: Java代码   // Base64 编码: byte [] encode = Base64.encode("Hello, World".getBytes(), Base64.DEFAULT); String enc = new String(encode); Log.d("","base 64 encode = &qu

Java8 BASE64 编解码

Java一直缺少BASE64编码 API,以至于通常在项目开发中会选用第三方的API实现.但是,Java 8实现了BASE64编解码API,它包含到java.util包.下面我会对Java 8的BASE64 API做一个介绍. java.util.Base64工具类提供了一套静态方法获取下面三种BASE64编解码器: 1)Basic编码 2)URL编码 3)MIME编码 Basic编码是标准的BASE64编码,用于处理常规的需求:输出的内容不添加换行符,而且输出的内容由字母加数字组成.下面是用法

iOS开发网络篇之Base64编解码

郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 如果文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额随意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源码下载:点我传送 游戏官方下载:http://dwz.cn/RwTjl 游戏视频预览:http://dwz.cn/RzHHd 游戏开发博客:http://dwz.cn/RzJzI 游戏源码传送:http://dwz.cn/Nret1 在iPhone开发中很多时候都需要将数据进行Base64编解码. 在一些大项目中,就需要将通过R

BASE64编解码

由于历史原因,Email只被允许传送ASCII字符,即一个8位字节的低7位.这里的历史原因就在于第一封Email是由老美发出,当然字符编码也就只考虑美标ASCII码了.到后来,世界各地的人们都想使用便捷的“伊妹儿”,如果你发送了一封带有非 ASCII字符(即字节的最高位是1)的Email通过有历史问题的网关时就可能会出现问题.网关可能会把最高位置为0,这对于使用2字节或更多字节对文字进行编码的国家而言将不能实现正确的信息交流.为了能够使非美标ASCII编码的国家正常的传送Email,单单靠改变字

Java 8实现BASE64编解码

Java一直缺少BASE64编码 API,以至于通常在项目开发中会选用第三方的API实现.但是,Java 8实现了BASE64编解码API,它包含到java.util包.下面我会对Java 8的BASE64 API做一个介绍. java.util.Base64工具类提供了一套静态方法获取下面三种BASE64编解码器: 1)Basic编码2)URL编码3)MIME编码 Basic编码是标准的BASE64编码,用于处理常规的需求:输出的内容不添加换行符,而且输出的内容由字母加数字组成.下面是用法:

python3的base64编解码

使用python3的base64编解码实现字符串的简易加密解密 引言: 在一些项目中,接口的报文是通过base64加密传输的,所以在进行接口自动化时,需要对所传的参数进行base64编码,对拿到的响应报文进行解码: Base64编码是一种"防君子不防小人"的编码方式.广泛应用于MIME协议,作为电子邮件的传输编码,生成的编码可逆,后一两位可能有"=",生成的编码都是ascii字符.优点:速度快,ascii字符,肉眼不可理解缺点:编码比较长,非常容易被破解,仅适用于加