Реализация стеганографии LSB на основе Matlab и Python

Python

Встраивание строки в изображение может выбирать пиксели последовательно или случайным образом. Ниже мы реализуем каждый алгоритм по очереди.

1. Последовательное встраивание

Последовательное встраивание очень простое: нужно пройтись по каждому пикселю, а затем вставить двоичный файл в последний бит, который является восьмым битом.

Для того, чтобы написать отчет, я также нарисовал блок-схему, которая размещена здесь для удобства понимания:

1.1 версия питона

Прежде всего, я реализовал один на python, в основном потому, что я не знаком с Matlab, и для написания очень просто использовать библиотеку PIL для python3. Просто посмотрите на код

# coding:utf-8
# python 3.6.6

from PIL import Image
import time

# 将字符串转为二进制
def str_convert_bin(s):
    result = ''
    for c in s:
        b = bin(ord(c)).replace('0b', '')
        b = '0'*(7-len(b))+b
        result = result+b
    return result

# 将二进制转化为字符串
def bin_convert_str(b):
    str=''
    # 将二进制字符串每7位分割,成列表
    b1 = [b[i:i+7] for i in range(0, len(b), 7)]
    for i in range(len(b1)):
        b2 = chr(int(b1[i],2))
        str = str+b2
    return str

# 将二进制字符串嵌入图片像素B通道 im:Image()、bin1:要嵌入的二进制串
def insert(im,bin1):
    size = im.size
    length = len(bin1)
    k=0
    flag=0
    for i in range(size[0]):
        for j in range(size[1]):
            # im.getpixel((i,j))读取像素点(i,j)的像素值
            pixel_b=bin(im.getpixel((i,j))[2]).replace('0b', '')
            if pixel_b[-1:]<bin1[k]:
                # im.putpixel((i,j),(x,y,z))设置像素点(i,j)的RGB值为(x,y,z)
                im.putpixel((i,j),(im.getpixel((i,j))[0],im.getpixel((i,j))[1],im.getpixel((i,j))[2]+1))
            if pixel_b[-1:]>bin1[k]:
                im.putpixel((i,j),(im.getpixel((i,j))[0],im.getpixel((i,j))[1],im.getpixel((i,j))[2]-1))    
            k=k+1 
            if k==length:
                flag=1
                break
        if flag==1:
            break
    print("字符串嵌入完成\n\n")

# 提取字符串 im:Image()、length:二进制字符串长度
def extract(im,length):
    size = im.size
    k=0
    result=''
    flag=0
    for i in range(size[0]):
        for j in range(size[1]):
            pixel_b=bin(im.getpixel((i,j))[2]).replace('0b', '')
            result=result+pixel_b[-1:]
            k=k+1 
            if k==length:
                flag=1
                break
        if flag==1:
            break
    print("提取完成,二进制字符串为:\n%s"%result)
    str = bin_convert_str(result)
    print("转换完成,结果为:\n%s"%str)

def main():
    test_str=input("请输入字符串:\n")
    result = str_convert_bin(test_str)
    print("待嵌入字符串转化为二进制为:\n%s"%result)
    print("开始嵌入....")
    im = Image.open("2.bmp")
    insert(im, result)

    time.sleep(5)
    print("开始提取字符串:")
    extract(im, len(result))

if __name__=='__main__':
    main()

результат:

1.2 матлаб версия

Для последующей более сложной стеганографии все равно нужно использовать матлаб, поэтому лучше перейти на матлаб.

Матлаб вводить не буду, я тоже сначала учусь пользоваться, код написан грубо, неохотно вставляю код:

% By gengyanqing
% LSB隐藏(顺序隐藏)
% 可以隐藏数字、字母、英文字符 ex: hello,world.111
% jpg失真!用png/bmp

clear all;clc;
data=imread('1.png');  % 读入图片
str=input('请输入要潜入的字符串:','s'); % 接收字符串
str_bin_mat=dec2bin(str); % 字符串转二进制矩阵

% 二进制矩阵转字符串
l_str_bin_mat=size(str_bin_mat); %二进制矩阵
str_bin='';
for i=1:l_str_bin_mat(1)
    for j=1:l_str_bin_mat(2)
        str_bin=[str_bin,str_bin_mat(i,j)];
    end
end
disp('待嵌入的字符串二进制形式为');
disp(str_bin);

% 检测是否能够完全嵌入
[l,w,h]=size(data);
if length(str_bin)>=l*w*h
    error('字符长度超出!!!');
end

%嵌入程序
data1=data;
disp('开始嵌入');
flag1=1; %输入字符二进制长度,判断嵌入是否结束
flag2=1;
flag3=1;
for i=1:l
    if flag3==0
        break
    end
    for j=1:w
        if flag2==0
            flag3=0;
            break
        end
        for k=1:h
            if flag1>length(str_bin)
                disp('over');
                flag2=0;
                break
            end
            a=dec2bin(data1(i,j,k),8);%数字取二进制
            data1(i,j,k)=bin2dec([a(1:7),str_bin(flag1)]);%二进制相加,再取十进制  
            flag1=flag1+1;
        end
    end
end
%保存图片
imwrite(data1,'1-2.png')
disp('嵌入完成,保存为1-2.png');

%以下为提取程序
disp('开始提取...')
data2 = imread('1-2.png');
[l,w,h]=size(data2);
str_bin1='';%提取到的二进制字符串
locationx=[];
locationy=[];
locationxy=[];
m=length(str_bin);
flag1=1;
flag2=1;
flag3=1;
for i=1:l
    if flag3==0
        break
    end
    for j=1:w
        if flag2==0
            flag3=0;
            break
        end
        for k=1:h
            if flag1>length(str_bin)
                flag2=0;
                break
            end
            a=dec2bin(data2(i,j,k),8);%十进制转二进制
            str_bin1=[str_bin1,a(8)];% 取最后一个数
            flag1=flag1+1;
        end
    end
