0x00 目录
0x01 问题描述
基于LSB算法实现在320x240的灰度图像上隐藏秘密信息,并分析LSB算法的健壮性(抗攻击)。
0x02 LSB算法原理
该算法包含秘密信息嵌入和提取两部分。嵌入:将二进制表示的秘密信息中的每一位,按照某种顺序(例如先按列再按行,如图1所示)依次存储在载体图像像素值的最低位上。提取:按照嵌入时的顺序依次从嵌有秘密信息的载体图像上提取像素值的最低位,将其组合后即可得到秘密信息。
0x03 LSB算法实现
使用Python编码实现基于LSB算法的秘密信息嵌入与提取。秘密信息嵌入算法如图2所示,秘密信息提取算法如图3所示。LSB算法完整代码:https://github.com/Chentingz/LSB-Steganography
0x04 实验结果分析
实验数据
- 秘密信息:”secret text is hidden in image using LSB algorithm\n2019.11.21”
- 原始载体图像名:raw_img.bmp
- 原始载体图像大小:320 x 240
- 原始载体图像通道数:单通道(灰度图像)
- 原始载体图像:见图4
实验结果
- 嵌入算法:按照图2的算法从文件中读取秘密信息后嵌入到原始载体图像中,从图5可见,嵌入前后的载体图像无明显变化。
- 提取算法:按照图3算法对嵌入秘密信息的载体图像提取出秘密信息,由图6可见,提取结果与嵌入前的秘密信息一致。
0x05 健壮性分析
对嵌有秘密信息的载体图像分别采用高斯噪声和椒盐噪声处理,然后提取秘密信息,观察秘密信息是否遭到破坏,噪声处理前后的图像对比如图7所示。
采用图3中的提取算法,分别对高斯噪声和椒盐噪声处理过的图像提取信息,提取结果如图8所示,可见对基于LSB嵌入秘密信息的图像进行噪声处理后,秘密信息将遭到不同程度的破坏,LSB算法抗攻击性差。
0x06 关键代码
秘密信息嵌入
from PIL import Image
eof_str = "00000000"
"""
将秘密信息嵌入到载体图像中
首先将秘密信息转换成二进制字符串,如"a" -> "0110 0001"
在二进制字符串的末尾添加两个0x0000的ASCII码作为结束标志,如"0110 0001" -> "0110 0001 0000 0000 0000 0000"
按照图像从上到下,从左到右的顺序,将串的每一位依次插入到像素的最低位中,每一个像素用一个字节表示
@param text: string类型的秘密信息
@param raw_img: image类型原始载体图像
@return: image类型嵌入秘密信息后的图像
"""
def insert_text_to_image(text, raw_img):
mod_img = raw_img.copy()
width = mod_img.size[0]
height = mod_img.size[1]
binstr = text2binarystring(text)
binstr += eof_str + eof_str
i = 0
for w in range(width):
for h in range(height):
if i == len(binstr):
break
value = mod_img.getpixel((w,h))
value = mod_lsb(value, binstr[i])
mod_img.putpixel((w,h), value)
i=i+1
return mod_img
"""
将秘密信息转换成二进制串
先将字符转换成对应的ASCII码,然后转二进制,最后8位对齐,不足的前面用0填充
@param text: string类型表示的秘密信息
@return: string类型表示的二进制串
"""
def text2binarystring(text):
binstr = ""
for ch in text :
# ord(ch): 将ch转换成十进制数 bin():转换成0b开头的二进制字符串 zfill:返回指定长度字符串,不足的前面填充0
binstr += bin(ord(ch)).replace('0b', '').zfill(8)
return binstr
"""
将value的最低位替换成bit,返回修改后的value
@param value: int类型表示的像素值
@param bit: string类型表示的嵌入位
@return: int类型表示的修改后的像素值
"""
def mod_lsb(value, bit):
str = bin(value).replace('0b', '').zfill(8)
lsb = str[len(str)-1]
if lsb != bit :
str = str[0:len(str)-1] + bit
return int(str, 2)
秘密信息提取
from PIL import Image
eof = chr(int(eof_str, 2))
"""
从图像中提取秘密信息,返回string类型的秘密信息
@param mod_img: 嵌入秘密信息后的图像
@return: string类型表示的秘密信息
"""
def get_text_from_image(mod_img):
width = mod_img.size[0]
height = mod_img.size[1]
bytestr = ""
text = ""
countEOF = 0
for w in range(width):
for h in range(height):
value = mod_img.getpixel((w,h))
bytestr += get_lsb(value)
if len(bytestr) == 8 :
# 转换成ASCII码
# 例:"0110 0001" -> 97 -> 'a'
ch = chr(int(bytestr, 2))
if ch == eof :
countEOF = countEOF + 1
if countEOF == 2 :
break
text += ch
bytestr = ""
return text
"""
返回像素值的lsb
@param value: int类型表示的像素值
@return: string类型表示的像素值最低位
"""
def get_lsb(value):
str = bin(value).replace('0b', '').zfill(8)
lsb = str[len(str)-1]
return lsb
加噪处理
import cv2
import matplotlib.pyplot as plt
import skimage.util as ski
import LSB
from PIL import Image
mod_img_path = "./test/mod_img.bmp"
img_gaussian_path = "./test/img_gaussian.bmp"
img_sp_path = "./test/img_sp.bmp"
img_mod_and_noises_compare_path = "./test/img_mod_and_noises_compare.png"
"""
对嵌有秘密信息的载体图像加噪处理,并保存
"""
def noise():
mod_img = cv2.imread(mod_img_path, cv2.IMREAD_GRAYSCALE)
img_copy = mod_img.copy()
# 高斯噪声处理后的嵌有秘密信息的载体图像
img_gaussian = ski.random_noise(img_copy, mode="gaussian", seed=None, clip=True, mean=0,var=0.05)
img_gaussian *= 255
# 椒盐噪声处理后的嵌有秘密信息的载体图像
img_sp = ski.random_noise(img_copy, mode="s&p", seed=None, clip=True, amount=0.1)
img_sp *= 255
# 保存加噪后的图像
cv2.imwrite(img_gaussian_path, img_gaussian)
cv2.imwrite(img_sp_path, img_sp)
# 构造对比图
plt.rcParams['font.sans-serif']=['SimHei'] # 中文字体设置
plt.rcParams['axes.unicode_minus'] = False
plt.subplot(131)
plt.title("嵌有秘密信息的载体图像")
plt.imshow(mod_img,cmap='gray')
plt.subplot(132)
plt.title("高斯噪声处理后图像")
plt.imshow(img_gaussian, cmap='gray')
plt.subplot(133)
plt.title("椒盐噪声处理后的图像")
plt.imshow(img_sp,cmap='gray')
# 保存对比图
plt.savefig(img_compare_path)
# 显示对比图
plt.show()
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!