关于base64 编解码的一点疑惑?

硬汉无敌 2018-06-20 10:55:21
大家都知道base64 编码过程是一个 3B 的数据转换成4B数据的过程。
例子
字符串 “123”
16进制编码 0x313233
2进制编码 0011 0001 0011 0010 0011 0011

之后将上面的二进制编码6个搞成1组

处理后的二进制编码 001100 010011 001000 110011
对照base64 编码表
最终base64编码结果 MTIz

OK,现在我的问题是假设字符串是 "1234"(字节数不是3的倍数), 在我们进行分析时,拿到的二进制编码是32bit, 并不是6的倍数,这个时候可以拿到5组base64数据, 还有余下的2bit数据。base64最终的编码结果是 ”MTIzNA==“, 我就想问一下这个最终的编码结果是怎么来的?余下的2bit它做了怎么样的处理?为什么要加2个 ”=“号, 作为后缀, 有什么样的意义呢?


...全文
470 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
硬汉无敌 2018-06-26
  • 打赏
  • 举报
回复
[quote=引用 6 楼 jha334201553 的回复:]
二进制数据是同样的道理呀。假设经过base64编码的就是一个长度为6的字符串(去掉 = ), 同样是6 * 6 bit数据。 经过移位处理,得到4 *8bit + 4bit
数据,我们按照标准算法,就是丢掉那4bit的数据。 这4bit是 36 %8 算出来的,跟二进制数据有00结尾的有什么关系呢?
「已注销」 2018-06-22
  • 打赏
  • 举报
回复
引用 4 楼 weixin_40810615 的回复:
赵四老师,能不能谈谈你的理解,不要一言不和就贴代码!我认为“1234” 和“12345”base64的编码,加不加等号,都可以把原始数据解出来。
“MTIzNA” 这个(去掉 =的)base64编码, 一共有6 * 6bit数据, 我们经过移位处理后,会得到 4B (4 * 8bit)数据。 还有剩余4bit,我们直接扔掉。就会把原始数据解出来。 “MTIzNDU”也是类似。那还加什么等号呢?
因为你编码的是字符串,如果编码二进制数据呢,里面有00结尾数据,解码出来全删掉吗?
donjin9 2018-06-22
  • 打赏
  • 举报
回复
不用补也能用,一般也支持的。
补了对齐呗
硬汉无敌 2018-06-22
  • 打赏
  • 举报
回复
赵四老师,能不能谈谈你的理解,不要一言不和就贴代码!我认为“1234” 和“12345”base64的编码,加不加等号,都可以把原始数据解出来。
“MTIzNA” 这个(去掉 =的)base64编码, 一共有6 * 6bit数据, 我们经过移位处理后,会得到 4B (4 * 8bit)数据。 还有剩余4bit,我们直接扔掉。就会把原始数据解出来。 “MTIzNDU”也是类似。那还加什么等号呢?
「已注销」 2018-06-21
  • 打赏
  • 举报
回复
=是补0的字节数,比如“1234”(4+2)*8 = 48 = 6*8 ,也就是"1234\0\0" 补充2字节的\0,等这个编码完成在最后 加 == ,以表示最后的两个\0是对齐补充的,解码的时候根据=个数再去掉末尾的\0
赵4老师 2018-06-20
  • 打赏
  • 举报
回复
仅供参考:
#pragma comment(lib,"crypt32")
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

//+-------------------------------------------------------------------------
// convert formatted string to binary
// If cchString is 0, then pszString is NULL terminated and
// cchString is obtained via strlen() + 1.
// dwFlags defines string format
// if pbBinary is NULL, *pcbBinary returns the size of required memory
// *pdwSkip returns the character count of skipped strings, optional
// *pdwFlags returns the actual format used in the conversion, optional
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptStringToBinaryA(
    IN     LPCSTR  pszString,
    IN     DWORD     cchString,
    IN     DWORD     dwFlags,
    IN     BYTE     *pbBinary,
    IN OUT DWORD    *pcbBinary,
    OUT    DWORD    *pdwSkip,    //OPTIONAL
    OUT    DWORD    *pdwFlags    //OPTIONAL
    );
