python - 非纯文本文件的 Steganographer 文件处理错误
python - Steganographer File Handling Error for non plain-text files
关于读取 Python 中的各种文件,我已经构建了 a Python Steganographer and am trying to add a GUI to it. After 。因为,隐写器只能对图像中的字节进行编码。我想添加支持以直接对其中的任何扩展名和编码的文件进行编码。为此,我正在读取二进制文件并尝试对其进行编码。它适用于基本上包含纯文本 UTF-8 的文件,因为它可以轻松编码 .txt
和 .py
文件。
我的更新代码是:
from PIL import Image
import os
class StringTooLongException(Exception):
pass
class InvalidBitValueException(Exception):
pass
def str2bin(message):
binary = bin(int.from_bytes(message, 'big'))
return binary[2:]
def bin2str(binary):
n = int(binary, 2)
return n.to_bytes((n.bit_length() + 7) // 8, 'big')
def hide(filename, message, bits=2):
image = Image.open(filename)
binary = str2bin(message) + '00000000'
if (len(binary)) % 8 != 0:
binary = '0'*(8 - ((len(binary)) % 8)) + binary
data = list(image.getdata())
newData = []
if len(data) * bits < len(binary):
raise StringTooLongException
if bits > 8:
raise InvalidBitValueException
index = 0
for pixel in data:
if index < len(binary):
pixel = list(pixel)
pixel[0] >>= bits
pixel[0] <<= bits
pixel[0] += int('0b' + binary[index:index+bits], 2)
pixel = tuple(pixel)
index += bits
newData.append(pixel)
image.putdata(newData)
image.save(os.path.dirname(filename) + '/coded-'+os.path.basename(filename), 'PNG')
return len(binary)
def unhide(filename, bits=2):
image = Image.open(filename)
data = image.getdata()
if bits > 8:
raise InvalidBitValueException
binary = ''
index = 0
while not (len(binary) % 8 == 0 and binary[-8:] == '00000000'):
value = '00000000' + bin(data[index][0])[2:]
binary += value[-bits:]
index += 1
message = bin2str(binary)
return message
现在,当我试图在其中隐藏 .pdf
或 .docx
文件时,问题就来了。有几件事正在发生:
1) Microsoft Word 或 Adobe Acrobat 显示文件已损坏。
2) 文件大小从 40KB 大幅减少到 3KB,这是一个明显的错误迹象。
我认为这背后的原因可能是该文件包含一个 NULL 字符读取,我的程序不会进一步读取它。你有什么替代方案吗?
我想更改结束字节,但结果可能仍然相同,因为文件可能包含该字节。
再次感谢!
当您确定标记序列不会出现在您的消息流中时,您可以使用 end-of-stream (EOS) 标记。当你不能保证时,你有两个选择:
- 创建一个更复杂的 EOS 标记,由许多字节组成。证明不会像以前那样出现同样的问题可能会很麻烦,或者
- 在您的消息开头添加一个 header,它编码要读取多少 bits/bytes 以完成完整的消息提取。
一般来说,只要我事先有我想要传输的信息,我就会使用 header 并且只在我不知道我的字节流何时终止时才依赖 EOS 标记,例如,on-the-fly 压缩.
对于嵌入,您的目标应该是:
- 获取二进制字符串
- 测量它的长度
- 将该整数转换为固定大小的二进制,比如 32 位
- 将该位串附加在您的消息位串前面
- 将所有这些嵌入到您的封面媒体中
提取:
- 提取前 32 位
- 将它们转换为整数以获得您的消息位串长度
- 从索引32开始提取需要的位数
- 转换回字节流并保存到文件
作为奖励,您可以将各种信息添加到 header,例如原始文件的名称。只要它全部以某种方式编码,您以后就可以提取它。例如。
header = 4 bytes for the length of the message string +
1 byte for the number of characters in the filename +
that many bytes for the filename
关于读取 Python 中的各种文件,我已经构建了 a Python Steganographer and am trying to add a GUI to it. After .txt
和 .py
文件。
我的更新代码是:
from PIL import Image
import os
class StringTooLongException(Exception):
pass
class InvalidBitValueException(Exception):
pass
def str2bin(message):
binary = bin(int.from_bytes(message, 'big'))
return binary[2:]
def bin2str(binary):
n = int(binary, 2)
return n.to_bytes((n.bit_length() + 7) // 8, 'big')
def hide(filename, message, bits=2):
image = Image.open(filename)
binary = str2bin(message) + '00000000'
if (len(binary)) % 8 != 0:
binary = '0'*(8 - ((len(binary)) % 8)) + binary
data = list(image.getdata())
newData = []
if len(data) * bits < len(binary):
raise StringTooLongException
if bits > 8:
raise InvalidBitValueException
index = 0
for pixel in data:
if index < len(binary):
pixel = list(pixel)
pixel[0] >>= bits
pixel[0] <<= bits
pixel[0] += int('0b' + binary[index:index+bits], 2)
pixel = tuple(pixel)
index += bits
newData.append(pixel)
image.putdata(newData)
image.save(os.path.dirname(filename) + '/coded-'+os.path.basename(filename), 'PNG')
return len(binary)
def unhide(filename, bits=2):
image = Image.open(filename)
data = image.getdata()
if bits > 8:
raise InvalidBitValueException
binary = ''
index = 0
while not (len(binary) % 8 == 0 and binary[-8:] == '00000000'):
value = '00000000' + bin(data[index][0])[2:]
binary += value[-bits:]
index += 1
message = bin2str(binary)
return message
现在,当我试图在其中隐藏 .pdf
或 .docx
文件时,问题就来了。有几件事正在发生:
1) Microsoft Word 或 Adobe Acrobat 显示文件已损坏。
2) 文件大小从 40KB 大幅减少到 3KB,这是一个明显的错误迹象。
我认为这背后的原因可能是该文件包含一个 NULL 字符读取,我的程序不会进一步读取它。你有什么替代方案吗?
我想更改结束字节,但结果可能仍然相同,因为文件可能包含该字节。
再次感谢!
当您确定标记序列不会出现在您的消息流中时,您可以使用 end-of-stream (EOS) 标记。当你不能保证时,你有两个选择:
- 创建一个更复杂的 EOS 标记,由许多字节组成。证明不会像以前那样出现同样的问题可能会很麻烦,或者
- 在您的消息开头添加一个 header,它编码要读取多少 bits/bytes 以完成完整的消息提取。
一般来说,只要我事先有我想要传输的信息,我就会使用 header 并且只在我不知道我的字节流何时终止时才依赖 EOS 标记,例如,on-the-fly 压缩.
对于嵌入,您的目标应该是:
- 获取二进制字符串
- 测量它的长度
- 将该整数转换为固定大小的二进制,比如 32 位
- 将该位串附加在您的消息位串前面
- 将所有这些嵌入到您的封面媒体中
提取:
- 提取前 32 位
- 将它们转换为整数以获得您的消息位串长度
- 从索引32开始提取需要的位数
- 转换回字节流并保存到文件
作为奖励,您可以将各种信息添加到 header,例如原始文件的名称。只要它全部以某种方式编码,您以后就可以提取它。例如。
header = 4 bytes for the length of the message string +
1 byte for the number of characters in the filename +
that many bytes for the filename