前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >乱序+移位加密24位bmp格式图片 scala实现

乱序+移位加密24位bmp格式图片 scala实现

作者头像
Ldpe2G
发布2018-07-06 17:39:29
1.6K0
发布2018-07-06 17:39:29
举报

前言:

关于bmp图片的格式分析:BMP

用java读写24位bmp格式图片的一篇博客:关于Java读取和编写BMP文件的总结

正文:

乱序和移位加密都属于古典加密方法,容易被破解,本文将两种加密方式结合,

再进行多轮加密,保密性能稍微增强一点。

乱序加密:

这里只简单介绍一下列乱序加密:

 设明文 m=m1 m2 ... ms,共 s 个字符,现规定每行有 n 个字符(n<s),

设 t= [s / n] , 如果n不整除s , 则明文按通用格式输出,共形成 t+1 行的

一个明文矩阵,第 t+1 行仅有 s-nt 个字符,有 ( t+1 ) * n - s 个空格。

密匙 k 是一个 Zn = { 1 2  ... n } 上的置换θ,把 1 2 ... n 置换成

 θ(1) θ(2) ... θ(n)。现在以 θ^ 作为θ的逆变换。

加密时对明文长方阵先按第θ^(1)列读出字符(自第 1 行读至第t+1 行,t+1行如果是空格则不读)

然后以行顺序填入一个空的矩阵该矩阵和明文矩阵一样大小,

再按第θ^(2)列读出字符...,最后按第θ^(n)列读出,然后就算加密完毕。

举个简单的例子:

现在加密以下明文:

  春种一粒粟, 秋收万颗子。
  四海无闲田, 农夫犹饿死。
  锄禾日当午, 汗滴禾下土。
  谁知盘中餐, 粒粒皆辛苦。

加密时忽略标点符号,字符数s = 40,列数n = 10,则t = [ 40 / 10 ] = 4,

这里恰好是可以整除。

                       设变换 θ:   θ(1) = 5,θ(2) = 1,θ(3) = 8,θ(4) = 7,θ(5) = 2,

θ(6) = 10,θ(7) = 3,θ(8) = 9,θ(9) = 6,θ(10) = 4。

相应的逆变换也就是密钥: θ^(1) = 2,θ^(2) = 5,θ^(3) = 7,θ^(4) = 10,θ^(5) = 1,

θ^(6) = 9,θ^(7) = 4,θ^(8) = 3,θ^(9) = 8,θ^(10) = 6。

明文矩阵:

  春种一粒粟秋收万颗子
  四海无闲田农夫犹饿死
  锄禾日当午汗滴禾下土
  谁知盘中餐粒粒皆辛苦

根据逆变换首先读取θ^(1)列,就是明文第2列,按行顺序填入空矩阵:

   种海禾知

然后读取θ^(2)列,就是明文第5列,按行顺序填入空矩阵:

   种海禾知粟田午餐

然后读取θ^(3)列,就是明文第7列,按行顺序填入空矩阵:

   种海禾知粟田午餐收夫
   滴粒

按照以上步骤。

加密后:

   种海禾知粟田午餐收夫
   滴粒子死土苦春四锄谁
   颗饿下辛粒闲当中一无
   日盘万犹禾皆秋农汗粒

解密时,由于是整除的情况明文矩阵每一列的行数相等都是4,所以每次按行读取密文矩阵

4个元素,然后按照密钥即逆变换放到相应的明文矩阵的列,

比如θ^(1) = 2,所以将“种海禾知”放到明文的第2列,θ^(2) = 5

“粟田午餐”放到明文的第5列,

如此类推根据密钥就可以解出明文。

乱序加密bmp图片:

加密bmp图片只是对bmp格式图片的图像数据部分进行加密,然后按照bmp图片的格式先将信息头写入文件,

最后再写入加密的数据,这样就完成了对bmp图片内容的加密,加密后还是bmp格式图片。

加密过程简述:

      主要还是按列乱序加密,不过在加密时,当当前列的序号能被2整除,

则读取时从上往下读,若列序号不能被2整除则从下往上读取明文,解密时

也按照相应的顺序即可,然后可以加密多轮,加密轮次由由命令行参数决定,

最后将密钥和加密轮次写入加密后的bmp图片的尾部,这样解密程序只需要读入

加密图片就可以解密了,每一轮加密的结果都会输出。

乱序加密例子:

           原图                         加密一次                       加密两次

 原图      

  加密一次                                                                                                         

加密二次

我们可以看到,加密两次后由于颜色没有被加密,还是会多少透露了一些信息,

所以还要加上移位加密对颜色rgb进行移位加密。

移位加密bmp图片:

程序每次加密前随机生成一个整数n, 0 <= n <= 255,然后对于

red通道:    red = (red + n) % 256

