zoukankan      html  css  js  c++  java
  • JAVA 加密算法初探DES&AES

    开发项目中需要将重要数据缓存在本地以便在离线是读取,如果不对数据进行处理,很容易造成损失。所以,我们一般对此类数据进行加密处理。这里,主要介绍两种简单的加密算法:DES&AES。

    先简单介绍一下一般的加密方案(如下图所示):

    1)明文:原始信息。
    2)加密算法:以密钥为参数,对明文进行多种置换和转换的规则和步骤,变换结果为密文。
    3)密钥:加密与解密算法的参数,直接影响对明文进行变换的结果。
    4)密文:对明文进行变换的结果。
    5)解密算法:加密算法的逆变换,以密文为输入、密钥为参数,变换结果为明文。

    密码学中常用的数学运算有一下几种:

    ◆移位和循环移位
      移位就是将一段数码按照规定的位数整体性地左移或右移。循环右移就是当右移时,把数码的最后的位移到数码的最前头,循环左移正相反。例如,对十进制数码12345678循环右移1位(十进制位)的结果为81234567,而循环左移1位的结果则为23456781。
    ◆置换
      就是将数码中的某一位的值根据置换表的规定,用另一位代替。它不像移位操作那样整齐有序,看上去杂乱无章。这正是加密所需,被经常应用。
    ◆扩展
      就是将一段数码扩展成比原来位数更长的数码。扩展方法有多种,例如,可以用置换的方法,以扩展置换表来规定扩展后的数码每一位的替代值。
    ◆压缩
      就是将一段数码压缩成比原来位数更短的数码。压缩方法有多种,例如,也可以用置换的方法,以表来规定压缩后的数码每一位的替代值。
    ◆异或
      这是一种二进制布尔代数运算。异或的数学符号为⊕ ,它的运算法则如下:
    1⊕1 = 0 
    0⊕0 = 0 
    1⊕0 = 1 
    0⊕1 = 1 
      也可以简单地理解为,参与异或运算的两数位如相等,则结果为0,不等则为1。
    ◆迭代
      迭代就是多次重复相同的运算,这在密码算法中经常使用,以使得形成的密文更加难以破解。

    一、下面就介绍下DES算法:

    1、先看下代码实验结果(明文不变,密钥前八位不变):

    通过对比发现在对同一明文加密时,只要密钥前八位相同,所产生的密文就相同。由此可以看出,DES采用的密钥长度为64位,进一步了解可以发现,这64位的密钥中只有56位可以用到,其余8位作为奇偶校验(这8位分别是每个字符转化成二进制后的最后一位)。所以,这也是DES如今不常用的原因,现在的电脑通过穷举,24小时之内就可以得到正确的密钥。但作为研究的材料还是可以的。

    下面,我们再看一下密钥和明文怎么产生密文的。

    在得到原始密钥(即我们输入的密钥)之后,还需要进行一系列的变换,才能产生真正和明文作用的密钥。其中的变换算法这里不作深究。简单的讲下用到的数学运算有:位移、16次迭代。最终形成16套加密密钥:key[0],key[1],key[2],…。key[14],key[15]。这16套密钥是真正参与到密文的生产。

    当然,在得到明文之后也需要进行操作,然后和密钥一起生成密文。其中,明文也会进行16次迭代,在每次迭代过程中,与16套中的密钥以此进行异或运算。之后再进一步对迭代之后的数据进行处理,最终得到密文。

    加密完成了,自然会涉及到解密。我们可能会认为解密是加密的逆运算。其实不全是。DES采用的解密算法,和加密算法是一样的,不同的是密钥的使用顺序。在加密中是按照第i次迭代就采用第i次迭代生成的密钥进行异或,而解密时第i次迭代就采用第17-i次迭代生成的密钥和数据进行异或。

    完整代码如下:

    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.security.spec.InvalidKeySpecException;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.DESKeySpec;
    public class des {
                          
        private final static String DES = "DES";                     
                       
        public static void main(String[] args){
        	String str_pass = "12345678fedcba";
        	String content = "不剃头的一休哥";
          //  String encryptString = encrypt("不剃头的一休哥",str_pass);
            byte[] key = str_pass.getBytes();
            byte[] src = content.getBytes();
            SecureRandom sr = new SecureRandom();
            byte[] result = null;
            // 从原始密匙数据创建DESKeySpec对象
            DESKeySpec dks;
    		try {
    			dks = new DESKeySpec(key);
    			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
    		    SecretKey securekey = keyFactory.generateSecret(dks);
    		    // Cipher对象实际完成加密操作
    		    Cipher cipher = Cipher.getInstance(DES);
    		    // 用密匙初始化Cipher对象
    		    cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
    		    // 正式执行加密操作
    		    result = cipher.doFinal(src);
    		} catch (InvalidKeyException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
            // 创建一个密匙工厂,然后用它把DESKeySpec转换成一个SecretKey对象
    		catch (NoSuchAlgorithmException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (InvalidKeySpecException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (NoSuchPaddingException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IllegalBlockSizeException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (BadPaddingException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
           
            String hs = "";
            String stmp = "";
            for (int n = 0; n < result.length; n++) {
                stmp = (java.lang.Integer.toHexString(result[n] & 0XFF));
                if (stmp.length() == 1)
                    hs = hs + "0" + stmp;
                else
                    hs = hs + stmp;
            }
            String encryptString = hs.toUpperCase();
            System.out.println("密钥:"+str_pass);
            System.out.println("密文:"+encryptString);
        }
                          
       
                          
    }
    

    二、AES算法

    AES 算法是基于置换和代替的。置换是数据的重新排列,而代替是用一个单元数据替换另一个。具体实现这里不介绍了,感兴趣的朋友可以自行查找。明确地说,AES 是一个迭代的、对称密钥分组的密码,它可以使用128、192 和 256 位密钥,并且用 128 位(16字节)分组加密和解密数据。

    先上代码吧

    import java.io.UnsupportedEncodingException;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.KeyGenerator;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;
    
    
    public class Aes {
    
    	public static void main(String[] args)
    	{
    		String content = "不剃头的一休哥";
    		String password = "12345678fedcba";
    		try {
    			KeyGenerator kg = KeyGenerator.getInstance("AES");
    			SecureRandom sr = new SecureRandom(password.getBytes());
    			kg.init(128,sr);
    			
    			SecretKey secretKey = kg.generateKey();
    			System.out.println("SecureRandom:"+sr.toString());
    			System.out.println("SecretKey:"+secretKey);
    			byte[] enCodeFormat = secretKey.getEncoded(); 
    			SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 
    			Cipher cipher = Cipher.getInstance("AES");// 创建密码器 
    			byte[] byteContent = content.getBytes("utf-8");  
                cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化  
                byte[] result = cipher.doFinal(byteContent);  
                String str_res = byte2String(result); // 
                System.out.println("密文:"+str_res);
    		} catch (NoSuchAlgorithmException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (NoSuchPaddingException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (UnsupportedEncodingException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (InvalidKeyException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IllegalBlockSizeException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (BadPaddingException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    	public static String byte2String(byte[] b) {
            String hs = "";
            String stmp = "";
            for (int n = 0; n < b.length; n++) {
                stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
                if (stmp.length() == 1)
                    hs = hs + "0" + stmp;
                else
                    hs = hs + stmp;
            }
            return hs.toUpperCase();
        }
    }
    

     代码中我有些一点解释:

    kg.init(128,new SecureRandom(password.getBytes()));
    SecretKey secretKey = kg.generateKey();
    

     第一行代码中的随机数可能不同,也就是说kg.init产生的影响可能不同。但是,只要保证password相同,所产生的secretKey就相同。如图所示(DES算法中也用到了随机数,所以也存在此类问题)

    查看参考手册可以发现,init函数的作用是  使用用户提供的随机源初始化此密钥生成器,使其具有确定的密钥大小。SecureRandom此类提供强加密随机数生成器。所以,虽然值不同,但是他们同属于一类。我们使用的时候就是用到他们的共同特征。(好牵强,我也没搞懂他们的共同特征是什么o(╯□╰)o)

    大概就写这么多吧,有时间查下KeyGenerator.generateKey()的源代码,就能知道他们的共同特征了。然后再作补充。

    嗯,加油。

    PS:

    1、部分内容来源于网上。

    2、下周就要真正参与到开发了,周末好好熟悉一下业务流程。O(∩_∩)O~~

     

    
    
    
  • 相关阅读:
    XML和JSON优缺点
    JSON与XML优缺点对比分析
    json数据格式
    ajax 请求二进制流 图片
    常用网站
    Js setTimeout 用法
    js Indexof的用法
    02_虚拟机的安装和SecureCRT、FileZilla、Xmanage、UltraEdit工具的介绍
    01_Hadoop学习笔记内容说明
    sudoers文件设置sudo命令无密码(root密码)登录
  • 原文地址:https://www.cnblogs.com/hearzeus/p/4318848.html
Copyright © 2011-2022 走看看