user-0 提问: 关于base64 编解码的一点疑惑？

回复:
user: user-0
content: [quote=引用 6 楼 jha334201553 的回复:] 二进制数据是同样的道理呀。假设经过base64编码的就是一个长度为6的字符串(去掉 = )， 同样是6 * 6 bit数据。 经过移位处理，得到4 *8bit + 4bit 数据，我们按照标准算法，就是丢掉那4bit的数据。 这4bit是 36 %8 算出来的，跟二进制数据有00结尾的有什么关系呢？

user: user-1
content: 引用 4 楼 weixin_40810615 的回复:赵四老师，能不能谈谈你的理解，不要一言不和就贴代码！我认为“1234” 和“12345”base64的编码，加不加等号，都可以把原始数据解出来。 “MTIzNA” 这个（去掉 =的）base64编码， 一共有6 * 6bit数据， 我们经过移位处理后，会得到 4B （4 * 8bit）数据。 还有剩余4bit,我们直接扔掉。就会把原始数据解出来。 “MTIzNDU”也是类似。那还加什么等号呢？因为你编码的是字符串，如果编码二进制数据呢，里面有00结尾数据，解码出来全删掉吗？

user: user-2
content: 不用补也能用，一般也支持的。 补了对齐呗

user: user-0
content: 赵四老师，能不能谈谈你的理解，不要一言不和就贴代码！我认为“1234” 和“12345”base64的编码，加不加等号，都可以把原始数据解出来。 “MTIzNA” 这个（去掉 =的）base64编码， 一共有6 * 6bit数据， 我们经过移位处理后，会得到 4B （4 * 8bit）数据。 还有剩余4bit,我们直接扔掉。就会把原始数据解出来。 “MTIzNDU”也是类似。那还加什么等号呢？

user: user-1
content: =是补0的字节数，比如“1234”（4+2）*8 = 48 = 6*8 ，也就是"1234\0\0" 补充2字节的\0，等这个编码完成在最后 加 == ，以表示最后的两个\0是对齐补充的，解码的时候根据=个数再去掉末尾的\0

user: user-3
content: 仅供参考：#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 //] //

user: user-2
content: 就像你说的每3个字节变成4个字节。字符串末尾不足3个字节的就按照约定补上去。