Java中常用加减密方式

1、加密概述:

         加密就是是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使以获得了加密的信息,但因不知解密方式,仍无法了解信息的内容。大体上又分为双向加密和单向加密。

2、单项加密

2.1、概述:

  单向加密又称为不可逆加密算法,在加密过程中不使用密钥,明文由系统加密成密文,密文无法破解,一般都是采用验证的方式,具体是:在验证过程中,重新输入明文,并经过同样的加密算法后,得到相同的密文。单向加密广泛用于口令加密。

2.2、特点:

(1)对同一消息反复执行加密得到相同的密文;

(2)加密算法生成密文不可预见;

(3)不可逆,一般不能通过密文获取明文

2.3、类别

2.3.1、MD5加密

2.3.1.1、概述:

  MD5的全称是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由MIT Laboratory for Computer Science和RSA Data Security Inc的Ronald L. Rivest开发出来,经MD2、MD3和MD4发展而来。

  MD5用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3MD4

  MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。

2.3.1.2、算法原理:

  对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

  在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448。因此,信息的位长(Bits Length)将被扩展至N*512+448,N为一个非负整数,N可以是零。填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。然后,在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。

2.3.1.3、java代码中使用MD5加密

 1       /**
 2      * md5计算.
 3      * 
 4      * @param datas
 5      *            待计算的数据
 6      * @return 计算结果
 7      */
 8     public static byte[] md5(byte[] datas) {
 9         MessageDigest md = null;
10         try {
11             md = MessageDigest.getInstance("MD5");
12             md.reset();
13             md.update(datas);
14             return md.digest();
15         } catch (Exception e) {
16             log.error("MD5计算失败", e);
17             return null;
18         }
19     }

 

 

2.3.2、SHA加密

2.3.2.1、概述

  其思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)的密文。可以简单的理解为取一串输入码(称为预映射或信息),并把他们转化为长度较短、位数固定的输出序列的过程。

  安全散列算法SHA(Secure Hash Algorithm,SHA)是美国国家标准技术研究所发布的国家标准FIPS PUB 180,最新的标准已经于2008年更新到FIPS PUB 180-3。其中规定了SHA-1,SHA-224,SHA-256,SHA-384,和SHA-512这几种单向散列算法。SHA-1,SHA-224和SHA-256适用于长度不超过2^64二进制位的消息。SHA-384和SHA-512适用于长度不超过2^128二进制位的消息。

2.3.2.2、原理

  SHA-1是一种数据加密算法,该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。

  单向散列函数的安全性在于其产生散列值的操作过程具有较强的单向性。如果在输入序列中嵌入密码,那么任何人在不知道密码的情况下都不能产生正确的散列值,从而保证了其安全性。SHA将输入流按照每块512位(64个字节)进行分块,并产生20个字节的被称为信息认证代码或信息摘要的输出。

该算法输入报文的长度不限,产生的输出是一个160位的报文摘要。输入是按512 位的分组进行处理的。SHA-1是不可逆的、防冲突,并具有良好的雪崩效应。

通过散列算法可实现数字签名实现,数字签名的原理是将要传送的明文通过一种函数运算(Hash)转换成报文摘要(不同的明文对应不同的报文摘要),报文摘要加密后与明文一起传送给接受方,接受方将接受的明文产生新的报文摘要与发送方的发来报文摘要解密比较,比较结果一致表示明文未被改动,如果不一致表示明文已被篡改。

MAC (信息认证代码)就是一个散列结果,其中部分输入信息是密码,只有知道这个密码的参与者才能再次计算和验证MAC码的合法性。

