You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MP3隐写项目写入文件时位翻转致解密内容乱码求助

背景

这是我正在开发的一个隐写术项目,代码预期实现以下功能:

  • 读取MP3文件(以字节形式)
  • 通过帧同步位0xFF查找帧头
  • 获取秘密消息(字符串)并转换为比特
  • 将比特插入帧头的不同位置,比如第24、29、30位
  • 将数据写回新文件
  • 尝试从新文件中恢复数据
遇到的错误

目前,将数据写回文件后,尝试从新文件中恢复数据时,部分文本会出现乱码。进一步分析后发现出现了位翻转问题。以下代码中仅实现了最多2比特的处理逻辑,增加比特数仅需为每个比特添加更多函数调用,但使用超过1比特时就会触发该问题。

代码

steg.py

import binascii
import utility


def encode_message(list_of_hex: list, message: str, num_bits: int = 1):
    """Function takes in a list of hexadecimal values in byte format, a message in string format and number of bits
    to replace (defaults to 1). Replaces the bytes in place so there is no return"""
    message_counter = 0
    message = ''.join(f"{ord(i):08b}" for i in message)
    length_of_message = len(message)
    if length_of_message % num_bits != 0:
        message += (num_bits - (length_of_message % num_bits)) * '0'
    for i in range(len(list_of_hex)):
        if message_counter < length_of_message:
            if list_of_hex[i] == b'ff' and list_of_hex[i + 1][:1] == b'f':
                if num_bits == 1:
                    current_byte = utility.convert_byte_hex_to_bin(list_of_hex[i + 2])  # Gets the next 8 bits (17-24)
                    replaced_byte = utility.encode_bit_0(current_byte, message[message_counter])  # Replace bit 24
                    message_counter += 1
                    list_of_hex[i + 2] = utility.convert_bin_to_hex(replaced_byte)
                elif num_bits == 2:
                    current_byte = utility.convert_byte_hex_to_bin(list_of_hex[i + 2])  # Gets the next 8 bits (17-24)
                    replaced_byte = utility.encode_bit_0(current_byte, message[message_counter])  # Replace bit 24
                    message_counter += 1
                    list_of_hex[i + 2] = utility.convert_bin_to_hex(replaced_byte)
                    # Encodes the next part of the header (Bits 25-32).
                    current_byte = utility.convert_byte_hex_to_bin(list_of_hex[i + 3])  # Gets the next 8 bits (25-32)
                    replaced_byte = utility.encode_bit_0(current_byte, message[message_counter])  # Replace bit 32
                    message_counter += 1
                    list_of_hex[i + 3] = utility.convert_bin_to_hex(replaced_byte)
                elif num_bits == 3:
                    ...
                elif num_bits == 4:
                    ...
                elif num_bits == 5:
                    ...
                elif num_bits == 6:  # Expect audio difference from here on out
                    ...
                elif num_bits == 7:  # Expect audio difference from here on out
                    ...
        else:
            break


def decode_message(list_of_hex: list, len_message: int, num_bits: int = 1):
    """Function takes in a list of hexadecimal values in byte format, length of the message (in terms of
    the number of characters) and number of bits per message (defaults to 1).
     Returns a list of binary values (1's and 0's)"""
    binary_list = []
    current_len = 0
    for i in range(len(list_of_hex)):
        if list_of_hex[i] == b'ff' and list_of_hex[i + 1][:1] == b'f':
            if current_len < len_message * 8:
                if num_bits == 1:
                    current_byte = utility.convert_byte_hex_to_bin(list_of_hex[i + 2])  # Gets the next 8 bits (17-24)
                    binary_list.append(current_byte[-1])  # inserts bit 24 into list
                    current_len += 1
                elif num_bits == 2:
                    current_byte = utility.convert_byte_hex_to_bin(list_of_hex[i + 2])  # Gets the next 8 bits (17-24)
                    binary_list.append(current_byte[-1])  # inserts bit 24 into list
                    current_len += 1
                    current_byte = utility.convert_byte_hex_to_bin(list_of_hex[i + 3])  # Gets the next 8 bits (25-32)
                    binary_list.append(current_byte[-1])  # inserts bit 32 into list
                    current_len += 1
                elif num_bits == 3:
                    ...
                elif num_bits == 4:
                    ...
                elif num_bits == 5:
                    ...
                elif num_bits == 6:
                    ...
                elif num_bits == 7:
                    ...
            else:
                break
    return binary_list

def text_from_bits(bits, encoding='utf8', errors='surrogatepass'):
    """Function takes in a string of bits.
    Parameters that can be overriden: Encoding and errors
    Returns text from a list of binary values (1's and 0's)"""
    n = int(bits, 2)
    return n.to_bytes((n.bit_length() + 7) // 8, 'big').decode(encoding, errors) or '\0'


def write_secret_to_file(filename: str, secret: str, num_bits: int = 1):
    """Function takes in the filename of mp3 file, secret to be encoded inside and number of bits to use.
    Writes the secret message into a new file called secret.mp3 which is created in the same directory"""

    encodelist = utility.read_file_into_hex_list(filename)
    encode_message(encodelist, secret, num_bits)
    with open('secret.mp3', 'wb') as filewrite:
        filewrite.write(binascii.unhexlify(b''.join(encodelist)))


def get_secret_from_file(filename: str, msg_len: int, num_bits: int = 1):
    """Function takes in the filename of the mp3 file which has a secret inside, the length of the secret message
    (in number of characters) and number of bits to use. Returns the decoded secret"""

    decodelist = utility.read_file_into_hex_list(filename)
    decoded_byte = decode_message(decodelist, msg_len, num_bits)
    decoded_byte_list = [decoded_byte[i:i + 8] for i in range(0, len(decoded_byte), 8)]
    char_list = []
    for i in decoded_byte_list:
        try:
            char_list.append(text_from_bits(''.join(i)))
        except UnicodeDecodeError:
            break
    return ''.join(char_list)

utility.py

import binascii


def encode_bit_0(bin_str: str, bit: str):
    """Function takes in the byte (in terms of binary) to manipulate and a bit to encode (1 or 0). Changes bit 0.
     Returns the encoded value as a string """
    replaced_byte = bin_str[:-1] + bit  # Replaces bit 0 aka LSB
    return replaced_byte  # padding to ensure 2 digits


def encode_bit_1(bin_str: str, bit: str):
    """Function takes in the byte (in terms of binary) to manipulate and a bit to encode (1 or 0). Changes bit 1.
     Returns the encoded value as a string """
    replaced_byte = bin_str[:-2] + bit + bin_str[-1]  # Encodes bit 1
    return replaced_byte

...

def convert_bin_to_hex(bin_str: str):
    """Takes in a binary string (string of 1's and 0's) and formats it into the hexadecimal value"""
    return bytes(f'{int(bin_str, 2):x}', 'utf8').zfill(2)  # padding to ensure 2 digits


def convert_byte_hex_to_bin(hex_str: bytes):
    """Takes in a hex string in byte form and formats it into a binary string"""
    return bin(int(hex_str, 16))[2:].zfill(8)


def read_file_into_hex_list(file: str):
    with open(file, 'rb') as fileread:
        file_hex_str = binascii.hexlify(fileread.read())

    return [file_hex_str[i:i + 2] for i in range(0, len(file_hex_str), 2)]

main.py

import steg

num_bits = 1
msg = 'Test'

steg.write_secret_to_file('audio.mpeg', msg, num_bits)

print(steg.get_secret_from_file('secret.mp3', len(msg), num_bits))

内容的提问来源于stack exchange,提问作者Ziv Ofir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:30:54