隐藏数字列表中的二进制值

时间:2015-10-11 02:17:53

标签: python steganography

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

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

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',则该字符在'01100001'上方变为binary_string

来自encode()的列表被重新组合(缺少更好的术语)并保存为图像。即使是并排,它与原始的颜色差异也难以区分。没有原版,我甚至无法想到图像已被修改。

显然,每张图片必须在视觉上忙碌,并将其视为一次性打击垫才能使其正常工作。此外,您无法使用互联网上的图片=)。

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

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

2 个答案:

答案 0 :(得分:1)

解决方案:永远不要使用MS Word,它的垃圾! :)

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

更好的解决方案:你能以某种方式编码代码开头的那些尾随NULL吗?例如,如果您知道永远不会有超过256个尾随NULL,则分配第一个字节来编码该数字?

答案 1 :(得分:0)

感谢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)