2.3.2.3、java中的SHA实现

 

      /**
	 * SHA1签名
	 * @param paramStr 要加签的字符串
	 * @return
	 */
	public static String SHA1(String paramStr) {
		MessageDigest alg;
		String result = "";
		String tmp = "";
		try {
			alg = MessageDigest.getInstance("SHA-1");
			alg.update(paramStr.getBytes());
			byte[] bts = alg.digest();

			for (int i = 0; i < bts.length; i++) {
				tmp = (Integer.toHexString(bts[i] & 0xFF));
				if (tmp.length() == 1)
					result += "0";
				result += tmp;
			}
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return result;
	}

  

2.4、SHA与MD5的区别:

(1)对强行攻击的安全性:最显著和最重要的区别是:SHA-1的摘要比MD5的摘要长32位。使用强行技术,产生任何一个报文使其摘要等于给定摘要的难度对MD5是是2^128数量级的操作,而对SHA-1则是2^160数量级的操作。这样,SHA-1对强行攻击有更大的强度。

(2)对密码分析的安全性:由于MD5的设计,易受密码分析的攻击,SHA-1不易受这样的攻击。

3、双向加密

3.1概述

         大体意思是明文加密后形成密文,可以通过算法还原成明文。

3.2分类

3.2.1对称加密

3.2.1.1概述

  对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。

3.2.1.2特点

优点:

    (1)算法公开,计算量小、加密速度快、加密效率高

缺点:

         (1)交易双方都使用同样的密钥,安全性得不到保证

         (2)每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一密钥,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。

3.2.1.3常用对称加密算法

  基于“对称密钥”的加密算法比较常用的主要有:DES 、 3DES 、AES

 

(1)DES

概述:

  DES算法全称为Data Encryption Standard,即数据加密算法,它是IBM公司于1975年研究成功并公开发表的。DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。

算法原理:

   DES算法的入口参数有三个:Key、Data、Mode。

  (1)Key为8个字节共64位,是DES算法的工作密钥;

  (2)Data也为8个字节64位,是要被加密或被解密的数据;

  (3)Mode为DES的工作方式,有两种:加密或解密。

 

  DES算法是这样工作的:如Mode为加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。来源:

链接:https://www.zhihu.com/question/36767829/answer/68911532

算法应用: 

  目前在国内,随着三金工程尤其是金卡工程的启动,DES算法在POS、ATM、磁卡及智能卡(IC卡)、加油站、高速公路收费站等领域被广泛应用,以此来实现关键数据的保密,如信用卡持卡人的PIN的加密传输,IC卡与POS间的双向认证、金融交易数据包的MAC校验等,均用到DES算法。

java代码实现:

  1       /**
  2      * 3DES加密
  3      * 
  4      * @param key
  5      *            密钥信息
  6      * @param content
  7      *            待加密信息
  8      * @return
  9      * @throws Exception
 10      */
 11     public static byte[] encode3DES(byte[] key, byte[] content) throws Exception {
 12         Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
 13         // 不是8的倍数的,补足
 14         if (key.length % 8 != 0) {
 15             int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
 16             byte[] temp = new byte[groups * 8];
 17             Arrays.fill(temp, (byte) 0);
 18             System.arraycopy(key, 0, temp, 0, key.length);
 19             key = temp;
 20         }
 21         // 长度为16位,转换成24位的密钥
 22         if (key.length == 16) {
 23             byte[] temp = new byte[24];
 24             System.arraycopy(key, 0, temp, 0, key.length);
 25             System.arraycopy(key, 0, temp, key.length, temp.length - key.length);
 26             key = temp;
 27         }
 28 
 29         // 不是8的倍数的,补足
 30         byte[] srcBytes = content;
 31         if (srcBytes.length % 8 != 0) {
 32             int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
 33             srcBytes = new byte[groups * 8];
 34             Arrays.fill(srcBytes, (byte) 0);
 35             System.arraycopy(content, 0, srcBytes, 0, content.length);
 36         }
 37 
 38         SecretKey deskey = new SecretKeySpec(key, "DESede");
 39         Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
 40         cipher.init(Cipher.ENCRYPT_MODE, deskey);
 41         byte[] temp = cipher.doFinal(srcBytes);
 42         byte[] tgtBytes = new byte[content.length];
 43         System.arraycopy(temp, 0, tgtBytes, 0, tgtBytes.length);
 44         return tgtBytes;
 45     }
 46 
 47     /**
 48      * 3DES解密
 49      * 
 50      * @param key
 51      *            密钥
 52      * @param content
 53      *            待解密信息
 54      * @return
 55      * @throws Exception
 56      */
 57     public static byte[] decode3DES(byte[] key, byte[] content) throws Exception {
 58         // 不是8的倍数的,补足
 59         if (key.length % 8 != 0) {
 60             int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
 61             byte[] temp = new byte[groups * 8];
 62             Arrays.fill(temp, (byte) 0);
 63             System.arraycopy(key, 0, temp, 0, key.length);
 64             key = temp;
 65         }
 66         // 长度为16位,转换成24位的密钥
 67         if (key.length == 16) {
 68             byte[] temp = new byte[24];
 69             System.arraycopy(key, 0, temp, 0, key.length);
 70             System.arraycopy(key, 0, temp, key.length, temp.length - key.length);
 71             key = temp;
 72         }
 73 
 74         // 不是8的倍数的,补足
 75         byte[] srcBytes = content;
 76         if (srcBytes.length % 8 != 0) {
 77             int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
 78             srcBytes = new byte[groups * 8];
 79             Arrays.fill(srcBytes, (byte) 0);
 80             System.arraycopy(content, 0, srcBytes, 0, content.length);
 81         }
 82 
 83         SecretKey deskey = new SecretKeySpec(key, "DESede");
 84         Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
 85         cipher.init(Cipher.DECRYPT_MODE, deskey);
 86         byte[] tgtBytes = cipher.doFinal(srcBytes);
 87         return tgtBytes;
 88     }
 89 
 90     /**
 91      * DES加密
 92      * 
 93      * @param key
 94      *            密钥信息
 95      * @param content
 96      *            待加密信息
 97      * @return
 98      * @throws Exception
 99      */
100     public static byte[] encodeDES(byte[] key, byte[] content) throws Exception {
101         // 不是8的倍数的,补足
102         if (key.length % 8 != 0) {
103             int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
104             byte[] temp = new byte[groups * 8];
105             Arrays.fill(temp, (byte) 0);
106             System.arraycopy(key, 0, temp, 0, key.length);
107             key = temp;
108         }
109 
110         // 不是8的倍数的,补足
111         byte[] srcBytes = content;
112         if (srcBytes.length % 8 != 0) {
113             int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
114             srcBytes = new byte[groups * 8];
115             Arrays.fill(srcBytes, (byte) 0);
116             System.arraycopy(content, 0, srcBytes, 0, content.length);
117         }
118 
119         IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
120         SecureRandom sr = new SecureRandom();
121         DESKeySpec dks = new DESKeySpec(key);
122         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
123         SecretKey secretKey = keyFactory.generateSecret(dks);
124         Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
125         cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv, sr);
126         byte[] tgtBytes = cipher.doFinal(srcBytes);
127         return tgtBytes;
128     }
129 
130     /**
131      * DES解密
132      * 
133      * @param key
134      *            密钥信息
135      * @param content
136      *            待加密信息
137      * @return
138      * @throws Exception
139      */
140     public static byte[] decodeDES(byte[] key, byte[] content) throws Exception {
141         // 不是8的倍数的,补足
142         if (key.length % 8 != 0) {
143             int groups = key.length / 8 + (key.length % 8 != 0 ? 1 : 0);
144             byte[] temp = new byte[groups * 8];
145             Arrays.fill(temp, (byte) 0);
146             System.arraycopy(key, 0, temp, 0, key.length);
147             key = temp;
148         }
149         // 不是8的倍数的,补足
150         byte[] srcBytes = content;
151         if (srcBytes.length % 8 != 0) {
152             int groups = content.length / 8 + (content.length % 8 != 0 ? 1 : 0);
153             srcBytes = new byte[groups * 8];
154             Arrays.fill(srcBytes, (byte) 0);
155             System.arraycopy(content, 0, srcBytes, 0, content.length);
156         }
157 
158         IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
159         SecureRandom sr = new SecureRandom();
160         DESKeySpec dks = new DESKeySpec(key);
161         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
162         SecretKey secretKey = keyFactory.generateSecret(dks);
163         Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
164         cipher.init(Cipher.DECRYPT_MODE, secretKey, iv, sr);
165         byte[] tgtBytes = cipher.doFinal(content);
166         return tgtBytes;
167     }

 (2)3DES

