初探无水印信息图片加密技术-阿里云开发者社区

开发者社区> 安全> 正文

初探无水印信息图片加密技术

简介: #背景 ####随着手机APP越来越多,对于APP信息安全面临的挑战越来越大,像接口传递的验证信息这些相对保密的信息如果直接放在app中明文,那么毫无疑问,很容易就被破解出来,想干嘛就干嘛。因此为了对部分本地信息加密,想出过无数的办法,本次讨论的重点,无水印信息图片加密。** ---------------------------------------------------- ##原

背景

随着手机APP越来越多,对于APP信息安全面临的挑战越来越大,像接口传递的验证信息这些相对保密的信息如果直接放在app中明文,那么毫无疑问,很容易就被破解出来,想干嘛就干嘛。因此为了对部分本地信息加密,想出过无数的办法,本次讨论的重点,无水印信息图片加密。**


原理

无水印信息图片加密,基本原理,就是将信息负载再图片上,然后程序通过特定的算法将信息再度拿出来,而图片一看下去也是正常显示的,肉眼看不出任何的猫腻。那么到底怎么附加法?


1. 追加信息法:

利用不同格式图片的特性,例如 BMP文件头标记了图片文件大小,后面信息不读取,或JPG文件拥有FFD9 标志结束符,因此就算将再多信息附加上去,也不会影响原来图片查看。

2.颜色特征法:

根据 颜色的特点,因为颜色的最后一个位含有的信息量就算改变也不会改变大局,所以颜色的最后一个bit作为信息记录点。

3.颜色特征法Ex:

颜色特征,按一定的算法,获取约定的图片特征,例如,都获取RGB中G的整张图的波形,通过某种滤波器,分析出来某段,然后加上校验码进行校验信息是否有效,而且多段,含冗余,分布图片各个地方,几时压缩,或者截图后,信息也有可能被获取到。


各自优缺点

追加信息法:

优点:

加密后图片正常显示,无信息长度限制,可以无限追加信息。我们都不明白为啥某个 “正常” 图片竟然有1,2G那么大,到底后面附加了什么???嘿嘿

缺点:无限追加,也是致命缺点,你不会傻到真的认为 阿强那张1,2G的图片真的只是单纯的图片那么简单吧?


颜色特征法:    

优点:

加密后图片正常显示,信息保密度更强,不会增加图片本身的大小,当然转格式例外,而且根据算法,整体的保密性更强。

缺点:

能加密得信息的长度受图片size限制,如果对图片进行过压缩,信息将会损失得一塌糊涂。**

颜色特征法EX:

优点:

经过压缩后,信息仍有机会提取出来,耐操,加密后不会改变图片大小,有冗余信息,破解难度大。

缺点:

图片容易显示不正常,当然搞成类似白噪点也是个技术活,能加密得信息的长度受图片size限制。




颜色特征法原理剖析


这里重点解释下颜色特征法是怎么实现得。


颜色原理

说之前,必须要说下颜色的组成。大家都知道平时开发中我们使用的颜色值例如白色  #FFFFFFFF  黑色 #00000000 这些数字代表什么呢?


**

他们以2位16进制数字位一个单位分别代表  A,R,G,B。记得在保存的时候别忘记了A,透明度,否则出来的都是黑色一片哦。**

这里讨论 R,G,B,他们代表红,绿,蓝,三原色,**

而2位16进制的数字联合代表256个色值,换算2进制就是 8位。因为主要决定颜色的信息其实都储藏在这里,而前面的值表示颜色的变化越大,而最后以为相对改变的话,对颜色本身的影响是非常小的,255和254是相差很小的颜色变化。**因此只要我们改变三原色随便一个或者几个的最后一位,其实对颜色变化影响微乎其微。肉眼压根不能看出变化。

                int rgb = image.getPixel(curX, curY);

                r = (rgb & 0x00ff0000) >> 16;
                g = (rgb & 0x0000ff00) >> 8;
                b = (rgb & 0x000000ff);
                al = (rgb & 0xff000000) >> 24;

                if (bitLength >= 0) {
                    switch (iRGB) {
                        case 0:
                            r = (r & 0x000000FE);
                            r |= value;
                            break;
                        case 1:
                            g = (g & 0x000000FE);
                            g |= value;
                            break;
                        case 2:
                            b = (b & 0x000000FE);
                            b |= value;
                            break;
                    }
                }
                rgb = al << 24 | (r << 16) | (g << 8) | b;

