隐写术进阶:利用纠错码在图像中高效隐藏数据

本文探讨了在图像隐写中应对压缩导致数据损坏的解决方案,详细介绍了纠错码的原理与应用,包括奇偶校验位和汉明码的实现方法,显著提升数据隐藏效率。

隐写术:在其他事物中隐藏事物的艺术与科学 – 第三部分

这是四部分系列的第三部分。在第一部分中,我们涵盖了图像格式的基础知识,并找到了在图像中隐藏数据的位置。在第二部分中,我们实际编写了代码,将数据隐写编码到图像中,然后提取它,而不使图像看起来不同。

压缩带来的挑战

在第二部分中,我们遇到了一个问题——压缩。当图像被压缩时,我们精心隐藏的数据可能会被损坏。我们通过将消息中的每一位重复9次来修复了这个问题,但我们可以做得更好。本文将介绍如何使用一些数学方法,以纠错码的形式,在每个图像中隐藏更多的数据位。

我们的朋友维基百科给出了纠错码的良好定义:

“纠错码(ECC)是向消息中添加冗余数据的过程,这样即使引入了一定数量的错误(最多达到所用代码的能力),接收方也可以恢复消息。”

我们之前使用的重复是最简单的ECC——我们发送冗余数据,一遍又一遍地重复自己,这样即使某些位是错误的,我们仍然可以接收消息。

定义问题

在我们开始寻找更好的方法之前,我们需要定义我们的问题。我们知道压缩会破坏数据,但具体是如何破坏的?

首先,我们可以说压缩引入了噪声——换句话说,有些位不是我们期望的那样。例如,我们可能输入消息1101,但输出1100——在这种情况下,我们会说最后一位从1“翻转”到了0。既然我们知道存在一些噪声,我们如何定义它?

我们有几个选择。你可以阅读论文,比如这篇8页的论文,由舰队信息战中心的某人撰写,或者你可以做一些假设并看看它们是否有效。

让我们折中一下,做出一些基于现实的假设。它们可能不是100%正确,但足够正确。因此,对于我们的目的,我们可以假设:

  1. 随机、位置无关的噪声:噪声中没有特定的模式;任何给定的位被翻转的机会与任何其他相同重要性的位相同。这意味着在图像中编码数据的位置无关紧要;图像左下角的像素(例如)与中间的像素一样可能被更改。
  2. 更重要的位噪声更少:任何像素的最低有效位最有可能被翻转,因为压缩试图消除无用数据,并且位被翻转的机会随着位变得更重要而减少。
  3. 噪声是二进制对称的:这是一种花哨的说法,表示噪声是无偏且均匀分布的——零被翻转的可能性与一相同。

与其花费大量时间从会被压缩的网站上上传和下载图像,我们可以通过随机化图像中的一些位来模拟这种类型的噪声。这让我们可以使用代码,这很好且可控,因此我们可以轻松进行大量测试。

这是我们的图像在模糊之前和之后:

它可能看起来没有太大不同,但它将we’re going to hide this message in an image!变成了we’re eking to hide this message in an image(结尾没有感叹号),所以它肯定造成了一些损害。

纠错码入门

现在的挑战是能够从模糊的图像中提取数据,即使存在噪声。第二部分的重复方法有效,但必须将每一位重复9次意味着我们无法传输足够的数据。我们可以做得更好。

在我们深入探讨纠错之前,我们需要谈谈奇偶校验位。本质上,奇偶校验位向任何给定的二进制字符串添加一个检查,告诉我们字符串中1位的数量是否为奇数。例如:字符串000没有1位,因此其奇偶校验位为0(留给我们最终的字符串0000)。相反,字符串010有奇数个1位,因此其奇偶校验位为1,留给我们0101。你会注意到,一旦添加了奇偶校验位,这意味着每个字符串都有偶数个一。

过程是:

  1. 根据你的消息计算奇偶校验位。如果它有奇数个1值,奇偶校验位是1,否则奇偶校验位是0
  2. 将这些奇偶校验位放入消息中;它们通常放在末尾,但只要接收方知道在哪里找到它们,它们的位置实际上并不重要。

我们为什么这样做?简单——如果字符串中的某个位被翻转,我们可以通过检查奇偶校验位来发现有问题(如果上面的字符串0101变成了1101,我们知道110的奇偶校验位应该是0——但它是1,所以一定有问题)。不幸的是,这只能告诉我们有问题——而不是什么问题。我们无法知道哪个位被翻转了。

汉明码:检测与纠正错误

进入理查德·汉明,他发明了汉明码,一种结合奇偶校验位来检测纠正错误的方法。等等,这即将变得非常棒(而且非常数学化)。

对于下一部分,让我们假设你试图发送4位数据,并且你(以某种方式)知道其中不会有多于一个错误。

假设你有通常的奇偶校验位和4位数据。如果有错误,你怎么能告诉哪个位错了?你不能——四个中的一个被翻转了,但无法知道是哪一个。(请注意,这些图形中的圆圈每个代表一个奇偶组——一旦所有奇偶校验位被计算并添加,每个组都会有偶数个一。这意味着如果我们接收消息时一个圆圈没有偶数个一,我们就知道有问题。)

如果你只是添加另一个奇偶校验位,那很好,但你所做的只是重复了奇偶校验位——这很有用,因为这意味着你可以通过检查另一个来告诉其中哪一个错了。但这似乎主要是浪费。如果出现问题,你仍然无法告诉哪些数据位被翻转了——第二个奇偶校验位没有提供新信息。

让我们尝试一些奇怪的事情。如果你从第一个奇偶校验位中排除第4个数据位会怎样?如果前三个数据位中的任何一个被翻转,第一个奇偶校验位会告诉我们,如果它们中的任何一个被翻转,第二个奇偶校验位会像往常一样告诉我们,但是……如果第一个奇偶校验位错了,可能是前三个数据位中的任何一个错了,但如果第二个奇偶校验位错了,可能是四个中的任何一个。看起来我们在这里有点缩小范围了。

如果我们再进一步,不断缩小第一个奇偶校验位覆盖的位数,我们得到下面的布局。我们在这里做了一件不可思议的事情!如果两个奇偶校验位都错了,我们知道第一个数据位错了——不仅仅是“一个位”,而是确切地知道哪个位错了!

如果你进一步推进,你可以到达这里:

说真的,花一分钟看看上面的图片。这意味着如果任何数据位被翻转,你可以告诉是哪一个并修复它,因为你知道每个圆圈必须包含偶数个一。通过扩展这个想法,你可以玩转奇偶校验位和数据位的数量来处理不同级别的错误—— broadly speaking,更多的奇偶校验位帮助你纠正更多的错误,但这意味着你用于数据的空间更少。

如果纠错码仍然令人困惑,这样想——我们创建了一堆接收无效的潜在消息,这样如果你收到它们,你就知道有问题(有效消息被称为“码字”——“纠错码”中的“码”)。当你收到一个你知道错误的消息时,你可以通过选择与你收到的内容最相似的有效码字来纠正错误(这意味着我们希望码字尽可能不同,以便任何给定的不正确消息应该是什么码字是明显的)。

这是纠正错误的数学基础,比我们之前使用的简单重复要高效得多——在我们的案例中,我们可以容纳四倍以上的数据量!下次,我们将把这些数学付诸实践。


  达科他运营Striker Security——你可以在https://strikersecurity.com/blog找到更多他的写作

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计