概述:

  3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法

算法原理:

  3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),加密算法,其具体实现如下:设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,M代表明文,C代表密文,这样:
(1)3DES加密过程为:C=Ek3(Dk2(Ek1(M)))
(2)3DES解密过程为:M=Dk1(EK2(Dk3(C)))
java代码实现:
  1 package cn.mars.app.txn.bjyl;
  2   
  3 import java.security.Key;
  4 import java.security.Security;
  5 
  6 import javax.crypto.Cipher;
  7 import javax.crypto.SecretKeyFactory;
  8 import javax.crypto.spec.DESedeKeySpec;
  9 
 10 /**
 11  * 3DES加密
 12  * 
 13  * @version 1.0
 14  * @author
 15  * 
 16  */
 17 public class DesUtil {
 18 
 19     /**
 20      * 密钥算法
 21      */
 22     public static final String KEY_ALGORITHM = "DESede";
 23     public static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";
 24     private static String strDefaultKey = "national";
 25     private Cipher encryptCipher = null;
 26     private Cipher decryptCipher = null;
 27 
 28     public DesUtil() throws Exception {
 29         this(strDefaultKey);
 30     }
 31     
 32     public static String byteArr2HexStr(byte[] arrB) throws Exception {
 33         int iLen = arrB.length;
 34         StringBuffer sb = new StringBuffer(iLen * 2);
 35         for (int i = 0; i < iLen; i++) {
 36             int intTmp = arrB[i];
 37             while (intTmp < 0) {
 38                 intTmp = intTmp + 256;
 39             }
 40             if (intTmp < 16) {
 41                 sb.append("0");
 42             }
 43             sb.append(Integer.toString(intTmp, 16));
 44         }
 45         return sb.toString();
 46     }
 47 
 48     public static byte[] hexStr2ByteArr(String strIn) throws Exception {
 49         byte[] arrB = strIn.getBytes();
 50         int iLen = arrB.length;
 51         byte[] arrOut = new byte[iLen / 2];
 52         for (int i = 0; i < iLen; i = i + 2) {
 53             String strTmp = new String(arrB, i, 2);
 54             arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
 55         }
 56         return arrOut;
 57     }
 58     /**
 59      * @param strKey
 60      * @throws Exception
 61      */
 62     public DesUtil(String strKey) throws Exception {
 63         Security.addProvider(new com.sun.crypto.provider.SunJCE());
 64         Key key = getKey(StringUtil.hexStringToByteArray(strKey));
 65         encryptCipher = Cipher.getInstance("DES/ECB/NoPadding");
 66         encryptCipher.init(Cipher.ENCRYPT_MODE, key);
 67         decryptCipher = Cipher.getInstance("DES/ECB/NoPadding");
 68         decryptCipher.init(Cipher.DECRYPT_MODE, key);
 69     }
 70 
 71     public byte[] encrypt(byte[] arrB) throws Exception {
 72         return encryptCipher.doFinal(arrB);
 73     }
 74 
 75     public String encrypt(String strIn) throws Exception {
 76         return byteArr2HexStr(encrypt(strIn.getBytes()));
 77     }
 78 
 79     public byte[] decrypt(byte[] arrB) throws Exception {
 80         return decryptCipher.doFinal(arrB);
 81     }
 82 
 83     public String decrypt(String strIn) throws Exception {
 84         return new String(decrypt(hexStr2ByteArr(strIn)));
 85     }
 86 
 87     private Key getKey(byte[] arrBTmp) throws Exception {
 88         byte[] arrB = new byte[8];
 89         for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
 90             arrB[i] = arrBTmp[i];
 91         }
 92         Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES");
 93         return key;
 94     }
 95 
 96     public static String printbytes(String tip, byte[] b) {
 97         String ret = "";
 98         String str;
 99         System.out.println(tip);
100         for (int i = 0; i < b.length; i++) {
101             str = Integer.toHexString((int) (b[i] & 0xff));
102             if (str.length() == 1)
103                 str = "0" + str;
104             System.out.print(str + " ");
105             ret = ret + str + " ";
106         }
107         return ret;
108     }
109     /**
110      * 加密
111      * @param data
112      * @param key
113      * @return
114      * @throws Exception
115      * @author yangxing
116      * 2014-7-22
117      */
118     public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
119         Key k = toKey(key);// 还原密钥
120         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
121         cipher.init(Cipher.ENCRYPT_MODE, k);
122         return cipher.doFinal(data);
123     }
124     /**
125      * 解密
126      * 
127      * @param data 待解密数据
128      * @param key 密钥
129      * @return byte[] 解密数据
130      */
131     public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
132         // 还原密钥
133         Key k = toKey(key);
134         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
135         // 初始化,设置为解密模式
136         cipher.init(Cipher.DECRYPT_MODE, k);
137         // 执行操作
138         return cipher.doFinal(data);
139     }
140     /**
141      * 转换密钥
142      * @param key 二进制密钥
143      * @return key 密钥
144      */
145     public static Key toKey(byte[] key) throws Exception {
146         DESedeKeySpec dks = new DESedeKeySpec(key);
147         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
148         return keyFactory.generateSecret(dks);
149     }
150     
151     public static void main(String[] args) {
152         try {
153             byte[] data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 };
154             DesUtil des1 = new DesUtil("498F456AC9D9CBA0");
155             printbytes("data", des1.encrypt(data));
156         } catch (Exception e) {
157             e.printStackTrace();
158         }
159     }
160 }