//+-------------------------------------------------------------------------
// convert formatted string to binary
// If cchString is 0, then pszString is NULL terminated and
// cchString is obtained via strlen() + 1.
// dwFlags defines string format
// if pbBinary is NULL, *pcbBinary returns the size of required memory
// *pdwSkip returns the character count of skipped strings, optional
// *pdwFlags returns the actual format used in the conversion, optional
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptStringToBinaryW(
    IN     LPCWSTR  pszString,
    IN     DWORD     cchString,
    IN     DWORD     dwFlags,
    IN     BYTE     *pbBinary,
    IN OUT DWORD    *pcbBinary,
    OUT    DWORD    *pdwSkip,    //OPTIONAL
    OUT    DWORD    *pdwFlags    //OPTIONAL
    );
#ifdef UNICODE
#define CryptStringToBinary  CryptStringToBinaryW
#else
#define CryptStringToBinary  CryptStringToBinaryA
#endif // !UNICODE

//+-------------------------------------------------------------------------
// convert binary to formatted string
// dwFlags defines string format
// if pszString is NULL, *pcchString returns the size of required memory in byte
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptBinaryToStringA(
    IN     CONST BYTE  *pbBinary,
    IN     DWORD        cbBinary,
    IN     DWORD        dwFlags,
    IN     LPSTR      pszString,
    IN OUT DWORD       *pcchString
    );
//+-------------------------------------------------------------------------
// convert binary to formatted string
// dwFlags defines string format
// if pszString is NULL, *pcchString returns the size of required memory in byte
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptBinaryToStringW(
    IN     CONST BYTE  *pbBinary,
    IN     DWORD        cbBinary,
    IN     DWORD        dwFlags,
    IN     LPWSTR      pszString,
    IN OUT DWORD       *pcchString
    );
#ifdef UNICODE
#define CryptBinaryToString  CryptBinaryToStringW
#else
#define CryptBinaryToString  CryptBinaryToStringA
#endif // !UNICODE

// dwFlags has the following defines
#define CRYPT_STRING_BASE64HEADER           0x00000000
#define CRYPT_STRING_BASE64                 0x00000001
#define CRYPT_STRING_BINARY                 0x00000002
#define CRYPT_STRING_BASE64REQUESTHEADER    0x00000003
#define CRYPT_STRING_HEX                    0x00000004
#define CRYPT_STRING_HEXASCII               0x00000005
#define CRYPT_STRING_BASE64_ANY             0x00000006
#define CRYPT_STRING_ANY                    0x00000007
#define CRYPT_STRING_HEX_ANY                0x00000008
#define CRYPT_STRING_BASE64X509CRLHEADER    0x00000009
#define CRYPT_STRING_HEXADDR                0x0000000a
#define CRYPT_STRING_HEXASCIIADDR           0x0000000b

#define CRYPT_STRING_NOCR                   0x80000000

// CryptBinaryToString uses the following flags
// CRYPT_STRING_BASE64HEADER - base64 format with certificate begin
//                             and end headers
// CRYPT_STRING_BASE64 - only base64 without headers
// CRYPT_STRING_BINARY - pure binary copy
// CRYPT_STRING_BASE64REQUESTHEADER - base64 format with request begin
//                                    and end headers
// CRYPT_STRING_BASE64X509CRLHEADER - base64 format with x509 crl begin
//                                    and end headers
// CRYPT_STRING_HEX - only hex format
// CRYPT_STRING_HEXASCII - hex format with ascii char display
// CRYPT_STRING_HEXADDR - hex format with address display
// CRYPT_STRING_HEXASCIIADDR - hex format with ascii char and address display
//
// CryptBinaryToString accepts CRYPT_STRING_NOCR or'd into one of the above.
// When set, line breaks contain only LF, instead of CR-LF pairs.

