Bootstrap

Java 加解密


 

常见概念

1、单向、非单向(双向)加密算法

  • 单向加密算法:只能加密不能解密,可以从明文加密得到密文,但不能从密文解析得到明文,常见的比如 MD5、SHA、HMAC。
  • 非单向(双向)加密算法:常见的比如 BASE64、对称加密算法、非对称加密算法、数字签名算法、数字证书。
     

2、对称、非对称加密算法 都属于非单向(双向)加密

  • 对称加密:加解密使用同一个秘钥,常见的比如 DES、AES。
  • 非对称加密:加解密使用不同的秘钥,常用于电商订单付款、银行相关业务,常见的比如 RSA。
     

3、数字签名、数字证书

  • 数字签名:用于对数据完整性、收发双方进行验证,数字签名是非对称密钥加密技术与数字摘要技术的应用,一套数字签名通常定义两种互补的运算,一个用于发送方对数据进行摘要作为签名,另一个用于接收方进行验证,常见的比如 RSA、DSA。
  • 数字证书:在互联网通讯中给通讯各方颁发一个标识身份信息的数字认证,用它来识别对方身份,常见的颁发机构比如CA中心。
     

古典加密:通过移位、替换等方式进行加密

 

Base64

对内容(通常是二进制数据)进行编码,严格来说属于编码方式。

常见使用场景

  • 图片、邮件的编码传输
  • url编码,注意这里的url编码并不是将空格、汉字之类的特殊字符编码为%xx
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.Base64;

@Slf4j
public class Base64Test {

    @Test
    public void testBase64() {
        String str = "xxx";

        String encodeStr = Base64.getEncoder().encodeToString(str.getBytes());
        log.info("Base64编码后的数据:{}", encodeStr);

        byte[] decodeContent = Base64.getDecoder().decode(encodeStr);
        String decodeStr = new String(decodeContent);
        log.info("Base64解码后的数据:{}", decodeStr);
    }

}

java.util.Base64 提供了多种编解码器

  • Base64.getEncoder/Decoder() 基础编解码器
  • Base64.getUrlEncoder/Decoder() url编解码器
  • Base64.getMimeEncoder/Decoder() 邮件编解码器

 

MD5

Message Digest algorithm 信息摘要算法,用于确保数据传输的完整一致、验证信息完整性,常用于文件校验,常见的实现算法有MD5、SHA。

MD算法特点:计算得到的MD值长度固定,不管数据多大,摘要后都能生成唯一的MD值,对原数据进行任何改动,哪怕只修改个字节,所得到的MD值都会发生变化,伪造数据(找到具有相同MD值的数据)非常困难。

MD常见应用场景:密码加密、文件校验,MD算法有多个版本的实现,最常用的是MD5

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.util.DigestUtils;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

@Slf4j
public class MD5Test {

    @Test
    public void testJdkMd5() throws NoSuchAlgorithmException {
        String str = "xxx";
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(str.getBytes());
        BigInteger bigInteger = new BigInteger(md.digest());
        String md5Str = bigInteger.toString();
        log.info("加密前的数据:{}  加密后的数据:{}  长度:{}", str, md5Str, md5Str.length());
    }

    @Test
    public void testSpringMd5() {
        String str = "xxx";
        String md5Str = DigestUtils.md5DigestAsHex(str.getBytes());
        log.info("加密前的数据:{}  加密后的数据:{}  长度:{}", str, md5Str, md5Str.length());
    }

}

在进行摘要之前,可以在原串基础上拼接字符串(加salt 盐)。

 

SHA

Secure Hash Algorithm 安全散列(哈希)算法,该算法的思想是接收一段明文(也称为输入码、预映射、信息),然后以一种不可逆的方式将它转换成一段长度较短、位数固定的密文(也称为输出序列、散列值、信息摘要、信息认证代码)。散列函数值相当于明文的“指纹”、“摘要”,可以视为对明文的数字签名。

SHA和MD都是信息摘要算法,彼此很相似,主要区别在于SHA比MD摘要位数要长得多,执行速度、效率比MD低,破解难度比MD更大。由于MD的设计,易受密码分析的攻击,SHA显得不易受这样的攻击,更安全。

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

@Slf4j
public class SHATest {

    @Test
    public void testSHA() throws NoSuchAlgorithmException {
        String str = "xxx";
        MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        byte[] bytes = sha256.digest(str.getBytes(StandardCharsets.UTF_8));
        StringBuilder hexStringBuilder = new StringBuilder();
        for (byte b : bytes) {
            //将每个字节转成十六进制字符串:byte最高位是符号位,通过和0xff进行与操作,转换为正整数
            String hexString = Integer.toHexString(b & 0xff);
            hexStringBuilder.append(hexString.length() == 1 ? "0" + hexString : hexString);
        }
        String encodeStr = hexStringBuilder.toString();
        log.info("明文:{},SHA加密得到的密文:{}", str, encodeStr);
    }

}

 

DES

Data Encryption Standard 数据加密标准算法,是一种对称加密算法,加、解密使用同一个秘钥,要求密钥是长度至少为8的字符串,且密钥长度必须是8的倍数。DES使用56位密钥,容易被破解,只能使用于一些保密性要求不高的场景。DES近些年来使用越来越少,逐渐被AES代替。

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.SecureRandom;

@Slf4j
public class DESTest {

    @Test
    public void testDES() throws Exception {
        String str = "xxx";
        //秘钥,长度至少为8,且要是8的倍数
        String password = "qwer1234";

        DESKeySpec desKeySpec = new DESKeySpec(password.getBytes());
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        Cipher cipher = Cipher.getInstance("DES");
        SecureRandom secureRandom = new SecureRandom();

        //加密
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, secureRandom);
        byte[] encryptBytes = cipher.doFinal(str.getBytes());
        log.info("密文:{}", new String(encryptBytes));

        //解密
        cipher.init(Cipher.DECRYPT_MODE, secretKey, secureRandom);
        byte[] decryptBytes = cipher.doFinal(encryptBytes);
        log.info("明文:{}", new String(decryptBytes));
    }

}

 

AES

Advanced Encryption Standard 高级加密标准,是目前最流行的一种对称加密算法,支持128、192、256位的密钥,使用128位分组来加解密。

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

@Slf4j
public class AESTest {

    @Test
    public void testAES() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
        secureRandom.setSeed("AES/CBC/PKCS5Padding".getBytes());
        //秘钥长度,可以是128、192、256
        keyGenerator.init(128, secureRandom);

        SecretKey originalKey = keyGenerator.generateKey();
        SecretKey secretKey = new SecretKeySpec(originalKey.getEncoded(), "AES");
        Cipher cipher = Cipher.getInstance("AES");

        //加密
        String text = "xxx";
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedBytes = cipher.doFinal(text.getBytes(StandardCharsets.UTF_8));
        String encryptText = Base64.getEncoder().encodeToString(encryptedBytes);
        log.info("加密得到的密文:{}", encryptText);

        //解密
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        encryptedBytes = Base64.getDecoder().decode(encryptText);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        String decryptedText = new String(decryptedBytes);
        log.info("解密得到的明文:{}", decryptedText);
    }

}

 

RSA

RSA是非对称加密算法的典型代表,加解密使用不同的密钥,密钥分为公钥(public key)、私钥(private key)2种,公钥公开 用于对明文进行加密,私钥保密 用于对密文进行解析获得明文。未泄露私钥,加密的数据就是安全的;密钥足够长(一般要求1024位及以上),加密的数据就难以被破解。此算法由 Rivest、Shamir、Adleman 三人设计,算法名称取的三个姓名的首字母。

;