(3)AES

概述:
  高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。
原理:
  AES加密过程涉及到4种操作:字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。解密过程分别为对应的逆操作。由于每一步操作都是可逆的,按照相反的顺序进行解密即可恢复明文。加解密中每轮的密钥分别由初始密钥扩展得到。算法中16字节的明文、密文和轮密钥都以一个4x4的矩阵表示。

 

java代码实现:

  1 package cn.mars.app.txn.wanglian;
  2 
  3 import java.security.MessageDigest;
  4 import java.security.NoSuchAlgorithmException;
  5 import java.security.SecureRandom;
  6 import java.security.Security;
  7 
  8 import javax.crypto.Cipher;
  9 import javax.crypto.KeyGenerator;
 10 import javax.crypto.SecretKey;
 11 import javax.crypto.spec.SecretKeySpec;
 12 
 13 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 14 
 15 import cfca.util.Base64;
 16 
 17 /**
 18  * java实现AES256加密解密
 19  * @author xiaoqiang
 20  *
 21  */
 22 
 23 public class AES256Util {
 24 
 25     public static byte[] encrypt(String content, String password) {
 26         try {
 27             // "AES":请求的密钥算法的标准名称
 28             KeyGenerator kgen = KeyGenerator.getInstance("AES");
 29             // 256:密钥生成参数;securerandom:密钥生成器的随机源
 30             SecureRandom securerandom = new SecureRandom(tohash256Deal(password));
 31             kgen.init(256, securerandom);
 32             // 生成秘密(对称)密钥
 33             SecretKey secretKey = kgen.generateKey();
 34             // 返回基本编码格式的密钥
 35             byte[] enCodeFormat = secretKey.getEncoded();
 36             // 根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称
 37             SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
 38             // 将提供程序添加到下一个可用位置
 39             Security.addProvider(new BouncyCastleProvider());
 40             // 创建一个实现指定转换的 Cipher对象,该转换由指定的提供程序提供。
 41             // "AES/ECB/PKCS7Padding":转换的名称;"BC":提供程序的名称
 42             Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
 43 
 44             cipher.init(Cipher.ENCRYPT_MODE, key);
 45             byte[] byteContent = content.getBytes("utf-8");
 46             byte[] cryptograph = cipher.doFinal(byteContent);
 47             byte[] encode = Base64.encode(cryptograph);
 48 
 49             return encode;
 50         } catch (Exception e) {
 51             e.printStackTrace();
 52         }
 53         return null;
 54     }
 55 
 56     public static String decrypt(byte[] cryptograph, String password) {
 57         try {
 58             KeyGenerator kgen = KeyGenerator.getInstance("AES");
 59             SecureRandom securerandom = new SecureRandom(tohash256Deal(password));
 60             kgen.init(256, securerandom);
 61             SecretKey secretKey = kgen.generateKey();
 62             byte[] enCodeFormat = secretKey.getEncoded();
 63             SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
 64             Security.addProvider(new BouncyCastleProvider());
 65             Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
 66 
 67             cipher.init(Cipher.DECRYPT_MODE, key);
 68             byte[] content = cipher.doFinal(Base64.decode(cryptograph));
 69             return new String(content);
 70         } catch (Exception e) {
 71             e.printStackTrace();
 72         }
 73         return null;
 74     }
 75 
 76     public static String parseByte2HexStr(byte buf[]) {
 77         StringBuffer sb = new StringBuffer();
 78         for (int i = 0; i < buf.length; i++) {
 79             String hex = Integer.toHexString(buf[i] & 0xFF);
 80             if (hex.length() == 1) {
 81                 hex = '0' + hex;
 82             }
 83             sb.append(hex.toUpperCase());
 84         }
 85         return sb.toString();
 86     }
 87 
 88     /*
 89      * private static byte[] parseHexStr2Byte(String hexStr) { if
 90      * (hexStr.length() < 1) return null; byte[] result = new
 91      * byte[hexStr.length()/2]; for (int i = 0;i< hexStr.length()/2; i++) { int
 92      * high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); int low =
 93      * Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); result[i] = (byte)
 94      * (high * 16 + low); } return result; }
 95      */
 96 
 97     private static byte[] tohash256Deal(String datastr) {
 98         try {
 99             MessageDigest digester = MessageDigest.getInstance("SHA-256");
100             digester.update(datastr.getBytes());
101             byte[] hex = digester.digest();
102             return hex;
103         } catch (NoSuchAlgorithmException e) {
104             throw new RuntimeException(e.getMessage());
105         }
106     }
107 
108     /**
109      * 生成随机密钥
110      * 
111      * @param size
112      *            位数
113      * @return
114      */
115     public static String generateRandomKey(int size) {
116         StringBuilder key = new StringBuilder();
117         String chars = "0123456789ABCDEF";
118         for (int i = 0; i < size; i++) {
119             int index = (int) (Math.random() * (chars.length() - 1));
120             key.append(chars.charAt(index));
121         }
122         return key.toString();
123     }
124 
125     public static void main(String[] args) {
126 
127         String content = "123456";
128         String password = generateRandomKey(32);
129         System.out.println("明文:" + content);
130         System.out.println("key:" + password);
131 
132         byte[] encryptResult = AES256Util.encrypt(content, password);
133         System.out.println(encryptResult);
134         System.out.println("密文:" + AES256Util.parseByte2HexStr(encryptResult));
135 
136         String decryptResult = AES256Util.decrypt(encryptResult, password);
137         System.out.println("解密:" + decryptResult);
138     }
139 }

 