// CryptStringToBinary uses the following flags
// CRYPT_STRING_BASE64_ANY tries the following, in order:
//    CRYPT_STRING_BASE64HEADER
//    CRYPT_STRING_BASE64
// CRYPT_STRING_ANY tries the following, in order:
//    CRYPT_STRING_BASE64_ANY
//    CRYPT_STRING_BINARY -- should always succeed
// CRYPT_STRING_HEX_ANY tries the following, in order:
//    CRYPT_STRING_HEXADDR
//    CRYPT_STRING_HEXASCIIADDR
//    CRYPT_STRING_HEXASCII
//    CRYPT_STRING_HEX


char *flags[12]={
"CRYPT_STRING_BASE64HEADER",
"CRYPT_STRING_BASE64",
"CRYPT_STRING_BINARY",
"CRYPT_STRING_BASE64REQUESTHEADER",
"CRYPT_STRING_HEX",
"CRYPT_STRING_HEXASCII",
"CRYPT_STRING_BASE64_ANY",
"CRYPT_STRING_ANY",
"CRYPT_STRING_HEX_ANY",
"CRYPT_STRING_BASE64X509CRLHEADER",
"CRYPT_STRING_HEXADDR",
"CRYPT_STRING_HEXASCIIADDR",
};
#define MAXC 1024
BYTE b[22]={
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0x41,0x42,0xB0,0xA1,0x4A,0x55,
};
BOOL r;
DWORD len,dwFlags;
TCHAR s[MAXC];
int _tmain() {
    _tprintf(_T("API CryptBinaryToString in crypt32.dll Demonstration:\n"));
    for (dwFlags=0;dwFlags<12;dwFlags++) {
        if (dwFlags==2
         || dwFlags==6
         || dwFlags==7
         || dwFlags==8) continue;
        r=CryptBinaryToString(b,22,dwFlags,NULL,&len);
        if (!r) {
            _tprintf(_T("CryptBinaryToString error!\n"));
            return 1;
        }
        if (len>MAXC) {
            _tprintf(_T("%d==len>MAXC==%d!\n"),len,MAXC);
            return 2;
        }
        r=CryptBinaryToString(b,22,dwFlags,s,&len);
        if (!r) {
            _tprintf(_T("CryptBinaryToString error!\n"));
            return 3;
        }
        _tprintf(_T("\n%s:[\n%s]\n"),flags[dwFlags],s);
    }
    return 0;
}
//API CryptBinaryToString in crypt32.dll Demonstration:
//
//CRYPT_STRING_BASE64HEADER:[
//-----BEGIN CERTIFICATE-----
//AAECAwQFBgcICQoLDA0OD0FCsKFKVQ==
//-----END CERTIFICATE-----
//]
//
//CRYPT_STRING_BASE64:[
//AAECAwQFBgcICQoLDA0OD0FCsKFKVQ==
//]
//
//CRYPT_STRING_BASE64REQUESTHEADER:[
//-----BEGIN NEW CERTIFICATE REQUEST-----
//AAECAwQFBgcICQoLDA0OD0FCsKFKVQ==
//-----END NEW CERTIFICATE REQUEST-----
//]
//
//CRYPT_STRING_HEX:[
//        00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f
//        41 42 b0 a1 4a 55
//]
//
//CRYPT_STRING_HEXASCII:[
//        00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f   ................
//        41 42 b0 a1 4a 55                                  AB..JU
//]
//
//CRYPT_STRING_BASE64X509CRLHEADER:[
//-----BEGIN X509 CRL-----
//AAECAwQFBgcICQoLDA0OD0FCsKFKVQ==
//-----END X509 CRL-----
//]
//
//CRYPT_STRING_HEXADDR:[
//0000    00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f
//0010    41 42 b0 a1 4a 55
//]
//
//CRYPT_STRING_HEXASCIIADDR:[
//0000    00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f   ................
//0010    41 42 b0 a1 4a 55                                  AB..JU
//]
//
donjin9 2018-06-20
  • 打赏
  • 举报
回复
就像你说的每3个字节变成4个字节。字符串末尾不足3个字节的就按照约定补上去。

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