对称加密、DES加解密、AES加解密、Base64加解密

为什么要学习加密与解密?

在笔试或面试中,经常会问到对称加密算法和非对称加密算法区别,哪些方式属于对称加密,哪些属于非对称加密,哪些地方用到了加密。
下面罗列出几种使用加密解密的场景~

  1. 系统中前后端交互的敏感字符加密,例如身份证号码,需要经过加密后传输
  2. 数据库中重要字段加密处理,例如银行账号,存入数据库的是密文,可依赖于Java加密或者数据库加密
  3. 对接SDK加密,按照SDK的要求进行加密,例如:先RSA后Base64等
  4. 对接渠道信息,例如对接宁波海关,文档要求,需要对数据生成摘要和签名等等

常见的加密解密方式

  1. 对称加密:
    DES:Data Encryption Standard 标准数据加密
    AES:Advancee Encryption Standard
  2. Base64算法加密
  3. 非对称加密算法:
    RSA:是目前最有影响力的公钥加密算法
    ECC:它比其他的方法使用更小的密钥提供相当的或更高等级的安全级别
  4. MD5算法加密
  5. SHA1算法
  6. HMAC算法

详解加密方式

对称加密

在这里插入图片描述
对称加密
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。
示例
我们现在有一个原文3要发送给B
设置密钥为108, 3 * 108 = 324, 将324作为密文发送给B
B拿到密文324后, 使用324/108 = 3 得到原文

常见加密算法

  1. DES : Data Encryption
    Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。
  2. AES : Advanced Encryption Standard, 高级加密标准
    .在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。

特点

  1. 加密速度快, 可以加密大文件
  2. 密文可逆, 一旦密钥文件泄漏, 就会导致数据暴露
  3. 加密后编码表找不到对应字符, 出现乱码
  4. 一般结合Base64使用
DES: 标准数据加密

DES是一个分组加密算法,典型的DES以64位为分组对数据加密,加密和解密用的是同一个算法。

入门Demo

package com.example.password_discipline.DesAes;

import com.sun.org.apache.xml.internal.security.utils.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;


public class DesAesDemo {
	public static void main(String[] args) throws Exception{
		// 原文
		String input = "小郑";
		// des加密串,必须是8位
		String key = "01234567";
		// 算法
		String algorithm = "DES";

		String transformation = "DES";
		String encryptData = DesAesDemo.encryptDesc(input, key, algorithm, transformation);
		System.out.println("加密后的字符串:" + encryptData);
		String decryptDesc = DesAesDemo.decryptDesc(encryptData, key, algorithm, transformation);
		System.out.println("解密后的字符串:" + decryptDesc);
	}

	/**
	 * 加密
	 * @param data
	 * @param key
	 * @param algorithm
	 * @param transformation
	 * @return
	 * @throws Exception
	 */
	public static String encryptDesc(String data, String key, String algorithm, String transformation) throws Exception{
		Cipher cipher = Cipher.getInstance(transformation);
		SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
		// 对加密进行初始化
		// 1、表示模式,有加密模式和解密模式
		// 2、表示密钥规则
		cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
		// 进行加密
		byte[] bytes = cipher.doFinal(data.getBytes());
		// 打印字节输出
		return Base64.encode(bytes);
	}

	/**
	 * 解密
	 * @param data
	 * @param key
	 * @param algorithm
	 * @param transformation
	 * @return
	 * @throws Exception
	 */
	public static String decryptDesc(String data, String key, String algorithm, String transformation) throws Exception{
		Cipher cipher = Cipher.getInstance(transformation);
		// 密钥规则
		SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
		cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
		byte[] bytes = cipher.doFinal(Base64.decode(data));
		// 打印输出
		return new String(bytes);
	}

}

在这里插入图片描述
【注意】
1、密钥Key必须是8个字节,否则会报错
2、DES加密后是乱码,因此经常搭配Base64进行转码
原因:对应的字节出现负数,但负数,没有出现在 ascii 码表里面,所以出现乱码

在这里插入图片描述
在这里插入图片描述

Base64加密

Base64是网络上最常见的用于传输8Bit字节码的可读性编码算法之一
可读性编码算法不是为了保护数据的安全性,而是为了可读性
可读性编码不改变信息内容,只改变信息内容的表现形式
所谓Base64,即是说在编码过程中使用了64种字符:大写A到Z、小写a到z、数字0到9、“+”和“/”