3.2.2非对称加密

3.2.2.1概述

  1976年,美国学者Dime和Henman为解决信息公开传送和密钥管理问题,提出一种新的密钥交换协议,允许在不安全的媒体上的通讯双方交换信息,安全地达成一致的密钥,这就是“公开密钥系统”。
  与对称加密算法不同,非对称加密算法需要两个密钥公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法
3.2.2.2工作流程
  如下图所示,甲乙之间使用非对称加密的方式完成了重要信息的安全传输。
  
  非对称加密工作过程简要示意图
  1、乙方生成一对密钥(公钥和私钥)并将公钥向其它方公开。
  2、得到该公钥的甲方使用该密钥对机密信息进行加密后再发送给乙方。
  3、乙方再用自己保存的另一把专用密钥(私钥)对加密后的信息进行解密。乙方只能用其专用密钥(私钥)解密由对应的公钥加密后的信息。
  在传输过程中,即使攻击者截获了传输的密文,并得到了乙的公钥,也无法破解密文,因为只有乙的私钥才能解密密文。
  同样,如果乙要回复加密信息给甲,那么需要甲先公布甲的公钥给乙用于加密,甲自己保存甲的私钥用于解密。
3.2.2.3优缺点:
  (1)优点:非对称加密与对称加密相比,其安全性更好:对称加密的通信双方使用相同的秘钥,如果一方的秘钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的,不需要像对称加密那样在通信之前要先同步秘钥。
  (2)缺点:非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
