{
"title": "base64数据隐写实现原理分析",
"tags": [
"post",
"技术"
],
"sources": [
"xlog"
],
"external_urls": [
"https://daidr.xlog.app/base64-hide"
],
"date_published": "2020-04-14T23:49:00.000Z",
"content": "\n![image](ipfs://bafkreiheogqhpqlfrorh2kswvgraz4re4fy2edg5xg6fqeidoaovchvnju)\n\n在开始这篇文章前,先让我们来看一组base64编码的字符串\n\n```\nZG==\nYY==\naW==\nZF==\ncm==\naM==\nb2==\ndc==\nc2==\nZf==\n```\n\n解码后的内容是daidrhouse,似乎没有什么问题。但是仔细看,第一行和第4行解码后的结果都是d,但内容竟然不太一样?\n\n按照正常的base64编码,daidrhouse应该得到下面的结果。\n\n```\nZA==\nYQ==\naQ==\nZA==\ncg==\naA==\nbw==\ndQ==\ncw==\nZQ==\n```\n\n显然,与前者相比,每串base64的第二个字符都被改变了,但解码后的内容依然不变,这得从base64编码的原理说起。\n\n## 什么是base64\n\n顾名思义,base64编码就是用64个ascii字符作为基础来编码二进制内容的一种编码方式。相信各位一定在网页中看到过base64编码的内嵌图片,甚至QQ音乐传输歌词文件时,也采用了base64编码。将二进制编码为ascii字符,使数据在某些场景下更便于阅读、便于传输。当然,将所有二进制「浓缩」到区区64个字符来表示,一定会在体积上作出妥协。字符在编码完成后,会增大1/3倍,至于原因,下面会讲到。\n\n### 索引表\n\nbase64有一张标准编码表,为64个ascii字符排序并赋予索引。\n\n| 索引 | 字符 | 索引 | 字符 | 索引 | 字符 | 索引 | 字符 |\n| --- | --- | --- | --- | --- | --- | --- | --- |\n| 0 | A | 16 | Q | 32 | g | 48 | w |\n| 1 | B | 17 | R | 33 | h | 49 | x |\n| 2 | C | 18 | S | 34 | i | 50 | y |\n| 3 | D | 19 | T | 35 | j | 51 | z |\n| 4 | E | 20 | U | 36 | k | 52 | 0 |\n| 5 | F | 21 | V | 37 | l | 53 | 1 |\n| 6 | G | 22 | W | 38 | m | 54 | 2 |\n| 7 | H | 23 | X | 39 | n | 55 | 3 |\n| 8 | I | 24 | Y | 40 | o | 56 | 4 |\n| 9 | J | 25 | Z | 41 | p | 57 | 5 |\n| 10 | K | 26 | a | 42 | q | 58 | 6 |\n| 11 | L | 27 | b | 43 | r | 59 | 7 |\n| 12 | M | 28 | c | 44 | s | 60 | 8 |\n| 13 | N | 29 | d | 45 | t | 61 | 9 |\n| 14 | O | 30 | e | 46 | u | 62 | + |\n| 15 | P | 31 | f | 47 | v | 63 | / |\n\n有时为了防止混淆(比如链接),会使用 `.` `_` 来代替索引表中的 `+` `/` 。\n\n### 编码方式\n\nbase64将3个字节(24位)作为一组进行处理。不足3字节时填充0,并在结尾使用 `=` 来标识填充的字节数。并将每6位作为1小组,将24位编码成4组6位二进制。此时,这6位二进制一共有 26\\=642^6=6426\\=64 种情况,正好能够用64个字符来表示。(这也解释了为什么编码完成后体积会增大1/3)\n\n### 举些栗子\n\n![image](ipfs://bafkreigidkppqcdm2sqveho5b66vgo2wsvaxdnho2ggftw5crcr25hpgm4)\n\n![image](ipfs://bafkreibcmqt6plibgxyf5udkwxqycr2whztedyass25w7repmlg5hr7cxm)\n\n## 隐写的原理\n\nbase64在解码的时候,会按照字符串末尾的 `=` 数量来删除相应字节数。或许你已经发现了,当一组字符的数量为1字节或2字节的时候,会有4位或2位二进制在解码时被忽略,及下图的红色标识。\n\n![image](ipfs://bafkreigpsyheueus2cfjvcrglbzkept6js6krhesc52r5rhqyaoi4qut2u)\n\n![image](ipfs://bafkreihtnexrks5h26vojgx4oyynqyhq5in24qvkrspr6jzw3hzwctr4vu)\n\n红色标识的这些二进制,能够被编码,但解码时却会被忽略。修改这些位置的内容,不会影响到原始数据。\n\n### 解决问题\n\n现在,可以来尝试解决文章开头的问题了。那组base64编码的字符串,隐藏了什么?\n\n![image](ipfs://bafkreifspml3zg24xihasuu3s3bzzkyfkpkpl2hshe3im7s4h3zxwemjcy)\n\n![image](ipfs://bafkreifqycgf3bnkks7g2qctrsvox7ucyrjcoz5l2q7pqg2uqjuymstrvm)\n\n![image](ipfs://bafkreifiypjwxfvzbsh33yhxz2gxkifpsbkba4pg6hr6vd5rot2zn32atm)\n\n![image](ipfs://bafkreiajnde5bvvdjqijilsxc6y4izuwsw2fmqp6wu3la4fqsa3phes3ku)\n\n![image](ipfs://bafkreiephcdxxgeiddjwng4dyncggy6pvrx2f74jknjx2rjlrzt77fhkmq)\n\n![image](ipfs://bafkreicrjgqutfkolsbkhyxospg2tpxrnumf34caxyjz565rfz7bitp2wa)\n\n![image](ipfs://bafkreibevxiz4ss7v7xtz5totg2wjvurwdwqbrpwyof34y2qry4akfezwe)\n\n![image](ipfs://bafkreiefgwv37czbo2rbmtoyaeqbgo76mmzgzu2mndygn65vagzlymrnmy)\n\n![image](ipfs://bafkreig7ukywiawzgnumtsc6izgkfayhvcaxawvcxwn62olehyigfzovda)\n\n![image](ipfs://bafkreihezasqw4ti3ahr2vabtpiwtmfnl3vcls45vh2q7ll5jluhsxnhzm)\n\n将所有红色标识的二进制位拼接起来,可以得到最后的结果hello\n\n![image](ipfs://bafkreichqgzl4kvttcalc2dylcu7uogx7siurdcbhfgfcvexce3pttk2jy)\n",
"attributes": [
{
"value": "base64-hide",
"trait_type": "xlog_slug"
}
]
}