【问题标题】:Hiding binary values in a number list在数字列表中隐藏二进制值
【发布时间】:2016-01-08 17:44:55
【问题描述】:

我试图在数字列表中隐藏二进制值(颜色值,因此它们可以稍微改变并保持相同的含义),但我觉得这种方法有点不雅。具体来说,由于我决定区分 NULL 字符 (00000000) 和无信息的方式,我更改的数字列表比我想要的要多。因此,如果二进制字符串为 0,我将列表中的数字更改为 1。如果它有 1,我将其更改为 2。

它有效,但我想问是否有人能想到仍然符合该标准的改进。这是看似明显的异或解决方案失败的条件。以下是我正在做的简化版本:

def encode(pic_data, file_data):
    """encode pic_data with the information stored in file_data"""
    # file data is shorter than pic_data, I test for it in the real code
    new_pic_data = pic_data.copy()
    for i in range(len(file_data)):
        # I add 1 to the value of 0 or 1, because I need to be able to
        # distinguish 0 from nothing
        data_value = int(file_data[i]) + 1
        # rgb max value is 255, data_value can be 1 or 2
        if new_pic_data[i] >= 253:
            data_value *= -1
        new_pic_data[i] += data_value

    return new_pic_data


def decode(pic_data_original, pic_data_modified):
    """
    extract a binary string from the differences between the input
    data sets
    """
    # both data sets have to be the same length
    new_file_data = [abs(pic_data_original[i] - pic_data_modified[i]) - 1
                     for i in range(len(pic_data_original))]
    # the test at the end of this makes sure we do not use locations
    # where no data was stored
    return ''.join(str(i) for i in new_file_data if i >= 0)


binary_string = '01100001'  # the data to be hidden
flat_rgb_data = [18, 15, 222, 69, 151, 222, 254, 199, 21]  # the picture

# [19, 17, 224, 70, 152, 223, 253, 201, 21]
encoded_rgb_data = encode(flat_rgb_data, binary_string)

# getting binary_string back, '01100001'
decoded_data = decode(flat_rgb_data, encoded_rgb_data)

print(decoded_data)

背景,对于那些感兴趣的人:

我在这里真正做的是一些图像隐写术,其中我可以将任意文件隐藏到图片中。基本思想是图片是[(R1, G1, B1), (R2, G2, B2), ...]形式的一系列RGB值。我将它展平成一个列表并得到[R1, G1, B1, R2, G2, B2, ...]。这是上面的flat_rgb_data

然后我读取任何类型的文件,并将字节字符串转换为二进制字符串。如果其中一个字符是'0x61',则在上面的binary_string 中变为'01100001'

来自encode() 的列表被重新组合(因为没有更好的术语)并保存为图像。即使并排,它与原件的颜色差异也很难区分。如果没有原图,我什至想不出这张图片已经被修改过。

显然,每张图片都必须在视觉上很忙,并被视为一次性便笺簿,这样才能正常工作。此外,您不能使用互联网上的图片 =)。

我需要能够区分NULL 字符(00000000)与没有信息之间的区别,正如我在上面提到的一个关键标准,是某些文件格式使用NULL 字符有意义的方式。通常人们在涉及文本时会忽略这一点,因为您可以安全地删除所有 NULLs。但例如,如果您从 MS Word 文档中删除 NULLs,Word 将无法再打开它。

无论如何,谢谢你的帮助。

【问题讨论】:

  • 有几件事我不明白。 XOR 在您的代码中在哪里实现?当您可以使用不同的方法从修改后的图像中提取信息时,为什么要使用原始图像来检测差异?在您的项目中同时使用原始图像和修改后的图像是您的要求,还是您因为缺乏更好的方法而想到的?
  • @Reti43 xor 明确没有在我的代码中实现,因为它不符合能够区分 0 和无的标准。原始图像是提取信息所必需的,因为没有它就无法从修改后的图像中提取数据;数据位于文件之间的差异中。不过,如果您找到了破解一次性便笺簿的方法,请分享。
  • 一次性笔记本是什么意思?如何以及将如何在您的工作流程中使用它? 只是根据您发布的代码,我认为没有理由根据您嵌入的位将每个像素的 lsb 修改为 0 或 1。无需使用原始图像来跟踪修改,您只需从修改后的 lsbs 中提取消息。顺便说一句,如果您对算法的 XOR 和一次性填充方面有疑问,您应该考虑发布它,即使它已损坏。特别是如果它坏了。
  • @Reti43 我有效地将原始图像用作一次性便笺簿(请参阅:密码学)。我明确没有将 lsb 设置为数据值。我不确定你是否理解隐写术的意义,因为如果我这样做了,任何人都可以在没有原始图像的情况下提取数据。我正在增加和减少颜色值。如果您认为只看到修改后的值就可以恢复数据,请分享。我对 xor 没有问题,因为它不符合我的标准而且我不使用它。该程序运行良好,我只是想改进它的一部分。
  • 隐写术是在媒介中隐藏信息的艺术,你如何隐藏它,或者媒介是什么并不重要。修改像素的 lsb 值是隐写术。只有当您确切知道隐藏秘密的方式和位置时,某人才能以有意义的方式提取它们,即您的隐写算法必须保持秘密。如果要添加额外的安全层,可以随机化修改像素的顺序 (PRNG),或者在嵌入之前加密消息。通过这两种方式,攻击都需要一个密钥来成功提取数据,或者理解它。