算法原理

base64 是 3个字节为一组,一个字节 8位,一共 就是24位 ,然后,把3个字节转成4组,每组6位,
3 * 8 = 4 * 6 = 24 ,每组6位,缺少的2位,会在高位进行补0 ,这样做的好处在于 ,base取的是后面6位,去掉高2位 ,那么base64的取值就可以控制在0-63位了,所以就叫base64,111 111 = 32 + 16 + 8 + 4 + 2 + 1 =

base64 构成原则

① 小写 a - z = 26个字母
② 大写 A - Z = 26个字母
③ 数字 0 - 9 = 10 个数字
④ + / = 2个符号

大家可能发现一个问题,咱们的base64有个 = 号,但是在映射表里面没有发现 = 号 , 这个地方需要注意,等号非常特殊,因为base64是三个字节一组 ,如果当我们的位数不够的时候,会使用等号来补齐
在这里插入图片描述
入门Demo


import com.sun.org.apache.xml.internal.security.utils.Base64;

public class Base64Demo {
	public static void main(String[] args) {
		System.out.println(Base64.encode("1".getBytes()));
		System.out.println(Base64.encode("ZD".getBytes()));
		System.out.println(Base64.encode("郑".getBytes()));
	}
}

Base64工具类

package com.example.password_discipline.base64;

import java.io.ByteArrayOutputStream;

/**
 * base64 format encoding & decoding
 */
public class Base64 {

	private static char[] base64EncodeChars = new char[] { 'A', 'B', 'C', 'D',
			'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
			'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
			'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
			'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
			'4', '5', '6', '7', '8', '9', '+', '/' };

	private static byte[] base64DecodeChars = new byte[] { -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59,
			60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
			10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1,
			-1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
			38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1,
			-1, -1 };

	private Base64(){
	}

	public static String encode(byte[] data){
		StringBuffer sb = new StringBuffer();
		int len = data.length;
		int i = 0;
		int b1, b2, b3;

		while (i < len) {
			b1 = data[i++] & 0xff;
			if (i == len) {
				sb.append(base64EncodeChars[b1 >>> 2]);
				sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
				sb.append("==");
				break;
			}
			b2 = data[i++] & 0xff;
			if (i == len) {
				sb.append(base64EncodeChars[b1 >>> 2]);
				sb.append(base64EncodeChars[((b1 & 0x03) << 4)
						| ((b2 & 0xf0) >>> 4)]);
				sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
				sb.append("=");
				break;
			}
			b3 = data[i++] & 0xff;
			sb.append(base64EncodeChars[b1 >>> 2]);
			sb.append(base64EncodeChars[((b1 & 0x03) << 4)
					| ((b2 & 0xf0) >>> 4)]);
			sb.append(base64EncodeChars[((b2 & 0x0f) << 2)
					| ((b3 & 0xc0) >>> 6)]);
			sb.append(base64EncodeChars[b3 & 0x3f]);
		}
		return sb.toString();
	}

