今天给大家变个小魔术。鄙人不才,师承谦哥,给大家献丑了。
我左手拿着一张图片,右手握着一只鼠标。
看清楚了哦,不能眨眼,一起来见证奇迹!我轻轻地这么一点,嗖的一下。
这是什么鬼魔术嗷,放了两张一样的图片糊弄观众?
非也,非也。这是两张看起来相同实际上并不相同的图片。在这第二张图片里面,我嵌入了一段秘密信息,也就是神秘的隐写术。
隐写方法及其应用曾出现在许多古代东西方的文字记载之中。
《Histories》最早描述了隐写的应用,其中记载,Histiaeus将消息刺在奴隶的头皮上,等到头发长出来再将奴隶送出去。
利用头发这个掩体传递密文,而本文所表演的魔术不过是把掩体换成了图片而已,使用了一种称为最低有效位(LSB)的算法。
我们知道图像像素的样点存在最低意义的比特位,比方说某个像素点为(255,255,255),用二进制表示就是每个颜色通道的数值都是11111111,最低意义的比特位就是这最后一位1,由于自然信号样点的奇偶性随机,对它们的修改是很难被人肉眼所感知的。比方说像素254和255仅在最低位不同,其差别是相当小的。
LSB算法正是通过修改这个最低有效位来达到传递密文的目的。
隐写不仅需要发出方将信息藏进载体里,接收方需要正确从这个藏了信息的载体里提取出信息。LSB算法也是如此,可以分成两部分来看待,嵌入算法以及提取算法。
嵌入算法的主要做法是提取原始图片的像素,将其每个像素点最低有效位全部置零。将需要嵌入的秘密信息转换成二进制存储,并以此依次修改原图的像素。下面是嵌入算法的主要代码,其中主要依靠 PIL 库来进行图片的操作处理。
def func(str1,str2,str3):
im = Image.open(str1)
#获取图片的宽和高
width,height= im.size[0],im.size[1]
print("width:"+str(width))
print("height:"+str(height))
count = 0
#获取需要隐藏的信息
key = get_key(str2)
keylen = len(key)
for h in range(height):
for w in range(width):
pixel = im.getpixel((w,h))
a=pixel[0]
b=pixel[1]
c=pixel[2]
if count == keylen:
break
a= a-mod(a,2)+int(key[count])
count+=1
if count == keylen:
im.putpixel((w,h),(a,b,c))
break
b =b-mod(b,2)+int(key[count])
count+=1
if count == keylen:
im.putpixel((w,h),(a,b,c))
break
c= c-mod(c,2)+int(key[count])
count+=1
if count == keylen:
im.putpixel((w,h),(a,b,c))
break
if count % 3 == 0:
im.putpixel((w,h),(a,b,c))
im.save(str3)
而提取算法恰好与嵌入算法对应,你在最低位嵌入,我就只要把新图片的最低位提取出来,把二进制数据转换成十进制再转换成字符串即可。