标签: python steganography


【解决方案1】:

解决方案:永远不要使用 MS Word,反正都是垃圾! :)

更严重的是,如果我很了解您的情况,如果您不使用您的想法,您面临的唯一问题是您将不知道可能有多少尾随 NULL。 (您仍然可以在文档“内部”检测到它们。)一个肮脏的解决方案(如果烦人的格式对额外的 NULL 感到满意)是假设所有尾随 0 实际上都是为 NULL 编码。

更好的解决方案:您能否以某种方式在代码开头编码该数量的尾随 NULL?例如,如果您知道您的尾随 NULL 永远不会超过 256 个,那么您分配第一个字节来对该数字进行编码?

【讨论】:

  • Word,只是一个随机的例子(我想你知道 =)。许多文件格式都使用 NULL。无论如何,我也想到了跟踪尾随 NULL 的想法,但是在我的实际程序中,我将数据半随机地沿着图像传播(担心如果图像全部是前置的,则更容易判断图像是否已被修改)。这意味着我的价值观到处都没有信息。不过,为这个好主意投票。
  • 即使您使用半随机随机播放,解码器也必须知道要解码的随机播放。并且一旦扭转了洗牌,就不再有任何信息价值散布在整个地方。所以实际上只有尾随的 NULL 很重要。
  • 按照我现在的做法,解码器不需要知道任何东西,因为我区分了 0 和“无信息”。
  • 我明白了,您不会随机排列顺序,只是随机排列位置。好吧,您可以避免的一件简单的事情(使用 +2 和 -2)是代码 0 和 -1 和 1 和 +1,以保持绝对差异更小。显然,您不能编码 00000000(像素为 0)和 11111111(像素为 255),但您可以相应地选择图像和编码像素:拥有只有几个 0 和 255 像素的图像以及编码像素的半随机选择避免那些像素。
  • 你也可以使用成对的像素:第一个以随机绝对差值 1 表示下一个正在编码,下一个用 xor 编码。所以当你解码时,你扫描你的图像直到下一个修改的像素,然后你取下一个像素的异或来提取你的信息位,然后重复。
【解决方案2】:

感谢 Julien Bernu 的想法;我希望他能充实这个想法并发布作为答案,但已经有一段时间了,所以我决定实施它,以便其他人可以从这个想法中受益。

我并不肯定这是比我原来的算法更好的策略,但它确实解决了我的具体问题,所以值得考虑。

优点:

  • 最多将每个颜色值修改为 +/- 1(而不是 +/- 2)
  • 保留区分NULL00000000 的能力

缺点:

  • 破坏算法对称性(现在必须跟踪哪个图像是原始图像,或者在修改后的图像中标记它)
  • 无法使用具有最大或最小颜色值(0 或 255)的图像部分,具体取决于与该颜色值对齐的位

以下是经过修改的简化示例。请注意,由于一些 0 和 255 值,我必须在图像数据中添加另一个像素才能存储信息。

def encode(pic_data, file_data):
    """encode pic_data with the information stored in file_data"""
    # file data is shorter than pic_data, I test for it in the real code
    # would also need to make sure that the length of pic_data is greater than
    # the length of file_data by the number of 0s and 255s in it, to be safe
    new_pic_data = pic_data.copy()
    offset = 0
    for i in range(len(file_data)):
        # Now, 1 is 1 and 0 is -1, which still allows us to
        # distinguish 0 from nothing
        data_value = 1 if file_data[i] == '1' else -1
        # rgb max value is between 0 and 255
        while pic_data[i + offset] == 0 and data_value == -1:
            offset += 1
        while pic_data[i + offset] == 255 and data_value == 1:
            offset += 1
        new_pic_data[i + offset] += data_value

    return new_pic_data


def decode(pic_data_original, pic_data_modified):
    """
    extract a binary string from the differences between the input
    data sets
    """
    # both data sets have to be the same length
    new_file_data = ['1' if (pic_data_modified[i] - pic_data_original[i] == 1)
                     else '0' if (pic_data_modified[i] - pic_data_original[i] == -1)
                     else ''
                     for i in range(len(pic_data_original))]
    return ''.join(i for i in new_file_data)


binary_string = '01100001'  # the data to be hidden
flat_rgb_data = [18, 15, 255, 0, 151, 0, 254, 199, 21, 180, 105, 205]  # the picture

# [17, 16, 255, 1, 150, 0, 253, 198, 20, 181, 105, 205]
encoded_rgb_data = encode(flat_rgb_data, binary_string)

# getting binary_string back, '01100001'
decoded_data = decode(flat_rgb_data, encoded_rgb_data)

print(decoded_data)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-10
    • 2018-04-07
    • 1970-01-01
    • 2013-06-06
    相关资源
    最近更新 更多