	public static byte[] decode(String str){
		byte[] data = str.getBytes();
		int len = data.length;
		ByteArrayOutputStream buf = new ByteArrayOutputStream(len);
		int i = 0;
		int b1, b2, b3, b4;

		while (i < len) {

			/* b1 */
			do {
				b1 = base64DecodeChars[data[i++]];
			} while (i < len && b1 == -1);
			if (b1 == -1) {
				break;
			}

			/* b2 */
			do {
				b2 = base64DecodeChars[data[i++]];
			} while (i < len && b2 == -1);
			if (b2 == -1) {
				break;
			}
			buf.write(((b1 << 2) | ((b2 & 0x30) >>> 4)));

			/* b3 */
			do {
				b3 = data[i++];
				if (b3 == 61) {
					return buf.toByteArray();
				}
				b3 = base64DecodeChars[b3];
			} while (i < len && b3 == -1);
			if (b3 == -1) {
				break;
			}
			buf.write((((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));

			/* b4 */
			do {
				b4 = data[i++];
				if (b4 == 61) {
					return buf.toByteArray();
				}
				b4 = base64DecodeChars[b4];
			} while (i < len && b4 == -1);
			if (b4 == -1) {
				break;
			}
			buf.write((((b3 & 0x03) << 6) | b4));
		}
		return buf.toByteArray();
	}

	public static void main(String[] args) {
		System.out.println(Base64.encode("1".getBytes()));
		System.out.println(Base64.encode("ZD".getBytes()));
	}
}

AES: 高级数据加密

AES 加密算法是密码学中的 高级加密标准,该加密算法采用 对称分组密码体制,
密钥长度的最少支持为 128 位、 192 位、256 位,分组长度 128 位,
算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的 区块加密标准。
AES 本身就是为了取代 DES 的,AES 具有更好的 安全性、效率 和 灵活性。

入门Demo
AES 加密解密和 DES 加密解密代码一样,只需要修改加密算法就行,拷贝 ESC 代码

package com.atguigu.desaes;
import com.sun.org.apache.xml.internal.security.utils.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class AesDemo {
    // DES加密算法,key的大小必须是8个字节

    public static void main(String[] args) throws Exception {
        String input ="硅谷";
        // AES加密算法,比较高级,所以key的大小必须是16个字节
        String key = "1234567812345678";

        String transformation = "AES"; // 9PQXVUIhaaQ=
        // 指定获取密钥的算法
        String algorithm = "AES";
        // 先测试加密,然后在测试解密
        String encryptDES = encryptDES(input, key, transformation, algorithm);
        System.out.println("加密:" + encryptDES);
        String s = dncryptDES(encryptDES, key, transformation, algorithm);
        System.out.println("解密:" + s);

    }

    /**
     * 使用DES加密数据
     *
     * @param input          : 原文
     * @param key            : 密钥(DES,密钥的长度必须是8个字节)
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @return : 密文
     * @throws Exception
     */
    private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // 获取加密对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 创建加密规则
        // 第一个参数key的字节
        // 第二个参数表示加密算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // ENCRYPT_MODE:加密模式
        // DECRYPT_MODE: 解密模式
        // 初始化加密模式和算法
        cipher.init(Cipher.ENCRYPT_MODE,sks);
        // 加密
        byte[] bytes = cipher.doFinal(input.getBytes());

        // 输出加密后的数据
        String encode = Base64.encode(bytes);

        return encode;
    }

    /**
     * 使用DES解密
     *
     * @param input          : 密文
     * @param key            : 密钥
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @throws Exception
     * @return: 原文
     */
    private static String dncryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // 1,获取Cipher对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定密钥规则
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        cipher.init(Cipher.DECRYPT_MODE, sks);
        // 3. 解密
        byte[] bytes = cipher.doFinal(Base64.decode(input));

        return new String(bytes);
    }
}

运行程序:AES 加密的密钥key , 需要传入16个字节
在这里插入图片描述
再运行程序
在这里插入图片描述

加密模式

加密模式:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html

ECB
ECB : Electronic codebook, 电子密码本. 需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密
在这里插入图片描述

  • 优点 : 可以并行处理数据
  • 缺点 : 同样的原文生成同样的密文, 不能很好的保护数据
  • 同时加密,原文是一样的,加密出来的密文也是一样的

CBC
CBC : Cipher-block chaining, 密码块链接. 每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块
在这里插入图片描述

  • 优点 : 同样的原文生成的密文不一样
  • 缺点 : 串行处理数据.

填充模式

当需要按块处理的数据, 数据长度不符合块处理需求时, 按照一定的方法填充满块长的规则

NoPadding

  • 不填充.
  • 在DES加密算法下, 要求原文长度必须是8byte的整数倍
  • 在AES加密算法下, 要求原文长度必须是16byte的整数倍

PKCS5Padding

  • 数据块的大小为8位, 不够就补足

Tips

  • 默认情况下, 加密模式和填充模式为 : ECB/PKCS5Padding
  • 如果使用CBC模式, 在初始化Cipher对象时, 需要增加参数, 初始化向量IV : IvParameterSpec iv = new
    IvParameterSpec(key.getBytes());

加密模式和填充模式

AES/CBC/NoPadding (128)
AES/CBC/PKCS5Padding (128)
AES/ECB/NoPadding (128)
AES/ECB/PKCS5Padding (128)
DES/CBC/NoPadding (56)
DES/CBC/PKCS5Padding (56)
DES/ECB/NoPadding (56)
DES/ECB/PKCS5Padding (56)
DESede/CBC/NoPadding (168)
DESede/CBC/PKCS5Padding (168)
DESede/ECB/NoPadding (168)
DESede/ECB/PKCS5Padding (168)
RSA/ECB/PKCS1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)

