|
點(diǎn)擊上方「嵌入式實(shí)驗(yàn)基地」,選擇「置頂公眾號(hào)」第一時(shí)間查看嵌入式筆記!
jkcfjgajovw64047061117.png (100.54 KB, 下載次數(shù): 0)
下載附件
保存到相冊(cè)
jkcfjgajovw64047061117.png
2024-10-26 05:24 上傳
?
本次為各位小伙伴帶來(lái)的是一種網(wǎng)絡(luò)上最常見的用于傳輸8Bit字節(jié)碼的編碼方式之一,base64編碼,基于C語(yǔ)言實(shí)現(xiàn)。
??原理性描述摘自:https://www.cnblogs.com/xq1314/p/7909521.html,如有版權(quán)問題,請(qǐng)聯(lián)系刪除。
1、Base64編碼概述??Base64是一種編碼方式,這個(gè)術(shù)語(yǔ)最初是在“MIME內(nèi)容傳輸編碼規(guī)范”中提出的。Base64不是一種加密算法,它實(shí)際上是一種“二進(jìn)制轉(zhuǎn)換到文本”的編碼方式,它能夠?qū)⑷我舛M(jìn)制數(shù)據(jù)轉(zhuǎn)換為ASCII字符串的形式,以便在只支持文本的環(huán)境中也能夠順利地傳輸二進(jìn)制數(shù)據(jù)。
(1)base64編碼:把二進(jìn)制數(shù)據(jù)轉(zhuǎn)為字符;
(2)base64解碼:把字符轉(zhuǎn)為二進(jìn)制數(shù)據(jù);
2、Base64編碼由來(lái)??因?yàn)橛行┚W(wǎng)絡(luò)傳輸渠道并不支持所有字節(jié),例如傳統(tǒng)的郵件只支持可見字符的傳輸,像ASCII碼的控制字符(ASCII碼包含了 128 個(gè)字符。其中前 32 個(gè), 0-31 ,即 0x00-0x1F ,都是不可見字符。這些字符,就叫做控制字符。)就不能通過郵件傳輸。另外,例如圖片二進(jìn)制流的每個(gè)字節(jié)不可能全部都是可見字符,所以就傳送不了。
??最好的方法就是在不改變傳統(tǒng)協(xié)議的情況下,做一種擴(kuò)展方案來(lái)支持二進(jìn)制文件的傳送,把不可能打印的字符用可打印的字符標(biāo)識(shí),問題就解決了。Base64編碼就應(yīng)運(yùn)而生,Base64就是一種基于64個(gè)可打印字符來(lái)表示二進(jìn)制數(shù)據(jù)的表示方法。
3、Base64編碼原理??如下圖Base64編碼索引表,字符選用了“A-Z 、 a-z 、 0-9、+、 / ”64個(gè)可打印字符。數(shù)字代表字符索引,這個(gè)是標(biāo)準(zhǔn)Base64標(biāo)準(zhǔn)協(xié)議規(guī)定的,不能更改。64個(gè)字節(jié)用6個(gè)bit位就可以全部表示(32+16+8+4+2+1)就可以全部表示。這里注意一個(gè)Base64字符是8個(gè)bit,但有效部分只有右邊6個(gè)bit,左邊兩個(gè)永遠(yuǎn)是0。
sshok2qcueu64047061217.png (35.18 KB, 下載次數(shù): 0)
下載附件
保存到相冊(cè)
sshok2qcueu64047061217.png
2024-10-26 05:24 上傳
??那么怎么用6個(gè)有效bit來(lái)表示傳統(tǒng)字符的8個(gè)bit呢?8和6的最小公倍數(shù)是24,也就是說(shuō)3個(gè)傳統(tǒng)字節(jié)可以由4個(gè)Base64字符來(lái)表示,保證有效位數(shù)是一樣的,這樣就多了1/3的字節(jié)數(shù)來(lái)彌補(bǔ)Base64只有6個(gè)有效bit的不足。你也可以說(shuō)用兩個(gè)Base64字符也能表示一個(gè)傳統(tǒng)字符,但是采用最小公倍數(shù)的方案其實(shí)是最減少浪費(fèi)的。結(jié)合下邊的圖比較容易理解。Man是三個(gè)字符,一共24個(gè)有效bit,只好用4個(gè)Base64字符來(lái)湊齊24個(gè)有效位。紅框表示的是對(duì)應(yīng)的Base64,6個(gè)有效位轉(zhuǎn)化成相應(yīng)的索引值再對(duì)應(yīng)Base64字符表,查出"Man"對(duì)應(yīng)的Base64字符是"TWFU"。說(shuō)到這里有個(gè)原則不知道你發(fā)現(xiàn)了沒有,要轉(zhuǎn)換成Base64的最小單位就是三個(gè)字節(jié),對(duì)一個(gè)字符串來(lái)說(shuō)每次都是三個(gè)字節(jié)三個(gè)字節(jié)的轉(zhuǎn)換,對(duì)應(yīng)的是Base64的四個(gè)字節(jié)。這個(gè)搞清楚了其實(shí)就差不多了。
kqldxliyooz64047061317.png (4.3 KB, 下載次數(shù): 0)
下載附件
保存到相冊(cè)
kqldxliyooz64047061317.png
2024-10-26 05:24 上傳
??但是轉(zhuǎn)換到最后你發(fā)現(xiàn)不夠三個(gè)字節(jié)了怎么辦呢?愿望終于實(shí)現(xiàn)了,我們可以用兩個(gè)Base64來(lái)表示一個(gè)字符或用三個(gè)Base64表示兩個(gè)字符,像下圖的A對(duì)應(yīng)的第二個(gè)Base64的二進(jìn)制位只有兩個(gè),把后邊的四個(gè)補(bǔ)0就是了。所以A對(duì)應(yīng)的Base64字符就是QQ。上邊已經(jīng)說(shuō)過了,原則是Base64字符的最小單位是四個(gè)字符一組,那這才兩個(gè)字符,后邊補(bǔ)兩個(gè)"="吧。其實(shí)不用"="也不耽誤解碼,之所以用"=",可能是考慮到多段編碼后的Base64字符串拼起來(lái)也不會(huì)引起混淆。由此可見Base64字符串只可能最后出現(xiàn)一個(gè)或兩個(gè)"=",中間是不可能出現(xiàn)"="的。下圖中字符"BC"的編碼過程也是一樣的。
nethrr2xya564047061417.png (5.6 KB, 下載次數(shù): 0)
下載附件
保存到相冊(cè)
nethrr2xya564047061417.png
2024-10-26 05:24 上傳
4、Base64編碼 c語(yǔ)言代碼實(shí)現(xiàn)/******* Base64 Encoding ******************/
static const size_t BASE64_ENCODE_INPUT = 3;
static const size_t BASE64_ENCODE_OUTPUT = 4;
static const char* const BASE64_ENCODE_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
size_t base64EncodeGetLength( size_t size )
{
/*
* output 4 bytes for every 3 input:
* 1 2 3
* 1 = --111111 = 111111--
* 2 = --11XXXX = ------11 XXXX----
* 3 = --1111XX = ----1111 XX------
* 4 = --111111 = --111111
*/
return (((size + BASE64_ENCODE_INPUT - 1) / BASE64_ENCODE_INPUT) * BASE64_ENCODE_OUTPUT) + 1; /*plus terminator*/
}
size_t base64Encode( char* dest, const void* src, size_t size )
{
if (dest && src)
{
unsigned char* pSrc = (unsigned char*)src;
size_t dwSrcSize = size;
size_t dwDestSize = 0;
size_t dwBlockSize = 0;
unsigned char n1, n2, n3, n4;
while (dwSrcSize >= 1)
{
/* Encode inputs */
dwBlockSize = (dwSrcSize 0;
switch (dwBlockSize)
{
case 3:
n4 = (unsigned char)(pSrc[ 2 ] & 0x3f);
n3 = ((unsigned char)(pSrc[ 2 ] & 0xc0) >> 6);
case 2:
n3 |= ((unsigned char)(pSrc[ 1 ] & 0x0f) 2);
n2 = ((unsigned char)(pSrc[ 1 ] & 0xf0) >> 4);
case 1:
n2 |= ((unsigned char)(pSrc[ 0 ] & 0x03) 4);
n1 = ((unsigned char)(pSrc[ 0 ] & 0xfc) >> 2);
break;
default:
assert( 0 );
}
pSrc += dwBlockSize;
dwSrcSize -= dwBlockSize;
/* Validate */
assert( n1 63 );
assert( n2 63 );
assert( n3 63 );
assert( n4 63 );
/* Padding */
switch (dwBlockSize)
{
case 1: n3 = 64;
case 2: n4 = 64;
case 3:
break;
default:
assert( 0 );
}
/* 4 outputs */
*dest++ = BASE64_ENCODE_TABLE[ n1 ];
*dest++ = BASE64_ENCODE_TABLE[ n2 ];
*dest++ = BASE64_ENCODE_TABLE[ n3 ];
*dest++ = BASE64_ENCODE_TABLE[ n4 ];
dwDestSize += BASE64_ENCODE_OUTPUT;
}
*dest++ = '\x0'; /*append terminator*/
return dwDestSize;
}
else
return 0; /*ERROR - null pointer*/
}
5、Base64解碼 c語(yǔ)言代碼實(shí)現(xiàn)/****************************** Base64 Decoding ******************************/
static const size_t BASE64_DECODE_INPUT = 4;
static const size_t BASE64_DECODE_OUTPUT = 3;
static const size_t BASE64_DECODE_MAX_PADDING = 2;
static const unsigned char BASE64_DECODE_MAX = 63;
static const unsigned char BASE64_DECODE_TABLE[ 0x80 ] = {
/*00-07*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/*08-0f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/*10-17*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/*18-1f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/*20-27*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
/*28-2f*/ 0xFF, 0xFF, 0xFF, 0x3e, 0xFF, 0xFF, 0xFF, 0x3f, /*2 = '+' and '/'*/
/*30-37*/ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /*8 = '0'-'7'*/
/*38-3f*/ 0x3c, 0x3d, 0xFF, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, /*2 = '8'-'9' and '='*/
/*40-47*/ 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /*7 = 'A'-'G'*/
/*48-4f*/ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /*8 = 'H'-'O'*/
/*50-57*/ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /*8 = 'P'-'W'*/
/*58-5f*/ 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*3 = 'X'-'Z'*/
/*60-67*/ 0xFF, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /*7 = 'a'-'g'*/
/*68-6f*/ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /*8 = 'h'-'o'*/
/*70-77*/ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /*8 = 'p'-'w'*/
/*78-7f*/ 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /*3 = 'x'-'z'*/
};
int base64Validate( const char* src, size_t size )
{
/*
* returns 0 if the source is a valid base64 encoding
*/
if (size % BASE64_DECODE_INPUT != 0)
return -1; /*ERROR - size isn't a multiple of 4*/
for (; size >= 1; --size, ++src)
{
unsigned char ch = *src;
if ((ch >= 0x80) || (BASE64_DECODE_TABLE[ ch ] > BASE64_DECODE_MAX))
break;
}
for (; 1 char ch = *src;
if ((ch >= 0x80) || (BASE64_DECODE_TABLE[ ch ] != BASE64_DECODE_MAX + 1))
break;
}
if (size != 0)
return -2; /*ERROR - invalid base64 character*/
return 0; /*OK*/
}
size_t base64DecodeGetLength( size_t size )
{
/*
* output 3 bytes for every 4 input:
* 1 2 3
* 1 = --111111 = 111111--
* 2 = --11XXXX = ------11 XXXX----
* 3 = --1111XX = ----1111 XX------
* 4 = --111111 = --111111
*/
if (size % BASE64_DECODE_INPUT == 0)
return (((size + BASE64_DECODE_INPUT - 1) / BASE64_DECODE_INPUT) * BASE64_DECODE_OUTPUT) + 1; /*plus terminator*/
else
return 0; /*ERROR - size isn't a multiple of 4*/
}
size_t base64Decode( void* dest, const char* src, size_t size )
{
if (dest && src && (size % BASE64_DECODE_INPUT == 0))
{
unsigned char* pDest = (unsigned char*)dest;
size_t dwSrcSize = size;
size_t dwDestSize = 0;
unsigned char in1, in2, in3, in4;
while (dwSrcSize >= 1)
{
/* 4 inputs */
in1 = *src++;
in2 = *src++;
in3 = *src++;
in4 = *src++;
dwSrcSize -= BASE64_DECODE_INPUT;
/* Validate ascii */
if (in1 >= 0x80 || in2 >= 0x80 || in3 >= 0x80 || in4 >= 0x80)
return 0; /*ERROR - invalid base64 character*/
/* Convert ascii to base64 */
in1 = BASE64_DECODE_TABLE[ in1 ];
in2 = BASE64_DECODE_TABLE[ in2 ];
in3 = BASE64_DECODE_TABLE[ in3 ];
in4 = BASE64_DECODE_TABLE[ in4 ];
/* Validate base64 */
if (in1 > BASE64_DECODE_MAX || in2 > BASE64_DECODE_MAX)
return 0; /*ERROR - invalid base64 character*/
/*the following can be padding*/
if ((int)in3 > (int)BASE64_DECODE_MAX + 1 || (int)in4 > (int)BASE64_DECODE_MAX + 1)
return 0; /*ERROR - invalid base64 character*/
/* 3 outputs */
*pDest++ = ((unsigned char)(in1 & 0x3f) 2) | ((unsigned char)(in2 & 0x30) >> 4);
*pDest++ = ((unsigned char)(in2 & 0x0f) 4) | ((unsigned char)(in3 & 0x3c) >> 2);
*pDest++ = ((unsigned char)(in3 & 0x03) 6) | (in4 & 0x3f);
dwDestSize += BASE64_DECODE_OUTPUT;
/* Padding */
if (in4 == BASE64_DECODE_MAX + 1)
{
--dwDestSize;
if (in3 == BASE64_DECODE_MAX + 1)
{
--dwDestSize;
}
}
}
*pDest++ = '\x0'; /*append terminator*/
return dwDestSize;
}
else
return 0; /*ERROR - null pointer, or size isn't a multiple of 4*/
}
6、Base64 編解碼測(cè)試代碼int main()
{
printf("qt test hello qt\r
");
int i=0,j=0;
unsigned char base64Decodemsg[50] = {0};
unsigned char base64Eecodemsg[10] = {0x04,0x10,0x83,0x10,0x51,0x87,0x24,0x71,0x85};
//base64加密后的信息存儲(chǔ)
unsigned char base64Encoded_msg[]={0};
//base64加解密測(cè)試
//測(cè)試網(wǎng)站:http://www.tomeko.net/online_tools/base64.php?lang=en
base64Encode(base64Encoded_msg,base64Eecodemsg,9);
printf("base64 encode message is:%s\r
",base64Encoded_msg);
base64Decode(base64Decodemsg,"BBCDEFGHJHGF",12);
printf("base64 decode message is:");
for(i=0;i9;i++){
printf("%0x",base64Decodemsg);
}
printf("\r
");
return 0;
}
7、Base64 編解碼運(yùn)行測(cè)試結(jié)果
wdjoga1e3co64047061517.png (84.29 KB, 下載次數(shù): 0)
下載附件
保存到相冊(cè)
wdjoga1e3co64047061517.png
2024-10-26 05:24 上傳
??如果你覺得對(duì)自己有幫助的話,給個(gè)贊,點(diǎn)個(gè)關(guān)注,點(diǎn)個(gè)在看,感謝前進(jìn)的道路上有你的陪伴!
??歡迎大家關(guān)注:嵌入式實(shí)驗(yàn)基地,來(lái)基地,和眾多小伙伴一起打boss!
??讓我快點(diǎn)遇到優(yōu)秀的你,然后一起變得更加優(yōu)秀,加油!!!小飛哥微信號(hào):w974762670,加好友進(jìn)群一起交流呀!
jozauwygfpw64047061617.png (336.59 KB, 下載次數(shù): 0)
下載附件
保存到相冊(cè)
jozauwygfpw64047061617.png
2024-10-26 05:24 上傳
推薦閱讀
?一種你值得擁有的簡(jiǎn)單易實(shí)現(xiàn)的開關(guān)電路
?無(wú)線通訊之紅外通訊
?DIY一個(gè)離線語(yǔ)音控制器
?HAL庫(kù)us延時(shí)的3種實(shí)現(xiàn)方式?邏輯分析儀的簡(jiǎn)單使用介紹(附帶iic,uart,spi數(shù)據(jù)波形分析)
?ART-PI重力感應(yīng)無(wú)線智能小車第一彈----ART-PI擴(kuò)展板設(shè)計(jì)?ART-PI重力感應(yīng)無(wú)線智能小車第二彈----Onenet+wifi+L298N電機(jī)驅(qū)動(dòng)?ART-PI重力感應(yīng)無(wú)線智能小車第三彈----RT-Studio+MPU6050+MQTT發(fā)布訂閱?STM32 DAC音頻輸出
?pcb設(shè)計(jì)基礎(chǔ)?OLED+ESP8266網(wǎng)絡(luò)小時(shí)鐘歡迎轉(zhuǎn)發(fā)、留言、點(diǎn)贊、分享給你的朋友,感謝您的支持! |
|