green通道:green = (green + n + 64) % 256

blue通道:  blue = (blue + n + 128) % 256

每一轮加密都对颜色进行一次移位加密。

效果:

               原图                         加密一次                      加密两次

原图

加密一次

加密两次

乱序+移位加密程序代码:

(注:只能加密宽度能被4整除的24位bmp图片,这应该个bug):

import java.io._

object EncryptBmp24 {

  def main(args: Array[String]): Unit = {
    if(args.length < 2){
	System.out.println("usage: programe bmpImagePath encryptTimes");
    }else{
	Encrypt(args(0), Integer.parseInt(args(1)))
    }
  }
  
  def Encrypt(bmpPath: String, times: Int) = {
        //获取图片的长宽和rgb数据
	val (height, width, red, green, blue) = init(bmpPath)
	val P = getRandomP(width)  //随机生成变换
	val Q = new Array[Int](width)
	val R = height  //每一列的行数

	//生成密钥
	for(i <- 0 to width - 1)  
		Q(P(i)) = i
	 	
	val encry_red = Array.ofDim[Int](height, width)  
	val encry_green = Array.ofDim[Int](height, width)  
	val encry_blue = Array.ofDim[Int](height, width)
	
	import java.util.Random
	//随机生成移位加密密钥
	val shift = new Random(System.currentTimeMillis).nextInt(256)
	//总共加密times次
	for(t <- 0 until times){
    	    var vi = 0
    	    var vj = 0
	    for(j <- 0 until width){
		//取变换对应的一列的元素按行填入加密矩阵
		for(k <- 0 until R){
			if(vj == width){
				vi += 1
				vj = 0
			}
			if(Q(j) % 2 == 0){
				encry_red(vi)(vj) = red(k)(Q(j))
				encry_green(vi)(vj) = green(k)(Q(j))
				encry_blue(vi)(vj) = blue(k)(Q(j))
			}else{
				encry_red(vi)(vj) = red(R - 1 - k)(Q(j))
				encry_green(vi)(vj) = green(R - 1 - k)(Q(j))
				encry_blue(vi)(vj) = blue(R - 1 - k)(Q(j))
			}
			vj += 1
		}
	    }
	    for(i <- 0 until height)
		for(j <- 0 until width){
    		    red(i)(j) = encry_red(i)(j) 
    		    green(i)(j) = encry_green(i)(j) 
    		    blue(i)(j) = encry_blue(i)(j) 
    		}
	    //加密rgb
	    encryptColor(red, green, blue, shift)
	    val parentPath = new File(bmpPath).getParent
	     Bmp24Writer.writeEncryptedBmp(s"$parentPath/encrypt$t.bmp", 
	 			Q, shift, t + 1, red, green, blue)
	}	
   }
  
   def encryptColor(red: Array[Array[Int]], 
  		        green: Array[Array[Int]], 
  			blue: Array[Array[Int]], shift: Int) = {
    	
    	val height = red.length
    	val width = red(0).length
    	for(i <- 0 until height)
    	  for(j <- 0 until width){
    		  red(i)(j) = (red(i)(j) + shift) % 256
    		  green(i)(j) = (green(i)(j) + shift + 64) % 256
    		  blue(i)(j) = (blue(i)(j) + shift + 128) % 256
    	  }
    } 
    
    def getRandomP(length: Int): Array[Int] = {
    	import java.util.ArrayList
    	import java.util.Random
      
    	val temp = new Array[Int](length)
    	val list = new ArrayList[Int]
    	
    	for(i <- 0 until length)
    		list add i
    		
    	val random = new Random(System.currentTimeMillis)
    	
    	for(t <- length until 0 by -1)
    		temp(length - t) = list remove random.nextInt(t)
    	temp
    }

    def init(bmpPath: String) = {  
       val fin = new FileInputStream(bmpPath)  
       val bis = new BufferedInputStream(fin)  
       // 获得文件头和信息头的数据
       //分别是14字节和40字节
       val array1 = new Array[Byte](14)  
       bis.read(array1, 0, 14) 
       val array2 = new Array[Byte](40)
       bis.read(array2, 0, 40) 
  
       // 解析信息头的数据得到位图数据的宽和高
       val width = Bmp24Writer.ChangeInt(array2, 7)
       val height = Bmp24Writer.ChangeInt(array2, 11) 
         
       println(s"width: $width, height: $height")
       
       //获取位图的数据,返回rgb二维整型数组
       val (red, green, blue) = Bmp24Writer.getInf(bis, height, width) 
       
       fin.close 
       bis.close
       (height, width, red, green, blue)
    }  
}

解密代码:

import java.io._

object DecryptBmp24 {

  def main(args: Array[String]): Unit = {
	if(args.length < 1){
		System.out.println("usage: programe bmpImagePath");
	}else{
		Decrypt(args(0))
	}
  }
  
