大多数加密都分为:对称加密、非对称加密、单向加密
在如今复杂的网络环境中单凭通过一个加密方式来确保数据安全是不科学的,一般都是混合加密。
在算力逐渐增强的情况下,没有什么加密算法是不能暴力破解的,只是时间问题,所以以后的加密算法会越来越复杂,密文会越来越长
对称加密:
加密和解密采用同一密钥(大部分时候用同一个。也可以是两个,但可以互相推导出,没啥意义)。它要求发送方与接收方在安全通信前,商定一个密钥。对称算法的安全性依赖于密钥,泄露密钥就意味着任何人都可以对他们发送或接收的消息解密。
优点:加解密算法可以公开、加解密速度快
缺点:每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一秘钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担;如何安全的在互联网传输密钥也是一个问题
场景:适合业务方少(每个业务方一个密钥管理起来也没什么),进行大数据量的加解密(效率高)
常见算法:(推荐AES加密、base64编码)
1)DES加密算法:由于长度是56位,已被破解,不再是一种安全的加密方式
2)3DES加密算法:相当于对每个数据块应用三次DES加密算法,是DES向AES过渡的加密算法
3)AES加密算法:长度256位,用于替代原先的DES,已广为全世界使用
4)base64编码:不是明文阅读的,都属于加密;所以base64编码转换也算一种对称加密
补充:
1、A和B需要交互的话,一个密钥即可。有时候是两个密钥(感觉没意义):A往B发消息用密钥1加工,B用密钥1解密;B往A发消息用密钥2加工,A用密钥2解密。
2、AES加密算法的加解密过程又有好几种模式,常用的有:CBC模式(需要提供初始化向量IV)、CTR模式(可自生成随机的初始化向量IV、效率高、推荐使用)
3、现在服务器普遍使用aes-256-gcm加密算法,AES256指加密算法,gcm指指的是该对称加密采用CTR模式,并带有GMAC消息认证码(防篡改)。这是组合用法。
感兴趣可以看 https://blog.csdn.net/liangjisheng/article/details/79627770
java实现:
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
/**
* AesGcm256加解密demo
* @author beigai
* @date 2021-02-23
*/
public class AesGcmUtils {
private static Logger log = LoggerFactory.getLogger(AesGcmUtils.class);
private static String gcm256algorithm = "AES/GCM/PKCS5Padding";
public static void main(String[] args) {
KeyGenerator generator = null;
try {
generator = KeyGenerator.getInstance("AES");
//初始化密钥生成器,AES要求密钥长度为128位、192位、256位
generator.init(256);
SecretKey secretKey = generator.generateKey();
String gcmSecretKey = Base64.encodeBase64String(secretKey.getEncoded());
System.out.println("生成密钥key: "+gcmSecretKey +"\n");
String toDoStr = "文本加密测试111";
System.out.println("明文文本:"+toDoStr);
String encryptResult = encryptByAesGcm(toDoStr,gcmSecretKey);
System.out.println("加密结果: "+encryptResult);
String decryptResult = decryptByAesGcm(encryptResult,gcmSecretKey);
System.out.println("解密结果: "+decryptResult +"\n");
} catch (NoSuchAlgorithmException e) {
log.error("密钥生成异常,error:", e);
}
}
public static String encryptByAesGcm(String content, String keyStr) {
try {
if (StringUtils.isEmpty(content) || StringUtils.isEmpty(keyStr)) {
throw new Exception("AESGCM256加密异常,检查文本或密钥");
}
SecretKey secretKey = new SecretKeySpec(Base64.decodeBase64(keyStr), "AES");
Cipher cipher = Cipher.getInstance(gcm256algorithm);
// 加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// 默认的12字节的随机重发IV
byte[] iv = cipher.getIV();
assert iv.length == 12;
byte[] encryptData = cipher.doFinal(content.getBytes());
// 默认的MAC消息认证码 16个字节
assert encryptData.length == content.getBytes().length + 16;
byte[] message = new byte[12 + content.getBytes().length + 16];
System.arraycopy(iv, 0, message, 0, 12);
System.arraycopy(encryptData, 0, message, 12, encryptData.length);
return Base64.encodeBase64String(message);
} catch (Exception e) {
log.error("AESGCM256加密文本处理失败,error:{}", e);
}
return null;
}
public static String decryptByAesGcm(String content, String keyStr) {
try {
if (StringUtils.isEmpty(content) || StringUtils.isEmpty(keyStr)) {
throw new Exception("AESGCM256解密异常,检查文本或密钥");
}
Cipher cipher = Cipher.getInstance(gcm256algorithm);
SecretKey key = new SecretKeySpec(Base64.decodeBase64(keyStr), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] message = Base64.decodeBase64(content);
if (message.length < 12 + 16) {
throw new IllegalArgumentException();
}
// 将 message从0前面12个字节 作为IV
GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
// 解密模式
cipher.init(Cipher.DECRYPT_MODE, key, params);
// 对message[12,]进行解密
byte[] decryptData = cipher.doFinal(message, 12, message.length - 12);
String decript = new String(decryptData);
return decript;
} catch (Exception e) {
log.error("AESGCM256解密文本处理失败,error:{}", e);
}
return null;
}
}
非对称加密:
公钥加密,私钥解密。(公钥加密的,只有私钥能解)
私钥签名,公钥验签。(私钥加密的,所有公钥都能解)
非对称加密的密钥是成对出现的,分为私钥和公钥。公钥从私钥提取出,一一对应。公钥加密,私钥可以解密。然后可以把你的public key分发给想给你传密文的用户,然后用户使用该public key加密过得密文,只有使用你的private key才能解密,也就是说,只要你自己保存好你的private key,就能确保,别人想给你发的密文不被破解,所以你不用担心别人的密钥被盗,没关系。
数字签名 是为了防止http内容被篡改。server先用Hash函数,生成信件的摘要(digest),使用私钥,对这个摘要加密,生成"数字签名"(signature)。client用server的公钥解密,得到信件的摘要。再对信件本身使用Hash函数,将得到的结果,与上一步得到的摘要进行对比。如果两者一致,就证明这封信未被修改过。
如果甲想给乙发一个安全的保密的数据,那么应该甲乙各自有一个私钥,甲先用乙的公钥加密这段数据,再用自己的私钥签名这段加密后的数据.最后再发给乙,这样确保了内容即不会被读取,也不会被篡改.
优点:安全性更高,公钥公开
缺点:计算复杂,效率低
场景:只适合对少量数据加解密
常见算法:
1)RSA加密算法:目前最优秀的公钥方案之一,可同时用于加密和数字签名
2)DSA加密算法:只能用于数字签名,所以比RSA快很多
3)ECC加密算法:目前加密强度最高的非对称加密算法
单向加密
也被称为hash加密算法,输入明文后由系统直接经过加密算法处理成秘文,这种加密后的数据是无法被解密的;只有重新输入相同明文,并经过同样的加密算法处理,才能得到相同的加密密文,比较是否相同。
优点:不可逆,易计算
缺点:可能存在散列冲突(hash碰撞秘文重复,但没关系,概率很小)
场景:防止密码泄露,判断数据完整性
常见算法:
1)MD5加密算法:被广泛使用的散列函数,碰撞几率大些,128位
2)SHA加密算法:有SHA1(已不安全)、SHA2(sha-256算法是sha-2里面的其中一个)两种,将明文转化为长度较短、位数固定的散列值
SHA2安全性最高,但也最耗时,256bit;被加密的数据没有太大的价值用md5即可
如何每次加密秘文都不一样?
主要应用在对称加密,防止有心人不断的重试破解加密方式,就像md5
前提:加解密的过程别人都无法看见
1、生成随机数,根据这个随机数加密,秘文中固定的位置加上这个随机数
2、解密的时候,从固定的位置取出这个随机数,解密即可