3.2.2.4常用非对称加密算法:
  在非对称加密中使用的主要算法有:RSAElgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等,其中RSA是最常用的。
(1)RSA加密算法
概述:
  RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准
  RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。
  在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK。
  正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要。
RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。
加密过程:
  (1)用户A和用户B通信,为了保证信息安全,使用RSA加密;
  (2)用户A生成一对公司钥,保留私钥,提供公钥给B用户;A发送信息给B,使用生成的私钥进行加密;
  (3)用户B接收用户A加密后的信息,使用A提供的公钥进行解密
java代码实现:
  1 package cn.mars.app.txn.zjyl;
  2 
  3 import java.io.ByteArrayOutputStream;
  4 import java.security.Key;
  5 import java.security.KeyFactory;
  6 import java.security.KeyPair;
  7 import java.security.KeyPairGenerator;
  8 import java.security.NoSuchAlgorithmException;
  9 import java.security.interfaces.RSAPrivateKey;
 10 import java.security.interfaces.RSAPublicKey;
 11 import java.security.spec.PKCS8EncodedKeySpec;
 12 import java.security.spec.X509EncodedKeySpec;
 13 import java.util.HashMap;
 14 import java.util.Map;
 15 
 16 import javax.crypto.Cipher;
 17 
 18 /**
 19  * Rsa工具类
 20  * 
 21  * @author ThinkPad
 22  *
 23  */
 24 public abstract class RsaUtils {
 25     /**
 26      * 生成公钥私钥对,使用默认模长1024。
 27      * 
 28      * @return Object[] : 0:公钥( RSAPublicKey ),1:私钥( RSAPrivateKey )
 29      */
 30 
 31     private static final int DEFAULT_KEY_LEN = 2048;
 32 
 33     public static Map<String, String> genKeyPair() {
 34         return genKeyPair(DEFAULT_KEY_LEN);
 35 
 36     }
 37 
 38     /**
 39      * 指定模长生成公私钥对
 40      * 
 41      * @param modulus
 42      * @return
 43      */
 44     public static Map<String, String> genKeyPair(int modulus) {
 45         KeyPairGenerator keyPairGen;
 46         try {
 47             keyPairGen = KeyPairGenerator.getInstance("RSA");
 48             keyPairGen.initialize(modulus);
 49             KeyPair keyPair = keyPairGen.generateKeyPair();
 50 
 51             Map<String, String> keyMaps = new HashMap<String, String>();
 52             RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
 53             keyMaps.put("publicKey", new String(Base64.encode(publicKey.getEncoded())));
 54             RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
 55             keyMaps.put("privateKey", new String(Base64.encode(privateKey.getEncoded())));
 56 
 57             return keyMaps;
 58         } catch (NoSuchAlgorithmException e) {
 59             throw new RuntimeException(e);
 60         }
 61     }
 62 
 63     /**
 64      * 公钥加密
 65      * 
 66      * @param publicKeyBytes
 67      * @param data
 68      * @param modulus
 69      *            公钥模长,范围512-2048。
 70      * @return
 71      */
 72     public static byte[] encryptByPublicKey(byte[] publicKeyBytes, byte[] data, int modulus) {
 73         try {
 74             // RSA最大加密明文大小
 75             int maxEncryptBlock = modulus / 8 - 11;
 76 
 77             X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes);
 78             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
 79             Key publicK = keyFactory.generatePublic(x509KeySpec);
 80             Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
 81             cipher.init(Cipher.ENCRYPT_MODE, publicK);
 82             int inputLen = data.length;
 83             ByteArrayOutputStream out = new ByteArrayOutputStream();
 84             int offSet = 0;
 85             byte[] cache;
 86             int i = 0;
 87             while (inputLen - offSet > 0) {
 88                 if (inputLen - offSet > maxEncryptBlock) {
 89                     cache = cipher.doFinal(data, offSet, maxEncryptBlock);
 90                 } else {
 91                     cache = cipher.doFinal(data, offSet, inputLen - offSet);
 92                 }
 93                 out.write(cache, 0, cache.length);
 94                 i++;
 95                 offSet = i * maxEncryptBlock;
 96             }
 97             byte[] encryptedData = out.toByteArray();
 98             out.close();
 99             return encryptedData;
100         } catch (Exception e) {
101             throw new RuntimeException(e);
102         }
103 
104     }
105 
106     /**
107      * 公钥加密,密钥模长使用默认长度1024。
108      * 
109      * @param publicKeyBytes
110      *            公钥RSAPublicKey getEncoded()
111      * @param data
112      *            要加密的字节数组
113      */
114     public static byte[] encryptByPublicKey(byte[] publicKeyBytes, byte[] data) {
115         return encryptByPublicKey(publicKeyBytes, data, DEFAULT_KEY_LEN);
116     }
117 
118     /**
119      * 公钥解密
120      * 
121      * @param publicKeyBytes
122      *            公钥RSAPublicKey getEncoded()
123      * @param encryptedData
124      *            被(私钥)加密过的字节数组
125      * @param modulus
126      *            模长,范围512-2048
127      * @return
128      */
129     public static byte[] decryptByPublicKey(byte[] publicKeyBytes, byte[] encryptedData, int modulus) {
130         // RSA最大解密密文大小
131         int maxDecryptBlock = modulus / 8;
132         try {
133             X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes);
134             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
135             Key publicK = keyFactory.generatePublic(x509KeySpec);
136             Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
137             cipher.init(Cipher.DECRYPT_MODE, publicK);
138             int inputLen = encryptedData.length;
139             ByteArrayOutputStream out = new ByteArrayOutputStream();
140             int offSet = 0;
141             byte[] cache;
142             int i = 0;
143             // 对数据分段解密
144             while (inputLen - offSet > 0) {
145                 if (inputLen - offSet > maxDecryptBlock) {
146                     cache = cipher.doFinal(encryptedData, offSet, maxDecryptBlock);
147                 } else {
148                     cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
149                 }
150                 out.write(cache, 0, cache.length);
151                 i++;
152                 offSet = i * maxDecryptBlock;
153             }
154             byte[] decryptedData = out.toByteArray();
155             out.close();
156             return decryptedData;
157         } catch (Exception e) {
158             throw new RuntimeException(e);
159         }
160     }
161 
162     /**
163      * 公钥解密,默认模长1024
164      * 
165      * @param publicKeyBytes
166      *            公钥RSAPublicKey getEncoded()
167      * @param encryptedData
168      *            被(私钥)加密过的字节数组
169      */
170     public static byte[] decryptByPublicKey(byte[] publicKeyBytes, byte[] encryptedData) {
171         return decryptByPublicKey(publicKeyBytes, encryptedData, DEFAULT_KEY_LEN);
172     }
173 
174     /**
175      * 私钥加密
176      * 
177      * @param privateKeyBytes
178      *            私钥RSAPrivateKey getEncoded()
179      * @param data
180      *            要加密的字节数组
181      * @param modulus
182      *            模长,范围512-2048。
183      */
184     public static byte[] encryptByPrivateKey(byte[] privateKeyBytes, byte[] data, int modulus) {
185         try {
186             // RSA最大加密明文大小
187             int maxEncryptBlock = modulus / 8 - 11;
188 
189             PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
190             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
191             Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
192             Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
193             cipher.init(Cipher.ENCRYPT_MODE, privateK);
194             int inputLen = data.length;
195             ByteArrayOutputStream out = new ByteArrayOutputStream();
196             int offSet = 0;
197             byte[] cache;
198             int i = 0;
199             while (inputLen - offSet > 0) {
200                 if (inputLen - offSet > maxEncryptBlock) {
201                     cache = cipher.doFinal(data, offSet, maxEncryptBlock);
202                 } else {
203                     cache = cipher.doFinal(data, offSet, inputLen - offSet);
204                 }
205                 out.write(cache, 0, cache.length);
206                 i++;
207                 offSet = i * maxEncryptBlock;
208             }
209             byte[] encryptedData = out.toByteArray();
210             out.close();
211             return encryptedData;
212         } catch (Exception e) {
213             throw new RuntimeException(e);
214         }
215     }
216 
217     /**
218      * 私钥加密,默认模长1024。
219      * 
220      * @param privateKeyBytes
221      *            私钥RSAPrivateKey getEncoded()
222      * @param data
223      *            要加密的字节数组
224      */
225     public static byte[] encryptByPrivateKey(byte[] privateKeyBytes, byte[] data) {
226         return encryptByPrivateKey(privateKeyBytes, data, DEFAULT_KEY_LEN);
227     }
228 
229     /**
230      * 私钥解密
231      * 
232      * @param privateKeyBytes
233      *            私钥RSAPrivateKey getEncoded()
234      * @param encryptedData
235      *            被(公钥)加密过的字节数组
236      * @param modulus
237      *            模长,范围512-2048
238      */
239     public static byte[] decryptByPrivateKey(byte[] privateKeyBytes, byte[] encryptedData, int modulus) {
240         try {
241             // RSA最大解密密文大小
242             int maxDecryptBlock = modulus / 8;
243 
244             PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
245             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
246             Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
247             Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
248             cipher.init(Cipher.DECRYPT_MODE, privateK);
249             int inputLen = encryptedData.length;
250             ByteArrayOutputStream out = new ByteArrayOutputStream();
251             int offSet = 0;
252             byte[] cache;
253             int i = 0;
254             while (inputLen - offSet > 0) {
255                 if (inputLen - offSet > maxDecryptBlock) {
256                     cache = cipher.doFinal(encryptedData, offSet, maxDecryptBlock);
257                 } else {
258                     cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
259                 }
260                 out.write(cache, 0, cache.length);
261                 i++;
262                 offSet = i * maxDecryptBlock;
263             }
264             byte[] decryptedData = out.toByteArray();
265             out.close();
266             return decryptedData;
267         } catch (Exception e) {
268             throw new RuntimeException(e);
269         }
270     }
271 
272     /**
273      * 私钥解密,默认模长1024。
274      * 
275      * @param privateKeyBytes
276      *            私钥RSAPrivateKey getEncoded()
277      * @param encryptedData
278      *            被(公钥)加密过的字节数组
279      */
280     public static byte[] decryptByPrivateKey(byte[] privateKeyBytes, byte[] encryptedData) {
281         return decryptByPrivateKey(privateKeyBytes, encryptedData, DEFAULT_KEY_LEN);
282     }
283 
284     public static void main(String[] args) {
285         genKeyPair();
286     }
287 }

 

  此文只是简单介绍了java常用的加减密算法,之后文章会对每种算法做具体说明。

posted @ 2017-11-17 15:10  DREAM.XIN  阅读(1565)  评论(0编辑  收藏  举报