java/web工具类之MD5、AES、Base64算法数据加密
对加密解先理解:
比如:甲乙双方要通信,中间的连接可能被人窃听甚至篡改。解决办法就是把传输的内容进行加密,用密文去传输,这样即使被监听也没办法知道信息的具体内容。
加密时,甲乙双方可以约定一个密码A,甲用A加密,乙用A解密,这就是对称加密。
对称加密存在一个问题是:密钥怎么传递给对方?
貌似没解,于是就出现了非对称加密,非对称加密时有两个密钥,就是公钥和私钥。用公钥加密的只能用私钥解密,反之用私钥加密的则只能用公钥解密。这样在流程上有点儿变化了。
原先在对称加密中,密钥没法传递,现在好了,密钥不用传递,因为公钥是公开的,谁都可以拿到。
但是还漏掉了一个问题:虽然篡改不了问题,那我总可以冒名发数据吧?
因为乙的公钥是公开的,那我就可以拿着乙的公钥给乙想发什么就发什么?
乙怎么知道数据甲发过来的呢?答案是用数字签名来验证。
总结:
加密技术通常分为两大类:“对称式"和"非对称式”。
非对称加密:包括RSA DSA RCC,非对称加密是相比对称加密而言的
对称加密:包括AES,DES,3DES。
其次,对应于安全问题的解决办法如下:
数据完整性问题:数据摘要验证
数据保密性问题:对称加密&非对称加密
身份验证问题:数字签名
1.Base64编码加密和解密
将数据转换为不便于识别的数据算是一种最简单的加密了,比如Base64编码。
Base64:属于对称加密算法
Base64是一种能将任意Binary资料用64种字元组合成字串的方法,而这个Binary资料和字串资料彼此之间是可以互相转换的,十分方便。
用处:
Base64这种编码是可逆的,也就是可以加密也可以解密。一般在web开发中常常用来加密图片路径,这种不是很重要又不想被人盗走的,就用这种简单加密。
JDK1.8以下
使用Java8以下的小伙伴,要使用Base64的编码与解码,就可以使用JDK里sun.misc套件下的BASE64Encoder和BASE64Decoder这两个类别,
用法如下:
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public static void main(String[] args) throws IOException{
//java 8以下 import sun.misc.BASE64Decoder;
String text = "这是一段明文";
byte[] bytes = text.getBytes();
String encodedStr = encode(bytes);
byte[] decodedBytes = decode(encodedStr);
System.out.println("原文字:"+text);
System.out.println("加密字段:"+encodedStr);
System.out.println("解密字段:"+new String(decodedBytes));
}
public static String encode(byte[] bytes){
return new BASE64Encoder().encode(bytes);
}
public static byte[] decode(String encodeStr) throws IOException{
return new BASE64Decoder().decodeBuffer(encodeStr);
}
结果:
JDK1.8或以上
在目前的Java8中,已经内置Base64的实现类,可以通过java.util.Base64工具类来使用。
非常方便。
用法如下:
public static void main(String[] args) throws IOException{
//Java 8 import java.util.Base64;
final Base64.Decoder decoder = Base64.getDecoder();
final Base64.Encoder encoder = Base64.getEncoder();
String text = "这是一段明文";
System.out.println("原文字:"+text);
final byte[] textByte = text.getBytes("UTF-8");
//编码
String encodedText = encoder.encodeToString(textByte);
System.out.println("加密字段:"+encodedText);
//解码
String jiemi = new String(decoder.decode(encodedText), "UTF-8");
System.out.println("解密字段:"+jiemi);
效果:
实际测试编码与解码速度的话,Java 8提供的Base64,要比sun.mis c套件提供的还要快至少11倍,
所以:
在Java上若要使用Base64,推荐Java8的java.util提供的Base64!
2.AES算法加密和解密
AES:也属于对称加密算法
AES加密的明文分组的长度为128位即16字节,密钥长度可以为16,24或者32字节(128,192,256位)。根据密钥的长度,算法被称为AES-128,AES-192或者AE-256。
用法如下:
package com.zout.crud.utils;
import org.springframework.util.StringUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
*
*@class_name:AesUtil
*@comments:AES加密工具类
*@author:邹涛/Zoutao
*@createtime:2019年3月3日
*/
public class AesUtil {
/**
* AES加密
*
* @param content
* @param key
* @param iv
* @return
*/
public static String encrypt(String content, String key, String iv) {
if (StringUtils.isEmpty(key)) {
return null;
}
if (key.length() != 16) {
return null;
}
String encryptText = "";
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
byte[] encrypted = cipher.doFinal(content.getBytes());
encryptText = parseByte2HexStr(encrypted);
} catch (IllegalBlockSizeException e) {
} catch (BadPaddingException e) {
} catch (InvalidKeyException e) {
} catch (InvalidAlgorithmParameterException e) {
} catch (NoSuchAlgorithmException e) {
} catch (NoSuchPaddingException e) {
}
return encryptText;
}
/**
* AES解密
*
* @param content
* @param key
* @param iv
* @return
*/
public static String decrypt(String content, String key, String iv) {
if (StringUtils.isEmpty(key)) {
return "AES加密KEY为空!";
}
if (key.length() != 16) {
return "AES加密KEY长度必须16位!";
}
String decryptText = "";
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
byte[] byteContent = parseHexStr2Byte(content);
byte[] original = cipher.doFinal(byteContent);
decryptText = new String(original);
} catch (NoSuchAlgorithmException e) {
} catch (NoSuchPaddingException e) {
} catch (InvalidAlgorithmParameterException e) {
} catch (InvalidKeyException e) {
} catch (BadPaddingException e) {
} catch (IllegalBlockSizeException e) {
}
return decryptText;
}
/**
* 将二进制转换成16进制
*
* @param buf
* @return sb
*/
public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 将16进制转换为二进制
*
* @param hexStr
* @return result
*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1) {
return null;
}
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
public static void main(String[] args) {
String key = "AkxfGVoMiKDxUiJM";
String iv = "1841611841611010";
String content = "root";
String str = encrypt(content, key, iv);
System.out.println("源数据:"+content);
System.out.println("AES加密:"+str);
System.out.println("AES解密:"+decrypt(str, key, iv));
}
}
效果:
MD5加密
MD5全称为信息-摘要算法(哈希算法),是为计算机安全领域的散列函数,用于确保消息的完整性。另外摘要算法还有SHA1,具体请度娘。
MD5是一种单向加密,它的加密不可逆,它将任意长度的字符串,经过算法计算后生成固定长度的数据,一般为16位表示。
MD5算法,是不可逆的,则属于内容摘要。
用法如下:
package com.zout.utils;
import java.security.MessageDigest;
/**
*
*@class_name:MD5andKL
*@comments:使用MessageDigest对字符串进行MD5算法的步骤:
*先将字符串转换成字节数组,在进行MD5算法,最后返回的也是一个字节数组,
*要我们自己转成32位的字符串或不转。
*@author:邹涛/Zoutao
*@createtime:2019年3月3日
*/
public class MD5andKL {
// MD5加码。32位
public static String MD5(String inStr) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
// 可逆的加密算法
public static String KL(String inStr) {
// String s = new String(inStr);
char[] a = inStr.toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char) (a[i] ^ 't');
}
String s = new String(a);
return s;
}
// 加密后解密
public static String JM(String inStr) {
char[] a = inStr.toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char) (a[i] ^ 't');
}
String k = new String(a);
return k;
}
// 测试主函数
public static void main(String args[]) {
String s = new String("123456");
System.out.println("原始:" + s);
System.out.println("MD5后:" + MD5(s));
System.out.println("MD5后再加密:" + KL(MD5(s)));
System.out.println("解密为MD5后的:" + JM(KL(MD5(s))));
}
}
效果:
在本工具类中,首先明文采用MD5加密,又加了一层新的加密KL,是可逆的。但是MD5不可逆。
不想要可以直接去掉KL。
4.项目应用总结:
- 加密算法是可逆的,用来对敏感数据进行保护。散列算法(签名算法、哈希算法)是不可逆的,主要用于身份验证。
- 对称加密算法使用同一个密匙加密和解密,速度快,适合给大量数据加密。对称加密客户端和服务端使用同一个密匙,存在被抓包破解的风险。
- 非对称加密算法使用公钥加密,私钥解密,私钥签名,公钥验签。安全性比对称加密高,但速度较慢。非对称加密使用两个密匙,服务端和客户端密匙不一样,私钥放在服务端,黑客一般是拿不到的,安全性高。
- Base64不是安全领域下的加解密算法,只是一个编码算法,通常用于把二进制数据编码为可写的字符形式的数据,特别适合在http,mime协议下的网络快速传输数据。UTF-8和GBK中文的Base64编码结果是不同的。采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到,但这种方式很初级,很简单。Base64可以对图片文件进行编码传输。
- MD5标准密钥长度128位(128位是指二进制位。二进制太长,所以一般都改写成16进制,每一位16进制数可以代替4位二进制数,所以128位二进制数写成16进制就变成了128/4=32位。16位加密就是从32位MD5散列中把中间16位提取出来);sha1标准密钥长度160位(比MD5摘要长32位),Base64转换后的字符串理论上将要比原来的长1/3。
- MD5可以用来加密用户密码,AES可以用来加密一些可翻转的数据,base64可以用来加密图片文件数据。
参考文章:
https://www.cnblogs.com/huqiaoblog/p/7519600.html?utm_source=debugrun&utm_medium=referral
https://www.cnblogs.com/sunxuchu/p/5483956.html
加密算法这一块,不需要深入研究,只需要拿来用即可。直接复制代码即可使用。