NeoAtlantis在6月1日凌晨看到了曾经的化学吧的成员__wqerty__发的贴子,内容如下:
首先用这个链接下载原图, 一定要用这个链接里的, 否则隐藏的信息可能会被破坏:
几点提示:
1.所有的文本信息都在像素里, 从最左上角的像素开始.
2.隐藏的文本首先是一个英文短篇小说, 然后是2006年某一天化学吧的文本.
3.破解出来的请告诉我短篇小说的名字和中文文本的具体日期.
4.RGBA
5.隐藏的文本一共141kB.
6.加密的方法很简单
根据帖子里的其他提示,我意识到,原图应该是使用LSB方法隐藏的信息。
1. 确定隐藏的技术
首先需要确定的是,wqerty在图片中用了最低几个有效位存储的数据。根据提示,RGBA,可能考虑在一个像素的R、G、B、A通道上利用最低有效位各存储了一个比特。
为了进一步确信这一点,提取RGBA各通道上的二值图。由于篇幅所限,这里以A通道上的第0位二值图为例:
可以看出,数据量大约占一半的像素。实际上根据提示5, 大约也能估计到。
2. 进行提取
我最后用来提取这一图片中的数据的代码如下。
#!/usr/bin/python
import PIL.Image
source = PIL.Image.open('quelle.png') # wqerty的原始png图片
r,g,b,a = source.split()
# src: r,g,b,a
src = [list(i.getdata()) for i in (r,g,b,a)]
for i in xrange(0, 4):
src[i] = [x & 0x01 for x in src[i]]
length = len(src[0])
combined = []
for i in xrange(0, length):
value = (src[0][i] << 0) + (src[1][i] << 1) + (src[2][i] << 2) + (src[3][i] << 3)
combined.append(value)
output = []
length = len(combined)
i=0
while i + 1 < length:
l = combined[i]
r = combined[i+1]
output.append((r << 4) + l)
i += 2
output = output[:141*1024]
outputStr = ''.join([chr(i) for i in output])
open('extracted_data_littleendian.bin', 'w+').write(outputStr)
在提示中没有提到使用的是Big-Endian还是Little-Endian。我认为应该称为后者。
3. 我的回复
如果wqerty看到这里——我给您撰写了回复。使用完全和挑战一样的技术。
回复的图片如下:
数据量为18040字节,使用GPG签名故可验证完整性和可信性。数据为UTF-8编码。
撰写这一回复的代码如下:
#!/usr/bin/python
import PIL.Image
source = PIL.Image.open('source.png')
data = open('answer/brief.txt.asc', 'r').read()
r,g,b,a = source.split()
# src: r,g,b,a
src = [list(i.getdata()) for i in (r,g,b,a)]
data = [ord(i) for i in data]
data = [(i & 0x0f, ((i & 0xf0) >> 4)) for i in data]
embed = []
for a, b in data:
embed.append(a)
embed.append(b)
length = len(embed)
for j in xrange(0, length):
for i in xrange(0, 4):
src[i][j] = (src[i][j] & 0xfe) | ((embed[j] >> i) & 0x01)
r = ''.join([chr(i) for i in src[0]])
g = ''.join([chr(i) for i in src[1]])
b = ''.join([chr(i) for i in src[2]])
a = ''.join([chr(i) for i in src[3]])
r = PIL.Image.fromstring('L', source.size, r)
g = PIL.Image.fromstring('L', source.size, g)
b = PIL.Image.fromstring('L', source.size, b)
a = PIL.Image.fromstring('L', source.size, a)
output = PIL.Image.merge('RGBA',(r,g,b,a))
output.save('output.png','PNG')
output.show()
使用了Python Image Library(PIL)作为图像处理的库。您需要事先安装之。
我的数据经过了GPG签名,使用的签名密钥在隐写的数据中有。在本博客页面底部也有。
4. 完整的解码过程
完整的研究解码过程,放置在我的github上面。包括RGBA通道的第0和第1位的二值图,解码程序,撰写回复用的编码程序,以及,解码的结果。
地址如下:传送门。