工作中经常会接触到一些加密算法,比如说base64、MD5、DES、AES等等,那么这些算法到底有什么区别以及具体的应用场景是什么呢,下面就做个简要的梳理。
一、什么是加/解密,目的是什么?
所谓加密,就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为 “密文”。目的就是保护数据不被非法窃取、阅读。
所谓解密,也就是加密的逆过程,即将该密文信息转化为其原来数据的过程。
举个例子:小王想给他的妻子写一封信,如果在邮寄的过程中,被他人截获那么就显而易见的将信息泄露掉。相反如果小王根据一个密码本将信的内容加密,比如每一个汉字对应一个编码,那么即使被别人截获,因为没有密码本那么信息也不会泄露,小王的妻子拿到加密后的信件后,用密码本再一一翻译成可读的文本,这个过程就是解密。
二、什么是加/解密算法
加密/解密过程中,使用到的算法就是加密/解密算法。
三、加/解密算法的分类
根据加/解密过程是否可逆,算法可以分为可逆加密算法和不可逆加密算法。
可逆算法包括:DES、3DES、AES、RSA、DSA
不可逆加密算法包括:SHA-1、MD5
对于可逆加密,如果没有秘钥,任何人拿到了密文后通过对应的可逆算法都可以解密,这是不安全的。所以引入了秘钥,加密的时候加入了秘钥,接收方解密时需提供秘钥,这样不知道秘钥就无法解密。
根据加解密使用的秘钥是否相同,算法可以分为对称加密算法和非对称加密算法。
对称加解密使用的秘钥是一致的,非对称加解密使用的秘钥是不一致的。
四、不可逆算法
4.1 MD5加密算法
MD5 用的是哈希函数。严格来说,MD5不是一种加密算法而是摘要算法。无论是多长的输入,MD5 都会输出长度为 128bits 的一个串 (通常用 16 进制 表示为 32 个字符)。完整的md5一般是32位,国内常见的一种是动网的16位(也就是只取32位md5的中间16位),另外有一种是变化过的md5,特征是全是数字,长度可能是20位或者19。
它的典型应用是对一段信息产生信息摘要,以 防止被篡改。
防止被篡改的意思是,发送方用此算法对一段信息产生一个摘要串,接收方也用此算法产生一个摘要串,然后比较这两个摘要串的内容是否一致,如果不一致我们就认为此信息在传输的过程中可能发生了篡改。
那么有没有可能我修改了信息内容,修改后的内容产生的md5与修改之前是一致的呢?md5防止篡改的关键在于,它的碰撞算法以前一直没有找到,所谓碰撞算法,就是修改原来的文件,同时保持修改后的文件和原文件md5一致。
不过后来,我国山东大学的杨教授搞定了碰撞算法。所以md5作为防篡改,已经不可靠了。类似的,sha1的碰撞算法,最近也被攻克。
public static String getMd5(String source) throws NoSuchAlgorithmException {
//1.获取MessageDigest对象
MessageDigest digest = MessageDigest.getInstance("md5");
//2.执行加密操作
byte[] bytes = source.getBytes();
//在MD5算法这,得到的目标字节数组的特点:长度固定为16
byte[] targetBytes = digest.digest(bytes);
//3.声明字符数组
char [] characters = new char[]{
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
//4.遍历targetBytes
StringBuilder builder = new StringBuilder();
for (byte b : targetBytes) {
//5.取出b的高四位的值
//先把高四位通过右移操作拽到低四位
int high = (b >> 4) & 15;
//6.取出b的低四位的值
int low = b & 15;
//7.以high为下标从characters中取出对应的十六进制字符
char highChar = characters[high];
//8.以low为下标从characters中取出对应的十六进制字符
char lowChar = characters[low];
builder.append(highChar).append(lowChar);
}
return builder.toString();
}
4.2 SHA-1加密算法
SHA1 是和 MD5 一样流行的 消息摘要算法,然而 SHA1 比 MD5 的 安全性更强。对于长度小于 2 ^ 64 位的消息,SHA1 会产生一个 160 位(40个字符)的 消息摘要。基于 MD5、SHA1 的信息摘要特性以及 不可逆 (一般而言),可以被应用在检查 文件完整性 以及 数字签名 等场景。
public static String shaEncode(String inStr) throws Exception {
MessageDigest sha = null;
try {
sha = MessageDigest.getInstance("SHA");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
byte[] byteArray = inStr.getBytes("UTF-8");
byte[] md5Bytes = sha.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();
}
五、对称加密算法
5.1 DES算法
DES(Data Encryption Standard)是一种分组密码算法,明文按 64 位进行分组,密钥长 64 位,密钥事实上是 56 位参与 DES 运算(第8、16、24、32、40、48、56、64 位是校验位)分组后的明文组和 56 位的密钥按位替代或交换的方法形成密文组,之后按照顺序将密文组连在一起,各段数据之间互不影响。标准的DES密钥长度为64bit,即8个字符,超过8个字符则舍弃后面。比如:用abcdefgh与abcdefghi加密是一样的结果。又因为有校验位的存在,所以用12345678与13345678进行加密是一样的。
如果密钥长度不足,会以指定的填充方式( 比如PKCS7Padding )方式补足位
关于数据补位参考:https://www.cnblogs.com/Lawson/archive/2012/05/20/2510781.html
因此,破译 DES 加密算法实际上就是 搜索密钥的编码。对于56 位长度的密钥 来说,如果用穷举法来进行搜索的话,其运算次数为 2 ^ 56 次=非常大的一个数。
des原理描述
https://blog.csdn.net/qq_32445015/article/details/80184954
package com.inspur.incloudmanager.controller.util;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.util.Base64;
public class DESUtil {
/**
* 偏移变量,固定占8位字节
*/
private final static String IV_PARAMETER = "12345678";
/**
* 密钥算法
*/
private static final String ALGORITHM = "DES";
/**
* 加密/解密算法-工作模式-填充模式
*/
// private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
private static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
/**
* 默认编码
*/
private static final String CHARSET = "utf-8";
/**
* 生成key
*
* @param password
* @return
* @throws Exception
*/
private static Key generateKey(String password) throws Exception {
DESKeySpec dks = new DESKeySpec(password.getBytes(CHARSET));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
return keyFactory.generateSecret(dks);
}
/**
* DES加密字符串
*
* @param password 加密密码,长度不能够小于8位
* @param data 待加密字符串
* @return 加密后内容
*/
public static String encrypt(String password, String data) {
if (password== null || password.length() < 8