【LSB图像低位隐写】字符串隐写

按照自己的理解写了一个简单的字符串隐藏在图像中的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')
    

二、效果

原图

 

隐写后的图

 

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值