end
disp('提取完成!');
disp('提取到的二进制字符串为:');
disp(str_bin1);
disp('开始转换...')

% 二进制转字符串
str2='';
for q=1:length(str_bin1)/l_str_bin_mat(2)
    w=str_bin1((q-1)*l_str_bin_mat(2)+1:q*l_str_bin_mat(2));%w为每七位
    a=bin2dec(w); % 转换为十进制
    if a>9
        str2=[str2,char(a)];
    end
    if a<9
        str2=[str2,a];
    end
end
disp('转换完成');
disp('最终结果为:');
disp(str2);

Вы можете вставлять символы, цифры и буквы, и результаты будут следующими:

2. Случайная стеганография LSB

На самом деле это похоже на порядок. Это не что иное, как изменение (i, j) на случайные точки при обходе пикселей. Мы можем написать случайную функцию для случайной генерации списков X и Y. Когда мы хотим встроить (i , j), мы просто меняем его на (X(i+j), Y(i+j)), почему бы и нет (X(i), Y(j)) Читатель может подумать об этом (это не случайно) .

Я также нарисовал блок-схему для этого, но, похоже, есть проблема, поэтому оставим ее, так как время срочно.

Далее посмотрим на функцию randomxy.m, которая генерирует случайный список:

% 随机生成两个列表
% l为长,w为宽,len_str_bin为嵌入二进制长度,key为随机种子
function [x,y]=randxy(l,w,len_str_bin,key)
    %设置随机种子,生成一串随机数
    rand('seed',key);
    disp('hhhhhhhhh');
    x=randperm(l,len_str_bin);
    y=randperm(w,len_str_bin);
    %x = unique(x); %去重处理
    %y = unique(y) ;%去重处理
end

Затем посмотрите на основной код:

% By gengyanqing
% LSB隐藏(随机隐藏)
% 可以隐藏数字、字母、英文字符 ex: hello,world.111
% jpg失真!用png/bmp

clear all;clc;
data=imread('1.png');  % 读入图片
str=input('请输入要潜入的字符串:','s'); % 接收字符串
str_bin_mat=dec2bin(str); % 字符串转二进制矩阵

% 二进制矩阵转字符串
l_str_bin_mat=size(str_bin_mat); %二进制矩阵
str_bin='';
for i=1:l_str_bin_mat(1)
    for j=1:l_str_bin_mat(2)
        str_bin=[str_bin,str_bin_mat(i,j)];
    end
end
disp('待嵌入的字符串二进制形式为');
disp(str_bin);

% 检测是否能够完全嵌入
[l,w,h]=size(data);
if length(str_bin)>=l*w*h
    error('字符长度超出!!!');
end

%嵌入程序
data1=data;
disp('开始嵌入');
flag1=1; %输入字符二进制长度,判断嵌入是否结束
flag2=1;
flag3=1;
% 调用randxy函数
[x,y]=randxy(l,w,length(str_bin),88);
for i=1:l
    if flag3==0
        break
    end
    for j=1:w
        if flag2==0
            flag3=0;
            break
        end
        for k=1:h
            if flag1>length(str_bin)
                disp('over');
                flag2=0;
                break
            end
            a=dec2bin(data1(x(i+j),y(i+j),k),8);%数字取二进制
            data1(x(i+j),y(i+j),k)=bin2dec([a(1:7),str_bin(flag1)]);%二进制相加,再取十进制  
            flag1=flag1+1;
        end
    end
end
%保存图片
imwrite(data1,'1-2.png')
disp('嵌入完成,保存为1-2.png');

%以下为提取程序
%这里提供了x和y,提取二进制字符串位数的信息
disp('开始提取...')
data2 = imread('1-2.png');
[l,w,h]=size(data2);
str_bin1='';%提取到的二进制字符串
locationx=[];
locationy=[];
locationxy=[];
m=length(str_bin);
flag1=1;
flag2=1;
flag3=1;
for i=1:l
    if flag3==0
        break
    end
    for j=1:w
        if flag2==0
            flag3=0;
            break
        end
        for k=1:h
            if flag1>length(str_bin)
                flag2=0;
                break
            end
            a=dec2bin(data2(x(i+j),y(i+j),k),8);%十进制转二进制
            locationx=[locationx,x(i+j)];%随机点x坐标
            locationy=[locationy,y(i+j)];%随机点y坐标
            locationxy=[locationxy;x(i+j),y(i+j),k];
            str_bin1=[str_bin1,a(8)];% 取最后一个数
            flag1=flag1+1;
        end
    end
end
disp('提取完成!');
disp('提取到的二进制字符串为:');
disp(str_bin1);
disp('开始转换...')

% 二进制转字符串
str2='';
for q=1:length(str_bin1)/l_str_bin_mat(2)
    w=str_bin1((q-1)*l_str_bin_mat(2)+1:q*l_str_bin_mat(2));%w为每七位
    a=bin2dec(w); % 转换为十进制
    if a>9
        str2=[str2,char(a)];
    end
    if a<9
        str2=[str2,a];
    end
end
disp('转换完成');
disp('最终结果为:');
disp(str2);

disp('随机位置分别为');
disp(locationxy);
plot(locationx,locationy);

результат:

На картинке ниже изображена скрытая точка (видно, что она действительно случайная)