趁放假把下学期的创新项目实践预判完成一点,下学期多腾出时间备考。
LSB算法 简介 LSB算法:全称Least Significant Bit(最低有效位),指将秘密信息嵌入到载体图像像素值的最低有效位 ,也称最不显著位,改变这一位置对载体图像的品质影响最小。
LSB属于空域算法中的一种,是将信息嵌入到图像点中像素位的最低位,以保证嵌入的信息是不可见的,但是由于使用了图像不重要的像素位,算法的鲁棒性差,水印信息很容易为滤波、图像量化、几何变形的操作破坏。
本篇主要讲简单实现在图片中注入隐含信息。
算法分析 以.png图片为例,每一个像素点显示的颜色由r、g、b三个元素分量的数值决定(取值范围为0~255),将其化为二进制的形式,如Color(255,102,102),不足8位的首部补0,可得到如下排列:
1 2 3 1111111 1 1110011 0 1110011 0
末尾排列为100,将其置0,我们可以将二进制编码写在其中,对应需要隐藏的信息。由于最低有效位的原理,在复杂的图片中人眼基本感受不到颜色的变化,这样就实现了加密;解密只需将其取出组合,并翻译成对应的文本即可。
算法步骤 1 将原始载体图像的空域像素值由十进制转换成二进制;
2 用二进制秘密信息中的每一比特信息替换与之相对应的载体数据的最低有效位 ;
3 将得到的含秘密信息的二进制数据转换为十进制像素值,从而获得含秘密信息的图像。
简单的java代码实现 加密 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 public class encryption { public static BufferedImage encryptionLSB (BufferedImage secretImg, String data) { List<StringBuffer> rgbList= new ArrayList <StringBuffer>(); StringToBin stringToBin=new StringToBin (); String dataBin= stringToBin.StrToBinstr(data); char [] databinArray=dataBin.toCharArray(); int width = secretImg.getWidth(), height = secretImg.getHeight(); String r8bit=null ; String g8bit=null ; String b8bit=null ; int a,r = 0 ,g=0 ,b=0 ; for (int w = 0 ; w < width; w++) { for (int h = 0 ; h < height; h++) { int val=secretImg.getRGB(w,h); a = (0xff000000 & val) >>> 24 ; r = (0x00ff0000 & val) >> 16 ; g = (0x0000ff00 & val) >> 8 ; b = (0x000000ff & val); double power = Math.pow(2.0 , 4.0 ); r8bit = Integer.toBinaryString((int )(r)); g8bit = Integer.toBinaryString((int )(g)); b8bit = Integer.toBinaryString((int )(b)); int rDifference = 8 - r8bit.length(); int gDifference = 8 - g8bit.length(); int bDifference = 8 - b8bit.length(); for (int i = rDifference; i > 0 ; i--){ r8bit="0" +r8bit;} for (int i = gDifference; i > 0 ; i--){ g8bit = "0" +g8bit;} for (int i = bDifference; i > 0 ; i--){ b8bit = "0" +b8bit;} StringBuffer rbuff=new StringBuffer (r8bit); StringBuffer gbuff=new StringBuffer (g8bit); StringBuffer bbuff=new StringBuffer (b8bit); rbuff.setCharAt(7 ,'0' ); gbuff.setCharAt(7 ,'0' ); bbuff.setCharAt(7 ,'0' ); rgbList.add(rbuff); rgbList.add(gbuff); rgbList.add(bbuff); } } int [] rgbArray=new int [rgbList.size()]; for (int i=0 ;i<rgbList.size();i++){ if (i<databinArray.length-1 ) { rgbList.get(i).setCharAt(7 , databinArray[i]); } rgbArray[i] = Integer.parseInt(rgbList.get(i).toString(), 2 ); } int i=0 ; for (int w = 0 ; w < width; w++) { for (int h = 0 ; h < height; h++) { secretImg.setRGB(w, h,new Color (rgbArray[i],rgbArray[i+1 ],rgbArray[i+2 ]).getRGB()); i=i+3 ; } } return secretImg; } public static void main (String[] args) throws IOException { BufferedImage secretImg = ImageIO.read(new File ("src/main/img/kitokawa.png" )); String data="这是一道密文!" ; secretImg=encryptionLSB(secretImg,data); ImageIO.write(secretImg, "png" , new File ("secret.png" )); } }
解密 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public class decrypt { public static String decryptLSB (BufferedImage secretImg,int limit) { int width = secretImg.getWidth(), height = secretImg.getHeight(); String dataBin = "" ; String data = "" ; String r8bit = null ; String g8bit = null ; String b8bit = null ; int a,x=0 , r = 0 , g = 0 , b = 0 ; for (int w = 0 ; w < width; w++) { for (int h = 0 ; h < height; h++) { int val = secretImg.getRGB(w, h); a = (0xff000000 & val) >>> 24 ; r = (0x00ff0000 & val) >> 16 ; g = (0x0000ff00 & val) >> 8 ; b = (0x000000ff & val); double power = Math.pow(2.0 , 4.0 ); r8bit = Integer.toBinaryString((int ) (r)); g8bit = Integer.toBinaryString((int ) (g)); b8bit = Integer.toBinaryString((int ) (b)); int rDifference = 8 - r8bit.length(); int gDifference = 8 - g8bit.length(); int bDifference = 8 - b8bit.length(); for (int i = rDifference; i > 0 ; i--) { r8bit = "0" + r8bit; } for (int i = gDifference; i > 0 ; i--) { g8bit = "0" + g8bit; } for (int i = bDifference; i > 0 ; i--) { b8bit = "0" + b8bit; } StringBuffer rbuff = new StringBuffer (r8bit); StringBuffer gbuff = new StringBuffer (g8bit); StringBuffer bbuff = new StringBuffer (b8bit); dataBin+=rbuff.charAt(7 ); dataBin+=gbuff.charAt(7 ); dataBin+=bbuff.charAt(7 ); if (x>limit)break ; x++; } if (x>limit)break ; } String X=Integer.toBinaryString('%' ); String Y=Integer.toBinaryString('#' ); String[] datas=dataBin.split(X+Y); for (int i=0 ;i<datas.length-1 ;i++){ data+= BinToString.toString(datas[i]); } return data; } public static void main (String[] args) throws IOException { int limit=10000 ; BufferedImage secretImg = ImageIO.read(new File ("secret.png" )); System.out.println(decryptLSB(secretImg,limit)); File f=new File ("a.txt" ); FileOutputStream fos1=new FileOutputStream (f); OutputStreamWriter dos1=new OutputStreamWriter (fos1); dos1.write(decryptLSB(secretImg,limit)); dos1.close(); } }
使用到的其他方法类 加工整合二进制编码字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class StringToBin { public String StrToBinstr (String str) { String x=Integer.toBinaryString('%' ); String y=Integer.toBinaryString('#' ); char [] strChar = str.toCharArray(); String result = "" ; for (int i = 0 ; i < strChar.length; i++) { result += Integer.toBinaryString(strChar[i]) + x+y; } return result; } }
二进制编码翻译成String 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class BinToString { public static String toString (String binary) { String x=Integer.toBinaryString('%' ); String y=Integer.toBinaryString('#' ); String[] tempStr=binary.split(x+y); char [] tempChar=new char [tempStr.length]; for (int i=0 ;i<tempStr.length;i++) { tempChar[i]=BinstrToChar(tempStr[i]); } return String.valueOf(tempChar); } public static int [] BinstrToIntArray(String binStr) { char [] temp=binStr.toCharArray(); int [] result=new int [temp.length]; for (int i=0 ;i<temp.length;i++) { result[i]=temp[i]-48 ; } return result; } public static char BinstrToChar (String binStr) { int [] temp=BinstrToIntArray(binStr); int sum=0 ; for (int i=0 ; i<temp.length;i++){ sum +=temp[temp.length-1 -i]<<i; } return (char )sum; } }
运行测试 加密生成secret.png:
解密生成文本:
附录 参考链接:
原理详解 百度百科 基于图像的 LSB 隐写术科普