  def Decrypt(bmpPath: String) = {
      	//从已经加密的图片中读出宽高,
	//加密的数据,密钥,加密轮次和移位密钥
    val (height, width, red, green, blue, keys, times, shift) = init(bmpPath)
    	val R = height
    	 	
    	val decry_red = Array.ofDim[Int](height, width)  
    	val decry_green = Array.ofDim[Int](height, width)  
    	val decry_blue = Array.ofDim[Int](height, width)
    	
    	for(t <- 0 until times){
        	var vi = 0
        	var vj = 0
        	//每一轮都对rgb进行一次移位解密
        	decryptColor(red, green, blue, shift)
    		for(j <- 0 until width){
    			for(k <- 0 until R){
            		if(vj == width){
            			vi += 1
            			vj = 0
            		}
            		if(keys(j) % 2 == 0){
            			decry_red(k)(keys(j)) = red(vi)(vj)
            			decry_green(k)(keys(j)) = green(vi)(vj)
            			decry_blue(k)(keys(j)) = blue(vi)(vj)
            		}else{
            			decry_red(R - 1 - k)(keys(j)) = red(vi)(vj)
            			decry_green(R - 1 - k)(keys(j)) = green(vi)(vj)
            			decry_blue(R - 1 - k)(keys(j)) = blue(vi)(vj)
            		}
            		vj += 1
        		}
        	}
    		for(i <- 0 until height)
    			for(j <- 0 until width){
        			red(i)(j) = decry_red(i)(j) 
        			green(i)(j) = decry_green(i)(j) 
        			blue(i)(j) = decry_blue(i)(j) 
        		}	
    	}	
    	val parentPath = new File(bmpPath).getParent
    	Bmp24Writer.writeNormalBmp(s"$parentPath/decrypt.bmp", 
    				red, green, blue)
    }
    //移位解密就是加密的逆变换
    def decryptColor(red: Array[Array[Int]], 
  		    green: Array[Array[Int]], 
  		    blue: Array[Array[Int]], shift: Int) = {
    	
    	val height = red.length
    	val width = red(0).length
    	for(i <- 0 until height)
    	  for(j <- 0 until width){
    		  red(i)(j) = (red(i)(j) - shift + 256) % 256
    		  green(i)(j) = (green(i)(j) - shift - 64 + 256) % 256
    		  blue(i)(j) = (blue(i)(j) - shift - 128 + 256) % 256
    	  }
      } 

    def init(bmpPath: String) = {  
       val fin = new FileInputStream(bmpPath)  
		val bis = new BufferedInputStream(fin)  
		val array1 = new Array[Byte](14)  
       bis read(array1, 0, 14) 
       val array2 = new Array[Byte](40)
       bis read(array2, 0, 40) 
  
       val width = Bmp24Writer.ChangeInt(array2, 7)
       val height = Bmp24Writer.ChangeInt(array2, 11) 
         
       println(s"width: $width, height: $height")
       //首先读出加密的数据
       val (red, green, blue) = Bmp24Writer.getInf(bis, height, width) 
       
       val keys = new Array[Int](width)
       //然后读取列乱序密钥
       val temp = new Array[Byte](4)
       for(i <- 0 until width){
            bis read(temp, 0, 4)
            keys(i) = Bmp24Writer.ChangeInt(temp, 3)
        }
       //然后读取加密轮次
       bis read(temp, 0, 4)
       val times = Bmp24Writer.ChangeInt(temp, 3)
       //读取移位密钥
       bis read(temp, 0, 4)
       val shift = Bmp24Writer.ChangeInt(temp, 3)
      
       for(i <- 0 to width - 1)
         print(s"${keys(i)} ")
       println(s"\nkey length: ${keys.length}")
       println(s"encrypted times: $times, color shift: $shift")
       
       fin.close 
       bis.close
       (height, width, red, green, blue, keys, times, shift)
    }  
}

Bmp24Writer: 

由于超出了文章限制的字符数,所以将这部分代码放到了 Bmp24Writer那篇文章中

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 正文:
    • 乱序加密:
      • 举个简单的例子:
    • 乱序加密bmp图片:
      • 加密过程简述:
      • 乱序加密例子:
    • 移位加密bmp图片:
      • 乱序+移位加密程序代码:
        • 解密代码:
        相关产品与服务
        图数据库 KonisGraph
        图数据库 KonisGraph(TencentDB for KonisGraph)是一种云端图数据库服务,基于腾讯在海量图数据上的实践经验,提供一站式海量图数据存储、管理、实时查询、计算、可视化分析能力;KonisGraph 支持属性图模型和 TinkerPop Gremlin 查询语言,能够帮助用户快速完成对图数据的建模、查询和可视化分析。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档