NeoAtlantis在6月1日凌晨看到了曾经的化学吧的成员__wqerty__发的贴子,内容如下:

首先用这个链接下载原图, 一定要用这个链接里的, 否则隐藏的信息可能会被破坏:

http://pan.baidu.com/share/link?shareid=350675&uk=306630

几点提示:

1.所有的文本信息都在像素里, 从最左上角的像素开始.

2.隐藏的文本首先是一个英文短篇小说, 然后是2006年某一天化学吧的文本.

3.破解出来的请告诉我短篇小说的名字和中文文本的具体日期.

4.RGBA

5.隐藏的文本一共141kB.

6.加密的方法很简单

根据帖子里的其他提示,我意识到,原图应该是使用LSB方法隐藏的信息

1. 确定隐藏的技术

首先需要确定的是,wqerty在图片中用了最低几个有效位存储的数据。根据提示,RGBA,可能考虑在一个像素的R、G、B、A通道上利用最低有效位各存储了一个比特。

为了进一步确信这一点,提取RGBA各通道上的二值图。由于篇幅所限,这里以A通道上的第0位二值图为例:

Bit-graph at 0-bit of Alpha Channel

可以看出,数据量大约占一半的像素。实际上根据提示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看到这里——我给您撰写了回复。使用完全和挑战一样的技术。

回复的图片如下:

Answer to 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位的二值图,解码程序,撰写回复用的编码程序,以及,解码的结果。

地址如下:传送门