数据加密的各种姿势

数据加密

数据按加密方式可分为对称加密和非对称加密和hash加密。

  • 对称加密:加解密密钥相同,假如有一把锁具,锁具在关闭(加密时)和开启(解密时)使用的是同一把钥匙(使用相同的密钥),则可以将该加密方式称为对称加密。常见的对称加密方式如:DES、3DES、Blowfish、IDEA、RC4、RC5、RC6 和 AES

数据加密的各种姿势

图片源自网络

  • 非对称加密:密钥分为公钥和私钥,如果后端返回的明文接口数据使用公钥进行加密脱敏,前端在解密时则需要私钥进行解密,使用公钥则无法对已加密数据进行解密。反之,如果后端接口使用私钥进行加密,前端在拿到接口数据密文后应先使用公钥解密。常见的非对称加密方式如:RSA、Diffie-Hellman、El Gamal、DSA

  • Hash加密

    数据明文加密后,无法解密出原数据,所以不适合数据传输的场景,但是可以用于登录密码验证,一般场景下,我们在新增用户时,会使用随机数作为用户的盐值(salt)+用户输入的密码拼接使用MD5算法将数据生成唯一的hash码,数据库存取密码的密文数据,上文知:hash加密无法反向解密,那么我们如何做到的登录呢?跳出思维的墙,在登录时,用户会输入账户名和密码,我们的登录逻辑中可以先使用用户名去数据库查询库中是否存在该用户信息(盐值、密文密码),如果不存在可按正常业务逻辑抛出业务异常,正常情况下,我们获取到用户信息,包括在新增用户时随机生成的盐值数据,下面的逻辑就是使用用户输入的密码+查到的数据库中的盐值进行hash加密,由于生成的密钥是唯一的,所以,如果用户输入的密码和注册时输入的一致(密码正确的情况),那么登录时生成的hashCode和注册时生成的hashCode是一致的,如果两个hash码一致,登录成功。

    常见的hash加密:MD5、HAVAL、SHA

            AdminUserEntity userDb = adminUserDb.getOne(Wrappers.<AdminUserEntity>lambdaQuery().eq(AdminUserEntity::getUsername, userName)
                    .eq(AdminUserEntity::getStatus, UserConstant.USER_STATUS.USER_ABLEDSTATE));
            if (Objects.isNull(userDb)) {
                //throw new Exception;
                // guava封装的Preconditions去判空只需一行代码,更加优雅
            }
            if (MD5Utils.getMD5(password + userDb.getSalt()).equals(userDb.getPassword())) {
                String token = buildToken(userDb);
                //其他业务逻辑
            }
    
    

对称加密 AES demo

package com.module.boots.api.de.utils;
 
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
 
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
 
import org.apache.tomcat.util.codec.binary.Base64;
 
import com.module.boots.exception.CommonRuntimeException;
 
/**
 * AES加密解密
 * @author:Ltx
 * @date:2020年12月6日
 */
public class AesUtils {
 
    private static final String KEY_ALGORITHM = "AES";
 
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";// 默认的加密算法
 
    /**
     * AES 加密操作
     * @author Ltx
     * @param content 待加密内容
     * @param password 加密密码
     * @return String 返回Base64转码后的加密数据
     */
    public static String encrypt(String content, String password) {
        try {
            // 创建密码器
            final Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            // 设置为UTF-8编码
            final byte[] byteContent = content.getBytes("utf-8");
            // 初始化为加密模式的密码器
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));
            // 加密
            final byte[] result = cipher.doFinal(byteContent);
            // 通过Base64转码返回
            return Base64.encodeBase64String(result);
 
        }
        catch (final Exception ex) {
            throw new CommonRuntimeException(ex.fillInStackTrace());
 
        }
    }
 
    /**
     * AES 解密操作
     * @author Ltx
     * @param content
     * @param password
     * @return String
     */
    public static String decrypt(String content, String password) {
        try {
            // 实例化
            final Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            // 使用密钥初始化,设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));
            // 执行操作
            final byte[] result = cipher.doFinal(Base64.decodeBase64(content));
            // 采用UTF-8编码转化为字符串
            return new String(result, "utf-8");
 
        }
        catch (final Exception ex) {
            throw new CommonRuntimeException(ex.fillInStackTrace());
        }
 
    }
 
    /**
     * 生成加密秘钥
     * @author Ltx
     * @param password 加密的密码
     * @return SecretKeySpec
     */
    private static SecretKeySpec getSecretKey(final String password) {
        // 返回生成指定算法密钥生成器的 KeyGenerator 对象
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(KEY_ALGORITHM);
            // AES 要求密钥长度为 128
            kg.init(128, new SecureRandom(password.getBytes()));
            // 生成一个密钥
            final SecretKey secretKey = kg.generateKey();
            // 转换为AES专用密钥
            return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
        }
        catch (final NoSuchAlgorithmException ex) {
            throw new CommonRuntimeException(ex.fillInStackTrace());
        }
    }
 
    public static void main(String[] args) {
        final String str = "V9JofCHn02eyXRiDb1VuseRSuOgEQftROwudMPWwMAO2Wk5K7aYZ4Vtm6xiTn5i5";
        System.out.println(decrypt(str, "xy934yrn9342u0ry4br8cn-9u2"));
    }
 
}

尚未完成,尽情期待~~~

上一篇:AES算法


下一篇:MySQL-事务机制