[半个找人贴]解码wqerty将信息藏于图片的挑战

neoatlantis 2014-06-01 14:57

(话说有谁如果能联系到wqerty,希望能帮我告知他这个贴子)
NeoAtlantis在2014年6月1日凌晨看到了曾经的化学吧的成员wqerty发的贴子,内容如下:
[quote]
首先用这个链接下载原图, 一定要用这个链接里的, 否则隐藏的信息可能会被破坏:
http://pan.baidu.com/share/link?shareid=350675&uk=306630
几点提示:
1.所有的文本信息都在像素里, 从最左上角的像素开始.
2.隐藏的文本首先是一个英文短篇小说, 然后是2006年某一天化学吧的文本.
3.破解出来的请告诉我短篇小说的名字和中文文本的具体日期.
4.RGBA
5.隐藏的文本一共141kB.
6.加密的方法很简单[/quote]


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

1. 确定隐藏的技术  

首先需要确定的是,wqerty在图片中用了最低几个有效位存储的数据。根据提示,RGBA,可能考虑在一个像素的R、G、B、A通道上利用最低有效位各存储了一个比特。
为了进一步确信这一点,提取RGBA各通道上的二值图。由于篇幅所限,这里以A通道上的第0位二值图为例:

可以看出,数据量大约占一半的像素。实际上根据提示5, 大约也能估计到。

2. 进行提取  

我最后用来提取这一图片中的数据的代码如下。
  1. #!/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看到这里——我给您撰写了回复。使用完全和挑战一样的技术。
回复的图片如下:

图片地址:
https://neoatlantis.github.io/data/2014-06-01-decode-wqerty-puzzle/answer.png

撰写这一回复的代码如下:
  1. #!/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签名,使用的签名密钥在隐写的数据中有。或者请到https://neoatlantis.github.io/gpgkey.html下载。

4. 完整的解码过程


完整的研究解码过程,放置在我的github上面。包括RGBA通道的第0和第1位的二值图,解码程序,撰写回复用的编码程序,以及,解码的结果。

地址如下:传送门


neoatlantis 2014-06-01 15:08

[attachment=9271]

再发一遍我的回复图。
这个图片的SHA1为:6201e48b593c061de7d6e10582b896d6ad025521

隐写数据长度18040字节,使用GPG签名,可以验证其完整性和可信性(来自我)。文本使用UTF-8编码。

活动星图 2014-06-02 01:42

只能说不明觉厉。
给外科体的百度信箱发信试试?

FIRE 2014-06-02 14:36

围观。。。。好厉害。。

回 活动星图 的帖子

neoatlantis 2014-06-02 15:31

[quote]活动星图:只能说不明觉厉。
给外科体的百度信箱发信试试? (2014-06-02 01:42) 
[/quote]
简单说就是1年零3个月以前,外科体在百度化吧发贴,就是一个900多kB的图片。
然后这个图片里面隐藏了信息(不是那种改个名就成rar的那种,是直接在像素里写的信息)。
然后我因为凑巧选过这门课(信息隐藏技术),凑巧昨天看到了,就写程序提取了。

提取结果在https://github.com/neoatlantis/wqerty-puzzle,进去浏览extracted_data_littleendian.bin就能看到了。

红色 2014-06-02 18:39

这个不好,这种就是面多加水的加密。
最好应该是像RAR ZIP之类的,压缩加密

回 红色 的帖子

金星凌日 2014-06-02 19:10

[quote]红色:这个不好,这种就是面多加水的加密。
最好应该是像RAR ZIP之类的,压缩加密 (2014-06-02 18:39) 
[/quote]
这个似乎不算加密,只是隐藏。

回 红色 的帖子

neoatlantis 2014-06-02 22:10

[quote]红色:这个不好,这种就是面多加水的加密。
最好应该是像RAR ZIP之类的,压缩加密 (2014-06-02 18:39) 
[/quote]
不是,这是在面里面扣出淀粉,然后在上面把氕换成氚,再把淀粉放回去的方法。

具体说是,比如有一个像素的红色分量是255, 二进制表示是11111111,这个像素的红色分量上,为了写入一个0,我们把最低位换成0, 变成(11111110)2=(254)10,这样这个分量的颜色变了,但是从255变到254, 人眼看不出来。图像自己的尺寸、数据量也都没变。
如果写1, 就不改变这个像素的红色分量。

一个像素有红、绿、蓝和透明度4个分量,所以一个像素上可以隐藏半个比特的数据。这就是我、外科体玩的把戏。

neoatlantis 2014-06-02 22:15

这的确不是加密,只是一种隐写技术。
类似的技术还可以把数据放进声音,比如mp3或者wav格式都可以用某种方法隐藏这种数据。

隐写技术是为了避免对数据的检查。有些时候直接使用密码会引起怀疑。
但是对于图片中的隐写,比较先进的技术目前只能估计出写入的数据量,具体写了什么,如何提取还不一定。这方面,结合密码来控制隐写的过程,也是有必要的。

另外貌似隐写技术已经被某些先进的恐怖分子利用过了。以前看过类似的新闻报道。

其他隐蔽的技术还有,用全角和半角的标点,用特定的类似垃圾邮件的语句组成垃圾邮件等等。

回 neoatlantis 的帖子

活动星图 2014-06-03 17:40

[quote]neoatlantis:简单说就是1年零3个月以前,外科体在百度化吧发贴,就是一个900多kB的图片。
然后这个图片里面隐藏了信息(不是那种改个名就成rar的那种,是直接在像素里写的信息)。
然后我因为凑巧选过这 .. (2014-06-02 15:31) 
[/quote]
整个过程我大概知道是咋回事,不明觉厉是指解码过程。。。
然后虽然知道了是那个著名小说,但是....好失望啊,还以为有啥羞羞的事情发生....