LSB 隐写术

曾几何时,我写下了我的 集线器上的第一篇文章。 这篇文章致力于解决一个非常有趣的问题,即隐写术。 当然,那个老话题中提出的解决方案不能称为真正意义上的隐写术。 这只是一个带有文件格式的游戏,但仍然是一个非常有趣的游戏。

今天我们将尝试更深入地研究 LSB 算法。 如果您有兴趣,欢迎您下猫。 (削减下的是流量:大约一兆字节。)

首先有必要做一个简单的介绍。 大家都知道,密码学的目的是让秘密信息无法被读取。 当然,密码学有其应用,但还有另一种数据保护方法。 我们不必加密信息,但假装我们没有它。 这正是发明隐写术的原因。 维基百科向我们保证“隐写术(来自希腊语 στεγανοσ - 隐藏和希腊语 γραφω - 我写的,字面意思是“秘密写作”)是通过对传输事实保密来隐藏信息传输的科学。

当然,没有人禁止将密码学和隐写术方法结合起来。 而且,在实践中他们是这样做的,但我们的任务是了解基础知识。 如果你仔细研究维基百科的文章,你会发现隐写算法包括所谓的。 容器和消息。 容器是任何有助于隐藏我们的秘密消息的信息。

在我们的例子中,容器将是 BMP 格式的图像。 首先,我们看一下这个文件的结构。 文件可分为4部分:文件头、图像头、调色板和图像本身。 出于我们的目的,我们只需要知道标头中写入的内容即可。

标头的前两个字节是 BM 签名,然后用双字写入文件大小(以字节为单位),接下来的 4 个字节保留且必须包含零,最后另一个双字包含距文件开头的偏移量。文件到图像的实际字节。 在 24 位 bmp 文件中,每个像素都使用三个 BGR 字节进行编码。

现在我们知道如何获取图像,剩下的就是了解如何在那里写入我们需要的信息。 为此,我们需要 LSB 方法。 该方法的本质如下:我们替换负责颜色编码的字节中的最低有效位。 假设我们的秘密消息的下一个字节是 11001011,并且图像中的字节是...11101100 01001110 01111100 0101100111...,那么编码将如下所示。 我们将秘密消息字节分成 4 个两位部分:11、00、10、11,并用结果片段替换图像的低位:...11101111 01001100 01111110 0101100111…. 这种替换通常是人眼无法察觉的。 此外,许多较旧的输出设备甚至无法显示如此微小的变化。

显然,您不仅可以更改 2 个最低有效位,还可以更改任意数量的位。 有以下模式:我们改变的位数越多,我们可以隐藏的信息就越多,这对原始图像造成的干扰就越大。 例如,这里有两个图像:

LSB 隐写术
LSB 隐写术

尽管我尽了最大努力,我还是看不出它们之间的区别,但尽管如此,在第二张图像中,使用所描述的方法,刘易斯·卡罗尔的诗《狩猎蛇》被隐藏了。 如果您已经读到这里,那么您可能有兴趣了解其实现。 这很简单,但我会立即警告您,一切都是在 Delphi 中完成的。 这样做的原因有两个:1.我认为Delphi是一门很好的语言;2.我认为Delphi是一种很好的语言。 XNUMX. 这个程序是在准备计算机视觉基础课程的过程中诞生的,而我教授这门课程的人除了 Delphi 之外还不懂任何东西。 对于不熟悉语法的人,需要解释一件事:shl x 是按位左移 x,shr x 是按位右移 x。

我们假设我们正在将存储在字符串中的文本写入容器并替换较低的两个字节:
录音代码:

对于 i:=1 到 length(str) 做
    开始
      l1:=字节(str[i]) shr 6;
      l2:=byte(str[i]) shl 2; l2:=l2 shr 6;
      l3:=byte(str[i]) shl 4; l3:=l3 shr 6;
      l4:=byte(str[i]) shl 6; l4:=l4 shr 6;
 
      f.ReadBuffer(tmp,1);
      f.Position:=f.Position-1;
      tmp:=((tmp shr 2) shl 2)+l1;
      f.WriteBuffer(tmp,1);
 
      f.ReadBuffer(tmp,1);
      f.Position:=f.Position-1;
      tmp:=((tmp shr 2) shl 2)+l2;
      f.WriteBuffer(tmp,1);
 
      f.ReadBuffer(tmp,1);
      f.Position:=f.Position-1;
      tmp:=((tmp shr 2) shl 2)+l3;
      f.WriteBuffer(tmp,1);
 
      f.ReadBuffer(tmp,1);
      f.Position:=f.Position-1;
      tmp:=((tmp shr 2) shl 2)+l4;
      f.WriteBuffer(tmp,1);
 
    结束;

阅读代码:

对于 i:=1 到 MsgSize 执行
    开始
      f.ReadBuffer(tmp,1);
      l1:=tmp shl 6;
      f.ReadBuffer(tmp,1);
      l2:=tmp shl 6; l2:=l2 shr 2;
      f.ReadBuffer(tmp,1);
      l3:=tmp shl 6; l3:=l3 shr 4;
      f.ReadBuffer(tmp,1);
      l4:=tmp shl 6; l4:=l4 shr 6;
      str:=str+char(l1+l2+l3+l4);
    结束;

好吧,对于那些真正懒惰的人来说—— 链接到程序及其源代码.

谢谢。

来源: habr.com

添加评论