一、可逆加密算法

解释: 加密后, 密文可以反向解密得到密码原文.

1、对称加密

文件加密和解密使用相同的密钥,即加密密钥也可以用作解密密钥

1-加密.png
解释: 在对称加密算法中,数据发信方将明文和加密密钥一起经过特殊的加密算法处理后,使其变成复杂的加密密文发送出去,收信方收到密文后,若想解读出原文,则需要使用加密时用的密钥以及相同加密算法的逆算法对密文进行解密,才能使其回复成可读明文。在对称加密算法中,使用的密钥只有一个,收发双方都使用这个密钥,这就需要解密方事先知道加密密钥。

优点: 对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高。

缺点: 没有非对称加密安全.

用途: 一般用于保存用户手机号、身份证等敏感但能解密的信息。

常见的对称加密算法有: AES、DES、3DES、Blowfish、IDEA、RC4、RC5、RC6、HS256

2、非对称加密

两个密钥:公开密钥(publickey)和私有密钥,公有密钥加密,私有密钥解密

2-加密.png

解释: 同时生成两把密钥:私钥和公钥,私钥隐秘保存,公钥可以下发给信任客户端.

加密与解密:

  • ​ 私钥加密,持有公钥才可以解密
  • ​ 公钥加密,持有私钥才可解密

签名:

  • ​ 私钥签名, 持有公钥进行验证是否被篡改过.

优点:非对称加密与对称加密相比,其安全性更好;

缺点: 非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
用途: 一般用于签名和认证。私钥服务器保存, 用来加密, 公钥客户拿着用于对于令牌或者签名的解密或者校验使用.

常见的非对称加密算法有: RSA、DSA(数字签名用)、ECC(移动设备用)、RS256 (采用SHA-256 的 RSA 签名)

二、不可逆加密算法

解释: 一旦加密就不能反向解密得到密码原文.

种类: Hash加密算法, 散列算法, 摘要算法等

**用途:**一般用于效验下载文件正确性,一般在网站上下载文件都能见到;存储用户敏感信息,如密码、 卡号等不可解密的信息。

常见的不可逆加密算法有: MD5、SHA、HMAC、BCrypt

三、Base64编码

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一。Base64编码可用于在HTTP环境下传递较长的标识信息。采用Base64Base64编码解码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。注意:Base64只是一种编码方式,不算加密方法。

在线编码工具:

http://www.jsons.cn/img2base64/

四、密码加密的技术选型

1、MD5密码加密

//md5加密  DegestUtils:spring框架提供的工具类
String md5Str = DigestUtils.md5DigestAsHex("abc".getBytes());
System.out.println(md5Str);//900150983cd24fb0d6963f7d28e17f72

md5相同的密码每次加密都一样,不太安全

2、手动加密(md5+随机字符串)

  • 在md5的基础上手动加盐(salt)处理
/**
 * @Author :leaflei
 * @Version: 1.0
 * @Description : 加密方式测试
 */
@SpringBootTest
public class EncryptTest {

    /**
     * 测试MD5直接加密(不推荐使用,已被破解)
     */
    @Test
    public void testMd5() {
        for (int i = 0; i < 9; i++) {
            //明文密码
            String pwd = "123456";
            //加密
            String pwdEncrypt = DigestUtils.md5DigestAsHex(pwd.getBytes());
            System.out.println("加密后的密码:" + pwdEncrypt);
        }
    }

    /**
     * 测试MD5+盐(场景:常用于用户注册或新增用户存储用户的密码)
     */
    @Test
    public void testMd5SaltForRegister(){
        for (int i = 0; i < 10; i++) {
            //明文密码
            String pwd = "123456";
            //随机生成数字+字母组合(作为盐)
            String salt = RandomStringUtils.randomAlphanumeric(10);
            //拼接明文密码和盐
            String pwdNew = pwd + salt;
            //加密
            String pwdEncrypt = DigestUtils.md5DigestAsHex(pwdNew.getBytes());
            System.out.println("盐:" +salt +", 加密后:" + pwdEncrypt);
        }
    }

    /**
     * 测试MD5+盐(场景:常用于用户登录校验密码)
     */
    @Test
    public void testMd5SaltForLogin(){
        //明文密码
        String loginPwd = "123456";
        //使用的盐(用户在表中的盐)
        String dbSalt = "0t8OZkQQEQ";
        //使用盐加密后的密码
        String dbPwd = "550e7408789a65da21420102ac2da109";
        //拼接用户登录的密码+表中的盐
        String pwdNew = loginPwd + dbSalt;
        //进行MD5运算
        String pwdEncrypt = DigestUtils.md5DigestAsHex(pwdNew.getBytes());
        //将运算后的密码与表中密码做比较
        if(dbPwd.equals(pwdEncrypt)){
            System.out.println("登录成功");
        } else {
            System.out.println("密码错误登录失败");
        }
    }

}

这样同样的密码,加密多次值是不相同的,因为加入了随机字符串

3、BCrypt密码加密(推荐)

​ 在用户模块,对于用户密码的保护,通常都会进行加密。我们通常对密码进行加密,然后存放在数据库中,在用户进行登录的时候,将其输入的密码进行加密然后与数据库中存放的密文进行比较,以验证用户密码是否正确。 目前,MD5和BCrypt比较流行。相对来说,BCrypt比MD5更安全。

BCrypt 官网http://www.mindrot.org/projects/jBCrypt/

(1)我们从官网下载源码

(2)新建工程,将源码类BCrypt拷贝到工程

(3)新建测试类,main方法中编写代码,实现对密码的加密

(4)新建单元测试编写代码,实现对密码的校验。BCrypt不支持反运算,只支持密码校验。

/**
 * @Author :leaflei
 * @Version: 1.0
 * @Description : 加密方式测试
 */
@SpringBootTest
public class EncryptTest {
    /**
     * 测试bcrypt加密(常用于用户注册或新增用户对密码进行密码)
     */
    @Test
    public void testBCryptForRegister(){
        for (int i = 0; i < 10; i++) {
            //明文密码
            String pwd = "123456";
            //生成盐
            String salt =  BCrypt.gensalt();
            //明文密码+盐 实现加密
            String pwdEncrypt = BCrypt.hashpw(pwd,salt);
            System.out.println("盐:"+salt+",加密后: " +pwdEncrypt);
        }
    }

    /**
     * 测试BCrypt校验(常用于用户登录时判断密码是否正确)
     */
    @Test
    public void testBCryptForLogin(){
        //明文密码
        String pwd = "123456";
        //加密时使用的盐
        String pwdDB = "$2a$10$owzLG4fiZ4vmUSnmubaY9.FGcTuCDsRqvKNn3wiuYhQnyXNgO.96i";
        //把明文密码和盐作为参数传递,调用checkpw方法实现密码校验
        boolean result = BCrypt.checkpw(pwd, pwdDB);
        //判断结果
        if(result){
            System.out.println("登录成功");
        } else {
            System.out.println("密码错误登录失败");
        }
    }
}