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

背景

随着手机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文件头

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



位图信息头


变量名大小作用
biSize4bytesBitmapInfoHeader结构需要的字数,固定的40
biWidth4bytes图像的宽度,用像素为单位
biHeight4bytes图像的高度,用像素为单位。还有个作用,标志图片是正向还是倒向的。如果该值是正数,说明图像是倒向的,如果该数是负数,那么图像是正向的
biPlanes2bytes为目标设备说明颜色的平面数,他的值总是设为1
biBitCount2bytes说明比特数/像数,其值为1、4、8、16、24、32,现在通常用24位
biCompression4bytes说明图像数据压缩的类型。
0 表示不压缩
1 表示8比特编码,只用于8位图
biSizeImage4bytes图像大小,单位为字节
biXpelsPerMeter4bytes说明水平分辨率,像素/米 表示
biYPelsPerMeter4bytes说明垂直分辨率,像素/米 表示
biClrUsed4bytes说明位图实际使用的彩色表中的颜色索引数
biClrImportant4bytes说明对图像显示有重要影响的颜色索引的数目如果是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



后续


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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值