Java的各种加密算法
Java的各种加密算法
JAVA中为我们提供了丰富的加密技术,可以基本的分为单向加密和非对称加密
1.单向加密算法
单向加密算法主要用来验证数据传输的过程中,是否被篡改过。
-
BASE64 严格地说,属于编码格式,而非加密算法
-
MD5(Message Digest algorithm 5,信息摘要算法)
-
SHA(Secure Hash Algorithm,安全散列算法)
-
HMAC(Hash Message Authentication Code,散列消息鉴别码
- AES(Advanced Encryption Standard,高级加密算法)
-
DES(Data Encryption Standard,数据加密算法)
-
PBE(Password-based encryption,基于密码验证)
-
RSA(算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman)
-
DH(Diffie-Hellman算法,密钥一致协议)
-
DSA(Digital Signature Algorithm,数字签名)
-
ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学)
1 //单向加密 2 package com.cn.BaseTest; 3 import sun.misc.BASEDecoder; 4 import sun.misc.BASEEncoder; 5 /* 6 BASE的加密解密是双向的,可以求反解. 7 BASEEncoder和BASEDecoder是非官方JDK实现类。虽然可以在JDK里能找到并使用,但是在API里查不到。 8 JRE 中 sun 和 com.sun 开头包的类都是未被文档化的,他们属于 java, javax 类库的基础,其中的实现大多数与底层平台有关, 9 一般来说是不推荐使用的。 10 BASE 严格地说,属于编码格式,而非加密算法 11 主要就是BASEEncoder、BASEDecoder两个类,我们只需要知道使用对应的方法即可。 12 另,BASE加密后产生的字节位数是的倍数,如果不够位数以=符号填充。 13 BASE 14 按照RFC的定义,Base被定义为:Base内容传送编码被设计用来把任意序列的位字节描述为一种不易被人直接识别的形式。 15 (The Base Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.) 16 常见于邮件、http加密,截取http信息,你就会发现登录操作的用户名、密码字段通过BASE加密的。 17 */ 18 19 public class BASE { 20 21 /** 22 * BASE解密 23 * 24 * @param key 25 * @return 26 * @throws Exception 27 */ 28 public static byte[] decryptBASE(String key) throws Exception { 29 return (new BASEDecoder()).decodeBuffer(key); 30 } 31 32 /** 33 * BASE加密 34 * 35 * @param key 36 * @return 37 * @throws Exception 38 */ 39 public static String encryptBASE(byte[] key) throws Exception { 40 return (new BASEEncoder()).encodeBuffer(key); 41 } 42 43 public static void main(String[] args) { 44 String str="123456"; 45 try { 46 String result= BASE.encryptBASE(str.getBytes()); 47 System.out.println("加密数据>>>>:"+result); 48 byte result[]= BASE.decryptBASE(result); 49 String str=new String(result); 50 System.out.println("解密数据>>>>:"+str); 51 } catch (Exception e) { 52 e.printStackTrace(); 53 } 54 } 55 }
1.2 MD5加密
MD5即Message-Digest Algorithm (信息-摘要算法),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理。广泛用于加密和解密技术,常用于文件校验。校验?不管文件多大,经过MD5后都能生成唯一的MD5值。好比现在的ISO校验,都是MD5校验。怎么用?当然是把ISO经过MD5后产生MD5的值。一般下载linux-ISO的朋友都见过下载链接旁边放着MD5的串。就是用来验证文件是否一致的。
1 //单向加密 2 package com.cn.MD5Test; 3 import java.math.BigInteger; 4 import java.security.MessageDigest; 5 /* 6 MD5(Message Digest algorithm ,信息摘要算法) 7 通常我们不直接使用上述MD5加密。通常将MD5产生的字节数组交给BASE再加密一把,得到相应的字符串 8 Digest:汇编 9 */ 10 public class MD { 11 12 public static final String KEY_MD = "MD5"; 13 14 public static String getResult(String inputStr){ 15 System.out.println("加密前的数据>>>>:"+inputStr); 16 BigInteger bigInteger=null; 17 try { 18 MessageDigest md = MessageDigest.getInstance(KEY_MD); 19 byte[] inputData = inputStr.getBytes(); 20 md.update(inputData); 21 bigInteger = new BigInteger(md.digest()); 22 } catch (Exception e) {e.printStackTrace();} 23 System.out.println("MD5加密后>>>>:" + bigInteger.toString()); 24 return bigInteger.toString(); 25 26 } 27 28 public static void main(String args[]){ 29 try { 30 String inputStr = "123456"; 31 getResult(inputStr); 32 } catch (Exception e) { 33 e.printStackTrace(); 34 } 35 } 36 }
MD算法具有以下特点:
- 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
- 容易计算:从原数据计算出MD5值很容易。
- 抗修改性:对原数据进行任何改动,哪怕只修改个字节,所得到的MD5值都有很大区别。
- 弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
- 强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-、RIPEMD以及Haval等。
1.3 SHA加密
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于^位的消息,SHA会产生一个位的消息摘要。该算法经过加密专家多年来的发展和改进已日益完善,并被广泛使用。该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。散列函数值可以说是对明文的一种“指纹”或是“摘要”所以对散列值的数字签名就可以视为对此明文的数字签名。
java实现代码:
1 //单向加密 2 package com.cn.SHATest; 3 import java.math.BigInteger; 4 import java.security.MessageDigest; 5 /* 6 SHA(Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具, 7 被广泛地应用于电子商务等信息安全领域。虽然,SHA与MD5通过碰撞法都被破解了, 8 但是SHA仍然是公认的安全加密算法,较之MD更为安全*/ 9 public class SHA { 10 11 public static final String KEY_SHA = "SHA"; 12 13 public static String getResult(String inputStr){ 14 BigInteger sha =null; 15 System.out.println("加密前的数据>>>:"+inputStr); 16 byte[] inputData = inputStr.getBytes(); 17 try { 18 MessageDigest messageDigest = MessageDigest.getInstance(KEY_SHA); 19 messageDigest.update(inputData); 20 sha = new BigInteger(messageDigest.digest()); 21 System.out.println("SHA加密后>>>>>:" + sha.toString()); 22 } catch (Exception e) {e.printStackTrace();} 23 return sha.toString(); 24 } 25 26 public static void main(String args[]){ 27 try { 28 String inputStr = "简单加密"; 29 getResult(inputStr); 30 } catch (Exception e) { 31 e.printStackTrace(); 32 } 33 } 34
SHA-与MD的比较
因为二者均由MD导出,SHA-和MD5彼此很相似。相应的,他们的强度和其他特性也是相似,但还有以下几点不同:
- 对强行攻击的安全性:最显著和最重要的区别是SHA-摘要比MD5摘要长 位。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对MD5是^数量级的操作,而对SHA-则是^数量级的操作。这样,SHA-对强行攻击有更大的强度。
- 对密码分析的安全性:由于MD5的设计,易受密码分析的攻击,SHA-显得不易受这样的攻击。
- 速度:在相同的硬件上,SHA-的运行速度比MD5慢。
1.4 HMAC加密
HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。
java实现代码:
1 //单向加密 2 package com.cn.HMACTest; 3 /* 4 HMAC 5 HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。 6 消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。 7 使用一个密钥生成一个固定大小的小数据块, 8 即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。*/ 9 import javax.crypto.KeyGenerator; 10 import javax.crypto.Mac; 11 import javax.crypto.SecretKey; 12 import javax.crypto.spec.SecretKeySpec; 13 import com.cn.comm.Tools; 14 /** 15 * 基础加密组件 16 */ 17 public abstract class HMAC { 18 19 public static final String KEY_MAC = "HmacMD"; 20 21 /** 22 * 初始化HMAC密钥 23 * 24 * @return 25 * @throws Exception 26 */ 27 public static String initMacKey() throws Exception { 28 KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC); 29 SecretKey secretKey = keyGenerator.generateKey(); 30 return BASE.encryptBASE(secretKey.getEncoded()); 31 } 32 33 /** 34 * HMAC加密 :主要方法 35 * 36 * @param data 37 * @param key 38 * @return 39 * @throws Exception 40 */ 41 public static String encryptHMAC(byte[] data, String key) throws Exception { 42 SecretKey secretKey = new SecretKeySpec(BASE.decryptBASE(key), KEY_MAC); 43 Mac mac = Mac.getInstance(secretKey.getAlgorithm()); 44 mac.init(secretKey); 45 return new String(mac.doFinal(data)); 46 } 47 48 public static String getResult(String inputStr){ 49 String path=Tools.getClassPath(); 50 String fileSource=path+"/file/HMAC_key.txt"; 51 System.out.println("加密前的数据>>>>>:"+inputStr); 52 String result=null; 53 try { 54 byte[] inputData = inputStr.getBytes(); 55 String key = HMAC.initMacKey(); /*产生密钥*/ 56 System.out.println("Mac密钥>>>>>:" + key); 57 /*将密钥写文件*/ 58 Tools.WriteMyFile(fileSource,key); 59 result= HMAC.encryptHMAC(inputData, key); 60 System.out.println("HMAC加密后>>>>:" + result); 61 } catch (Exception e) { 62 e.printStackTrace(); 63 } 64 return result.toString(); 65 } 66 67 public static String getResult(String inputStr){ 68 System.out.println("加密前的数据>>>>:"+inputStr); 69 String path=Tools.getClassPath(); 70 String fileSource=path+"/file/HMAC_key.txt"; 71 String key=null;; 72 try { 73 /*将密钥从文件中读取*/ 74 key=Tools.ReadMyFile(fileSource); 75 System.out.println("getResult密钥>>>>:" + key); 76 } catch (Exception e) { 77 e.printStackTrace(); 78 } 79 String result=null; 80 try { 81 byte[] inputData = inputStr.getBytes(); 82 /*对数据进行加密*/ 83 result= HMAC.encryptHMAC(inputData, key); 84 System.out.println("HMAC加密后>>>>:" + result); 85 } catch (Exception e) { 86 e.printStackTrace(); 87 } 88 return result.toString(); 89 } 90 91 public static void main(String args[]){ 92 try { 93 String inputStr = "123456"; 94 /*使用同一密钥:对数据进行加密:查看两次加密的结果是否一样*/ 95 getResult(inputStr); 96 getResult(inputStr); 97 } catch (Exception e) { 98 e.printStackTrace(); 99 } 100 } 101 }
2.1 AES(Advanced Encryption Standard,高级加密标准)
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),是一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
那么为什么原来的DES会被取代呢,,原因就在于其使用56位密钥,比较容易被破解。而AES可以使用128、192、和256位密钥,并且用128位分组加密和解密数据,相对来说安全很多。完善的加密算法在理论上是无法破解的,除非使用穷尽法。使用穷尽法破解密钥长度在128位以上的加密数据是不现实的,仅存在理论上的可能性。统计显示,即使使用目前世界上运算速度最快的计算机,穷尽128位密钥也要花上几十亿年的时间,更不用说去破解采用256位密钥长度的AES算法了。
目前世界上还有组织在研究如何攻破AES这堵坚厚的墙,但是因为破解时间太长,AES得到保障,但是所用的时间不断缩小。随着计算机计算速度的增快,新算法的出现,AES遭到的攻击只会越来越猛烈,不会停止的。
AES现在广泛用于金融财务、在线交易、无线通信、数字存储等领域,经受了最严格的考验,但说不定哪天就会步DES的后尘。
java实现代码:
1 /** 2 * File Name:AESTest.java 3 * 4 * Date:2017年11月16日下午5:27:24 5 * Copyright (c) 2017 All Rights Reserved. 6 * 7 */ 8 9 package io.hexin.bean; 10 11 /** 12 * ClassName:AESTest 13 * Function: TODO 14 * Reason: TODO 15 * Date: 2017年11月16日 下午5:27:24 16 * @author lizm 17 * @since JDK 1.6 18 * 19 */ 20 public class AESTest { 21 22 /** 23 * AES加密字符串 24 * 25 * @param content 26 * 需要被加密的字符串 27 * @param password 28 * 加密需要的密码 29 * @return 密文 30 */ 31 public static byte[] encrypt(String content, String password) { 32 33 try { 34 // 创建AES的Key生产者 35 KeyGenerator kgen = KeyGenerator.getInstance("AES"); 36 // 利用用户密码作为随机数初始化出128位的key生产者 37 kgen.init(128, new SecureRandom(password.getBytes())); 38 //加密没关系,SecureRandom是生成安全随机数序列,password.getBytes()是种子,只要种子相同,序列就一样,所以解密只要有password就行 39 SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥 40 // 返回基本编码格式的密钥,如果此密钥不支持编码,则返回null。 41 byte[] enCodeFormat = secretKey.getEncoded(); 42 // 转换为AES专用密钥 43 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 44 // 创建密码器 45 Cipher cipher = Cipher.getInstance("AES"); 46 byte[] byteContent = content.getBytes("utf-8"); 47 // 初始化为加密模式的密码器 48 cipher.init(Cipher.ENCRYPT_MODE, key); 49 // 加密 50 byte[] result = cipher.doFinal(byteContent); 51 return result; 52 } catch (NoSuchPaddingException e) { 53 e.printStackTrace(); 54 } catch (NoSuchAlgorithmException e) { 55 e.printStackTrace(); 56 } catch (UnsupportedEncodingException e) { 57 e.printStackTrace(); 58 } catch (InvalidKeyException e) { 59 e.printStackTrace(); 60 } catch (IllegalBlockSizeException e) { 61 e.printStackTrace(); 62 } catch (BadPaddingException e) { 63 e.printStackTrace(); 64 } 65 return null; 66 } 67 68 /** 69 * 解密AES加密过的字符串 70 * 71 * @param content 72 * AES加密过过的内容 73 * @param password 74 * 加密时的密码 75 * @return 明文 76 */ 77 public static byte[] decrypt(byte[] content, String password) { 78 try { 79 // 创建AES的Key生产者 80 KeyGenerator kgen = KeyGenerator.getInstance("AES"); 81 kgen.init(128, new SecureRandom(password.getBytes())); 82 // 根据用户密码,生成一个密钥 83 SecretKey secretKey = kgen.generateKey(); 84 // 返回基本编码格式的密钥 85 byte[] enCodeFormat = secretKey.getEncoded(); 86 // 转换为AES专用密钥 87 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); 88 // 创建密码器 89 Cipher cipher = Cipher.getInstance("AES"); 90 // 初始化为解密模式的密码器 91 cipher.init(Cipher.DECRYPT_MODE, key); 92 byte[] result = cipher.doFinal(content); 93 // 明文 94 return result; 95 } catch (NoSuchAlgorithmException e) { 96 e.printStackTrace(); 97 } catch (NoSuchPaddingException e) { 98 e.printStackTrace(); 99 } catch (InvalidKeyException e) { 100 e.printStackTrace(); 101 } catch (IllegalBlockSizeException e) { 102 e.printStackTrace(); 103 } catch (BadPaddingException e) { 104 e.printStackTrace(); 105 } 106 return null; 107 } 108 109 110 /**将二进制转换成16进制 111 * @param buf 112 * @return 113 */ 114 public static String parseByte2HexStr(byte buf[]) { 115 StringBuffer sb = new StringBuffer(); 116 for (int i = 0; i < buf.length; i++) { 117 String hex = Integer.toHexString(buf[i] & 0xFF); 118 if (hex.length() == 1) { 119 hex = '0' + hex; 120 } 121 sb.append(hex.toUpperCase()); 122 } 123 return sb.toString(); 124 } 125 126 /**将16进制转换为二进制 127 * @param hexStr 128 * @return 129 */ 130 public static byte[] parseHexStr2Byte(String hexStr) { 131 if (hexStr.length() < 1) 132 return null; 133 byte[] result = new byte[hexStr.length()/2]; 134 for (int i = 0;i< hexStr.length()/2; i++) { 135 int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); 136 int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); 137 result[i] = (byte) (high * 16 + low); 138 } 139 return result; 140 } 141 142 public static void main(String[] args) { 143 String content = "美女,一起共进晚餐么?"; 144 String password = "123";//密码就是key 145 System.out.println("加密之前:" + content); 146 // 加密 147 byte[] encrypt = AesTest.encrypt(content, password); 148 System.out.println("加密后的内容:" + new String(encrypt)); 149 150 //如果想要加密内容不显示乱码,可以先将密文转换为16进制 151 String hexStrResult = parseByte2HexStr(encrypt); 152 System.out.println("16进制的密文:" + hexStrResult); 153 154 //如果的到的是16进制密文,别忘了先转为2进制再解密 155 byte[] twoStrResult = parseHexStr2Byte(hexStrResult); 156 157 // 解密 158 byte[] decrypt = AesTest.decrypt(encrypt, password); 159 System.out.println("解密后的内容:" + new String(decrypt)); 160 } 161 }