图片隐写之LSB(Least Significant Bit)原理及其代码实现

本文详细介绍了隐写术中的LSB隐写技术,包括其原理,如何将秘密信息嵌入图片,以及如何通过Python实现LSB隐写和数据还原的过程。重点在于理解如何利用图片的最低有效位存储和隐藏信息,以及如何确保信息的安全传输。
摘要由CSDN通过智能技术生成

1. 什么是隐写?

隐写术是一门关于信息隐藏的技巧与科学,所谓信息隐藏指的是不让除预期的接收者之外的任何人知晓信息的传递事件或者信息的内容。隐写术的英文叫做Steganography,来源于特里特米乌斯的一本讲述密码学与隐写术的著作Steganographia,该书书名源于希腊语,意为“隐秘书写”。

2. 什么是图片隐写?

图片隐写术这项技术可以将秘密信息嵌入到图片媒介中而不损坏它的载体的质量。第三方既觉察不到秘密信息的存在,也不知道存在秘密信息。因此密钥、数字签名和私密信息都可以在开放的环境(如Internet或者内联网)中安全的传送。简单概括就是信息明明就在眼前,但是你却视而不见

3. LSB隐写的原理

在png图片的存储中,每个颜色表示需要有8bit,即有256种颜色,一共包含256的三次方个颜色,即16777216中颜色,人类的眼睛可以区分约1,000万种不同的颜色,剩下无法区分的颜色就有6777216。
在这里插入图片描述
那么什么是LSB呢,每个像素点的颜色可以用十进制0~255的数值表示,那么上图中的RGB(218,150,149)表示成二进制为:
在这里插入图片描述
LSB隐写就是修改RGB颜色分量的最低二进制位也就是最低有效位(LSB),而人类的眼睛不会注意到这前后的变化,我们仅对RGB中的最低位进行修改,如当前像素位点最后一位修改成1,1,0.则上述RGB变成218->219:
在这里插入图片描述
上述变化很难用肉眼察觉到,而且每一个像素位点携带了一位信息,那么我们可以利用八个字节的最低位存储一个比特信息,而该比特信息则可以转化为ASCII字符,从而达到隐写信息的目的。

4. 如何实现LSB隐写?

import numpy as np
import PIL.Image as Image

# 读取图片的像素信息
picture = Image.open('./pic/pic.jpg')
pic_data = np.array(picture)

# 读取要隐写的文件,长度为4893
with open('./pic/secret.py', encoding="utf-8") as file:
    secrets = file.read()

# 将图片拷贝一份,作为最终的图片数据
im_data = np.array(picture.copy()).ravel().tolist()

def cover_lsb(bin_index, data):
    '''
    :param bin_index:  当前字符的ascii的二进制
    :param data: 取出数组像素的八个数值
    :return: LSB隐写后的字符
    '''
    res = []
    for i in range(8):
        data_i_bin = bin(data[i])[2:].zfill(8)
        if bin_index[i] == '0':
            data_i_bin = data_i_bin[0:7] + '0'
        elif bin_index[i] == '1':
            data_i_bin = data_i_bin[0:7] + '1'
        res.append(int(data_i_bin, 2))
    return res


pic_idx = 0
# 采用LSB隐写技术,横向取数据,每次取9个数据,改变8个像素最低位
res_data = []
for i in range(len(secrets)):
    # 拿到隐写文件的字符ascii数值, 并转换为二进制,填充成八位
    index = ord(secrets[i])
    bin_index = bin(index)[2:].zfill(8)
    # 对数据进行LSB隐写,替换操作
    res = cover_lsb(bin_index, im_data[pic_idx * 8: (pic_idx + 1) * 8])
    pic_idx += 1
    res_data += res
# 对剩余未填充的数据进行补充填充,防止图像无法恢复
res_data += im_data[pic_idx * 8:]

# 将新生成的文件进行格式转换并保存,此处一定保存为压缩的png文件
new_im_data = np.array(res_data).astype(np.uint8).reshape((pic_data.shape))
res_im = Image.fromarray(new_im_data)
res_im.save('./pic/res_encode.png')

