我有一些代码使用 LSB 隐写术来隐藏视频帧中的加密数据。我遇到的主要问题是我不知道我能做些什么来使视频更能抵抗 YouTube 压缩/压缩。我也找不到更好的隐写库来提供帮助。
就我的尝试而言,我考虑过使用 ECC,但我使用的库“stegano”除了“red”和“lsb”之外实际上没有任何东西。我还考虑过将生成的视频编辑为随机颜色的一大帧,也许会使压缩效果不那么有效,但它仍然不起作用。
就我所说的“Youtube 压缩”而言,视频最终会上传到不公开的 YouTube,然后我可以下载它并显示隐藏的加密数据,然后从那里开始。
以下是我当前使用的代码,无需压缩即可工作。
这段代码工作得很好,并且完全符合我的要求。问题是当我将视频上传到 YouTube 并从 YouTube 下载视频时,它会损坏。
import cv2
import numpy as np
import secrets
import string
import os
import beaupy #Teminal User Interface | TUI. aka nice menu
from pystyle import Colors, Colorate
import math
from tqdm import tqdm
from stegano import lsb #what I use to hide and reveal data.
import shutil
import magic
import gcm
import base64
from pytube import YouTube #downloading video from youtube
from subprocess import call,STDOUT
def clear():
os.system('clear||cls')
def get_file_type(bytes_data):
mime = magic.Magic(mime=True)
file_type = mime.from_buffer(bytes_data)
return file_type.split('/')[1]
def generate_filename():
alphabet = string.ascii_letters + string.digits
filename = ''.join(secrets.choice(alphabet) for i in range(12)) + ".mp4"
return filename
def generate_video():
output_filename = generate_filename()
duration=7
width=640
height=480
fps=30
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_filename, fourcc, fps, (width, height))
# Generate "random" background color | BGR from left to right
background_color = tuple(secrets.randbelow(256) for i in range(3)) #(0, 0, 255) = red
# Create frames with "random" background color
for i in tqdm(range(int(fps * duration)), desc="Creating video..."):
frame = np.zeros((height, width, 3), dtype=np.uint8)
frame[:, :, :] = background_color
out.write(frame)
out.release()
cv2.destroyAllWindows()
clear()
return output_filename
def clean_tmp(path=".tmp"):
if os.path.exists(path):
shutil.rmtree(path)
print("[INFO] tmp files have been cleaned up.\n")
def split_string(s_str,count=25): #up to how many frames the data is embedded into.
per_c=math.ceil(len(s_str)/count)
c_cout=0
out_str=''
split_list=[]
for s in s_str:
out_str+=s
c_cout+=1
if c_cout == per_c:
split_list.append(out_str)
out_str=''
c_cout=0
if c_cout!=0:
split_list.append(out_str)
return split_list
def frame_extraction(video):
if not os.path.exists(".tmp"):
os.makedirs(".tmp")
temp_folder=".tmp"
print("[INFO] tmp directory has been created")
vidcap = cv2.VideoCapture(video)
count = 0
while True:
success, image = vidcap.read()
if not success:
break
cv2.imwrite(os.path.join(temp_folder, "{:d}.png".format(count)), image)
count += 1
def encode_video(file_name):
clear()
key_data = beaupy.prompt("Data for key gen")
if not key_data:
clear()
return None
key_data = key_data.encode()
clear()
eKey = gcm.keygen(key_data) #Returns random bytes from Argon2id and will return "None" if what's provided is less than 100 characters.
if not eKey:
return None
save_me = base64.b64encode(eKey) #for saving eKey to decrypt later.
input(f'Save this key so you can decrypt and decode later: {save_me.decode()}\n\nPress "enter" to contine...')
clear()
with open(file_name, 'rb') as rb:
data = rb.read()
data_enc = gcm.stringE(enc_data=data, key=eKey) #encrypts data and returns base64 encoded string
video_file = generate_video()
frame_extraction(video_file)
root=".tmp/"
split_string_list = split_string(data_enc)
for i in range(0, len(split_string_list)):
f_name=f"{root}{i}.png"
secret_enc=lsb.hide(f_name, split_string_list[i])
secret_enc.save(f_name)
print(f"[INFO] frame {f_name} holds {split_string_list[i]}")
output_vid = '.tmp_vid.mp4'
call(["ffmpeg", "-i", ".tmp/%d.png" , "-vcodec", "png", output_vid, "-y"], stdout=open(os.devnull, "w"), stderr=STDOUT)
cwd = os.getcwd()
os.walk(f".tmp/{output_vid}", cwd)
clean_tmp()
os.rename(output_vid, video_file)
def decode_video(video, b64_enc_key):
frame_extraction(video)
secret=[]
root=".tmp/"
for i in range(len(os.listdir(root))):
f_name=f"{root}{i}.png"
try:
secret_dec=lsb.reveal(f_name)
print(f"Found data in: {f_name}. Data: {secret_dec}")
except Exception:
break
secret.append(secret_dec)
result = ''.join([i for i in secret]) # base64 string
clean_tmp()
dKey = base64.b64decode(b64_enc_key)
str_dcr = gcm.stringD(dcr_data=result, key=dKey)
gcm.clear()
return str_dcr
# ... (if __name__ == '__main__': code and the creation of the beaupy menu options would be below this line)
我正在寻求帮助的是如何有效地处理压缩并简单地使用LSB/上面显示的代码。如果“stegano”库不够好,那么推荐任何其他更好的库或方法将非常感激。如果有人有其他文档可以分享,那也会有帮助。
请随意帮助编写一个或两个函数来帮助我处理视频的压缩问题。
另外..如果 LSB 无论如何都不起作用,那么更好的选择是什么?您能否提供带有示例的链接/文档,供我使用,以便我可以使用。 (这可以在上面显示的代码以及我如何使用多个框架的上下文中工作)
YouTube 重新压缩上传到其中的所有视频。尽管水印的设计可以在重新压缩后继续存在,但基本的隐写术(例如 LSB)会因此被完全破坏。
能够在再压缩中幸存下来的鲁棒隐写术是一个活跃的研究领域。
恐怕您需要等待很长时间才能找到一个好的、既定的解决方案来解决您的问题。