加密模式和填充模式例子

package com.atguigu.desaes;

import com.sun.org.apache.xml.internal.security.utils.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DesDemo {
    // DES加密算法,key的大小必须是8个字节

    public static void main(String[] args) throws Exception {
        String input ="硅谷";
        // DES加密算法,key的大小必须是8个字节
        String key = "12345678";
        // 指定获取Cipher的算法,如果没有指定加密模式和填充模式,ECB/PKCS5Padding就是默认值
        //     String transformation = "DES"; // 9PQXVUIhaaQ=
        //String transformation = "DES/ECB/PKCS5Padding"; // 9PQXVUIhaaQ=
        // CBC模式,必须指定初始向量,初始向量中密钥的长度必须是8个字节
        //String transformation = "DES/CBC/PKCS5Padding"; // 9PQXVUIhaaQ=
        // NoPadding模式,原文的长度必须是8个字节的整倍数 ,所以必须把 硅谷改成硅谷12
        String transformation = "DES/CBC/NoPadding"; // 9PQXVUIhaaQ=
        // 指定获取密钥的算法
        String algorithm = "DES";
        String encryptDES = encryptDES(input, key, transformation, algorithm);
        System.out.println("加密:" + encryptDES);
//        String s = dncryptDES(encryptDES, key, transformation, algorithm);
//        System.out.println("解密:" + s);

    }

    /**
     * 使用DES加密数据
     *
     * @param input          : 原文
     * @param key            : 密钥(DES,密钥的长度必须是8个字节)
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @return : 密文
     * @throws Exception
     */
    private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // 获取加密对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 创建加密规则
        // 第一个参数key的字节
        // 第二个参数表示加密算法
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // ENCRYPT_MODE:加密模式
        // DECRYPT_MODE: 解密模式
         // 初始向量,参数表示跟谁进行异或,初始向量的长度必须是8位
//        IvParameterSpec iv = new IvParameterSpec(key.getBytes());
         // 初始化加密模式和算法
        cipher.init(Cipher.ENCRYPT_MODE,sks);
        // 加密
        byte[] bytes = cipher.doFinal(input.getBytes());

        // 输出加密后的数据
        String encode = Base64.encode(bytes);

        return encode;
    }

    /**
     * 使用DES解密
     *
     * @param input          : 密文
     * @param key            : 密钥
     * @param transformation : 获取Cipher对象的算法
     * @param algorithm      : 获取密钥的算法
     * @throws Exception
     * @return: 原文
     */
    private static String dncryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // 1,获取Cipher对象
        Cipher cipher = Cipher.getInstance(transformation);
        // 指定密钥规则
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
//        IvParameterSpec iv = new IvParameterSpec(key.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, sks);
        // 3. 解密
        byte[] bytes = cipher.doFinal(Base64.decode(input));

        return new String(bytes);
    }
}

运行程序:
在这里插入图片描述
修改成 CBC 加密 模式

 String transformation = "DES/CBC/PKCS5Padding";

运行 ,报错,需要添加一个参数
在这里插入图片描述
修改加密代码:
在这里插入图片描述
运行程序
在这里插入图片描述
修改填充模式

String transformation = "DES/CBC/NoPadding";

运行报错 NoPadding 这种填充模式 原文必须是8个字节的整倍数
在这里插入图片描述
修改运行
在这里插入图片描述
在测试 AES 的时候需要注意,key需要16个字节,加密向量也需要16个字节 ,其他方式跟 DES 一样

推荐同系列文章

keytool openssl : https://blog.csdn.net/xiaozhegaa/article/details/109602118
密码学 ~ 数字签名: https://blog.csdn.net/xiaozhegaa/article/details/109601966
密码学 ~ 非对称加密 RSA ECC: https://blog.csdn.net/xiaozhegaa/article/details/109601632
密码学 ~ 消息摘要: https://blog.csdn.net/xiaozhegaa/article/details/109601148
对称加密、DES加解密、AES加解密、Base64加解密: https://blog.csdn.net/xiaozhegaa/article/details/109595399

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值