图片格式原理


如果你以为只是改个颜色值,就大功告成,呵呵,那你马上哭着发现,压根你加密的信息从来就没正确拿出来过。因为图片是含有头部信息的,而且不同格式的图片头信息肯定也不一致的,相对固定的头部是BMP图片的,因此俺们这次也是采用输出BMP图片作为加密后的结果图片。首先我们看看BMP文件头组成:


bmp文件头

变量名 大小 作用
bfType 2bytes 默认直接写死 424d 说明文件类型的
bfSize 4bytes 图片总大小,包括头信息
bfReserved1 2bytes 保留,必须设置为0
bfReserved2 2bytes 保留,必须设置为0
bfOffBits 4bytes 说明文件头开始到实际图片数据之间的偏移量,其实也是相对恒定的



位图信息头


变量名 大小 作用
biSize 4bytes BitmapInfoHeader结构需要的字数,固定的40
biWidth 4bytes 图像的宽度,用像素为单位
biHeight 4bytes 图像的高度,用像素为单位。还有个作用,标志图片是正向还是倒向的。如果该值是正数,说明图像是倒向的,如果该数是负数,那么图像是正向的
biPlanes 2bytes 为目标设备说明颜色的平面数,他的值总是设为1
biBitCount 2bytes 说明比特数/像数,其值为1、4、8、16、24、32,现在通常用24位
biCompression 4bytes 说明图像数据压缩的类型。
0 表示不压缩
1 表示8比特编码,只用于8位图
biSizeImage 4bytes 图像大小,单位为字节
biXpelsPerMeter 4bytes 说明水平分辨率,像素/米 表示
biYPelsPerMeter 4bytes 说明垂直分辨率,像素/米 表示
biClrUsed 4bytes 说明位图实际使用的彩色表中的颜色索引数
biClrImportant 4bytes 说明对图像显示有重要影响的颜色索引的数目如果是0,表示都很重要



so,在修改完图像信息后,需要将这些信息补上头信息,再将颜色信息附上,关键代码如下

补充头信息:

            FileOutputStream fileos = new FileOutputStream(filename);
            // bmp文件头
            int bfType = 0x4d42;
            long bfSize = 14 + 40 + bufferSize;
            int bfReserved1 = 0;
            int bfReserved2 = 0;
            long bfOffBits = 14 + 40;
            // 保存bmp文件头
            writeWord(fileos, bfType);
            writeDword(fileos, bfSize);
            writeWord(fileos, bfReserved1);
            writeWord(fileos, bfReserved2);
            writeDword(fileos, bfOffBits);
            // bmp信息头
            long biSize = 40L;
            long biWidth = nBmpWidth;
            long biHeight = nBmpHeight;
            int biPlanes = 1;
            int biBitCount = 24;
            long biCompression = 0L;
            long biSizeImage = 0L;
            long biXpelsPerMeter = 0L;
            long biYPelsPerMeter = 0L;
            long biClrUsed = 0L;
            long biClrImportant = 0L;
            // 保存bmp信息头
            writeDword(fileos, biSize);
            writeLong(fileos, biWidth);
            writeLong(fileos, biHeight);
            writeWord(fileos, biPlanes);
            writeWord(fileos, biBitCount);
            writeDword(fileos, biCompression);
            writeDword(fileos, biSizeImage);
            writeLong(fileos, biXpelsPerMeter);
            writeLong(fileos, biYPelsPerMeter);
            writeDword(fileos, biClrUsed);
            writeDword(fileos, biClrImportant);



最后把图像信息也附上去。

for (int nCol = 0, nRealCol = nBmpHeight - 1; nCol < nBmpHeight; ++nCol, --nRealCol)
    for (int wRow = 0, wByteIdex = 0; wRow < nBmpWidth; wRow++, wByteIdex += 3) {
         int clr = bitmap.getPixel(wRow, nCol);
         bmpData[nRealCol * wWidth + wByteIdex] = (byte) Color.blue(clr);
         bmpData[nRealCol * wWidth + wByteIdex + 1] = (byte) Color.green(clr);
         bmpData[nRealCol * wWidth + wByteIdex + 2] = (byte) Color.red(clr);
         }


效果



gif5新文件.gif



后续


这只是相对最简单的图像加密,图像并压缩后容易出现损失,因此,后面要加上特征值作为验证,还有应该有一定冗余,还需要部分对其做成类似噪点的研究。



版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
+ 订阅

云安全开发者的大本营

其他文章