5. 如何实现隐写数据还原?

import numpy as np
import PIL.Image as Image

# 打开隐写文件
picture = Image.open('./pic/res_encode.png')
pic_datas = np.array(picture).ravel().tolist()

# 字符的长度为4893
with open('./pic/secret.py', encoding="utf-8") as file:
    secrets = file.read()

str_len = len(secrets)
print('字符的长度为:', str_len)

# 将图片拷贝一份,作为最终的图片数据
im_data = np.array(picture.copy()).ravel().tolist()


def lsb_decode(data):
    '''
    :param bin_index:  当前字符的ascii的二进制
    :param data: 取出数组像素的八个数值
    :return: LSB隐写后的字符
    '''
    str = ''
    for i in range(len(data)):
        print(bin(data[i])[2:])
        data_i_bin = bin(data[i])[2:][-1]
        str += data_i_bin
    return str


pic_idx = 0
# 采用LSB隐写技术,横向取数据,每次取9个数据,改变8个像素最低位
res_data = []

for i in range(len(secrets)):
    # 拿到第i个数据,转换成二进制
    data = im_data[i * 8: (i + 1) * 8]
    data_int = lsb_decode(data)
    # 找到最低位
    res_data.append(int(data_int, 2))

# 将二进制数据转换成ASCII
str_data = ''
for i in res_data:
    temp = chr(i)
    str_data += temp
print(str_data)

6. 总结

基本的LSB原理很简单,最容易实现,但是鲁棒性不佳,后续更好的隐藏信息,则会通过数字水印技术实现,后面文章再进行更新。

  • 20
    点赞
  • 125
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
没有积分的私聊我 看到消息百分百发给你 1、算法核心: 1、读取图片A,获得其RGB三个通道数据并转换成三个矩阵a1,a2,a3。 2、读取文件B,将其转换成比特流b。 3、遍历b,得到比特b1,b2,b3,b4,b5,b6等等,将b1代替a1第一个元素的最低位,将b2代替a2第一个元素的最低位,将b3代替a3第一个元素的最低位,将b4代替a1第二个元素的最低位,以此类推。 2、具体实现: 1、隐写: 1、使用java ImageIO读取图片,获取其RGB通道信息。 2、使用java NIO读取被嵌入的文件,将其转换为byte数组,需要特别指出的是原生方法得到是byte类型的数组,但是算法实现需要更加精细的操作,所以还需要对得到的byte数组进行进一步的转换封装,将其转换成形如10101的数组。例如,读取文件得到byte数组的第一个元素为63,需将63转换为00111111数组。并且保存好文件的长度。 3、按照算法,遍历形如10101的数组 1、如果遍历到的值为0,将矩阵对应的矩阵元素与0xfe进行与运算,将最低位置为0 2、如果遍历到的值为1,将矩阵对应的矩阵元素与0x01进行或运算,将最低位置为1 4、将步骤3得到的经过经过隐写的矩阵写为一张新的图片。 3、读取 1、使用java ImageIO读取图片,获取其RGB通道信息。 2、使用隐写步骤3得到的文件长度,遍历图片的像素矩阵,需要特别指出的是因为后续步骤还需要进行进一步的转化,所以这一步是将得到的“100100......”序列每八位封装为一个数组,最终得到一些数组集合,每个数组包含八位二进制序列。 3、将步骤2得到的数组进行转换,例如00111111应该转换为byte类型数值为63的数字,10111111转换为-63。这一步会得到一个byte类型的数组。 4、将步骤3得到的byte类型数组写入文件,需要指出的是写入的文件形式应该和隐写模块步骤二中读入的文件形式一致。 3、程序使用方法 1、安装Java8 2、使用命令行进入jar文件所在目录下,使用命令 java -jar 2016115130.jar 3、安装提示输入嵌入和被嵌入的文件名字,注意路径问题
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

l8947943

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值