按照自己的理解写了一个简单的字符串隐藏在图像中的python代码
前言
脱胎于内容安全的大作业~ 目前第一阶段,只完成了字符串隐藏在图像中
步过图像隐藏在图像应该异曲同工,之后实现~
一、代码
图像的output路径和input路径写死了,这个需要自己调整一下
from PIL import Image
# 定义 ANSI 转义码
green_background = "\033[48;5;113m"
red_background = "\033[48;5;203m"
yellow_background = "\033[48;5;226m"
blue_background = "\033[48;5;159m"
black_font = "\033[30m"
reset = "\033[0m"
###定义的一些具有背景色的print
def greebbk_print(str,end=None):
if type(str) != type("123"):
return -1
print(green_background+black_font+str+reset,end=end)
def redbk_print(str,end=None):
if type(str) != type("123"):
return -1
print(red_background+black_font+str+reset,end=end)
def yellowbk_print(str,end=None):
if type(str) != type("123"):
return -1
print(yellow_background+black_font+str+reset,end=end)
def bluebk_print(str,end=None):
if type(str) != type("123"):
return -1
print(blue_background+black_font+str+reset,end=end)
def string2binstream(string):
if type(string)!=type('123'):
redbk_print('[-]Invalid Input!')
return -1
string=str(len(string))+':'+string
binstream=''
for c in string:
binstream+=bin(ord(c))[2:].zfill(8)
return binstream
def binstream2string(binary_str):
# 检查输入字符串是否只包含 '1' 或 '0'
string=''
if not all(bit in '01' for bit in binary_str):
redbk_print("输入字符串应只包含 '1' 或 '0'.")
return -1
for i in range(0,len(binary_str),8):
string+=chr(int(binary_str[i:i+8],2))
return string
### 处理RGBA图像的隐写
def RGBA_info(image,binInfo,output_path='output.png'):
'''
binInfo形如:'010001100011011110101'
隐写方法为:
FOR CLOUMN:
FOR ROW:
FOR R->G->B->A:
FOR MASKBITS
REWRITE BIT
'''
if image.mode!='RGBA':
redbk_print('[-] Not [RGBA] image')
return -1
### 创建一个等大小的空白画布,以便进行隐写信息添加
steg_pic=Image.new('RGBA',image.size,(0,0,0,0))
### 记录选择的RGBA隐写位
bitsMask=[]
### 选择RGBA隐写的位
bluebk_print('[~]Now you are going to choose bits you wanna use to hide info in channels:')
bluebk_print('[~]You have to input numbers from [0,7] splited by comma like: 0,3,7')
for channel in ['r','g','b','a']:
yellowbk_print(f'[~]Channel {channel}:')
try:
bluebk_print('[~]Input:',end='')
bits=input().strip(',')
if not len(bits):
bitsMask.append([])
continue
# print(bits)
bits=bits.split(',')
for bit in bits:
if int(bit)<0 or int(bit)>=8:
raise ValueError
bitsMask.append(bits)
except ValueError:
redbk_print('[-]Invalid Input!')
return -1
### 开始隐写
index=0
cloumn,row=image.size
for x in range(cloumn):
for y in range(row):
pixel=list(image.getpixel((x,y)))
for channel in range(4):
if index>=len(binInfo):
break
### 取出需要修改的掩码
for bit in bitsMask[channel]:
if int(binInfo[index]):
pixel[channel]=pixel[channel]|(1<<int(bit))
else:
pixel[channel]=pixel[channel]&(255-(1<<int(bit)))
index+=1
if index>=len(binInfo):
break
steg_pic.putpixel((x,y),tuple(pixel))
steg_pic.save(output_path)
greebbk_print(f'[+]Success hide info to {output_path}')
### 处理RGBA图像的隐写
def RGBA_reinfo(image,output_path='output.png'):
'''
binInfo形如:'010001100011011110101'
隐写方法为:
FOR CLOUMN:
FOR ROW:
FOR R->G->B->A:
FOR MASKBITS
REWRITE BIT
'''
if image.mode!='RGBA':
redbk_print('[-] Not [RGBA] image')
return -1
### 记录选择的RGBA隐写位
bitsMask=[]
### 选择RGBA隐写的位
bluebk_print('[~]Now you are going to choose bits you wanna use to hide info in channels:')
bluebk_print('[~]You have to input numbers from [0,7] splited by comma like: 0,3,7')
for channel in ['r','g','b','a']:
yellowbk_print(f'[~]Channel {channel}:')
try:
bluebk_print('[~]Input:',end='')
bits=input().strip(',')
if not len(bits):
bitsMask.append([])
continue
# print(bits)
bits=bits.split(',')
for bit in bits:
if int(bit)<0 or int(bit)>=8:
raise ValueError
bitsMask.append(bits)
except ValueError:
redbk_print('[-]Invalid Input!')
return -1
binInfo=''
### 开始隐写信息回复
cloumn,row=image.size
for x in range(cloumn):
for y in range(row):
pixel=list(image.getpixel((x,y)))
for channel in range(4):
### 取出需要掩码对应位的信息
for bit in bitsMask[channel]:
binInfo+=str(int((pixel[channel]&1<<int(bit))!=0))
string=binstream2string(binInfo)
colon_index=string.index(':')
length=int(string[:colon_index])
string2=string[colon_index+1:]
string2=string2[:length]
greebbk_print(f'[+]The hidden info: {string2}')
def main(path=None):
bluebk_print('================================================')
bluebk_print('Choose the image to hide info:',end='')
input()
image=Image.open('cat.png')
bluebk_print('Enter the string to be hidden:',end='')
string=input()
bluebk_print('Input the name of output file:',end='')
input()
binstream=string2binstream(string)
bluebk_print('------------------------------------------------')
if image.mode=='1':
yellowbk_print(f'[!]Image Mode:{image.mode} [二值图像]')
redbk_print('[-]二值图像无法使用LSB低位隐写')
elif image.mode=='L':
greebbk_print(f'[+]Image Mode:{image.mode} [灰度图像]')
yellowbk_print('[!]对灰度值图像进行LSB隐写可能会效果不佳')
elif image.mode=='P':
greebbk_print(f'[+]Image Mode:{image.mode} [8位调色板图像]')
greebbk_print('[+]正在将图像转换为RGBA模式...')
image=image.convert('RGBA')
greebbk_print('[+]转换成功')
greebbk_print('[+]Image Mode:RGBA [真彩色加透明度]')
RGBA_info(image,binstream)
elif image.mode=='RGB':
greebbk_print(f'[+]Image Mode:{image.mode} [真彩色图像]')
greebbk_print('[+]正在将图像转换为RGBA模式...')
image=image.convert('RGBA')
greebbk_print('[+]转换成功')
greebbk_print('[+]Image Mode:RGBA [真彩色加透明度]')
RGBA_info(image,binstream)
elif image.mode=='RGBA':
greebbk_print(f'[+]Image Mode:{image.mode} [真彩色加透明度')
RGBA_info(image,binstream)
else:
redbk_print('[-]Unknown or Unsupported Mode!')
return -1
image2=Image.open('output.png')
RGBA_reinfo(image2)
if __name__ == '__main__':
main()
# string2binstream('abcdefg')
# binstream2string('01100001011000100110001101100100011001010110011001100111')
二、效果
原图
隐写后的图