【加密】对称加密算法

前言

之前对非对称加密作了介绍(请大力点击),现对对称加密作个简单介绍。

对称加密算法

能通过相同的密钥对报文进行加密、解密的算法,叫对称加密算法。
比如,客户端,将一段报文通过密钥加密成密文,发送密文给服务端,服务端收到密文,通过相同的密钥解密,还原报文。

常用的对称加密算法:DES

特点:

  • 通过相同的密钥对报文进行加密、解密。所以,需要保证密钥的保密。
  • 计算速度快。所以,经常与计算速度慢的非对称加密算法一起使用,形成混合加密(后续博文描述)。

为什么要有密钥

我们有加密算法,为什么要有密钥?
答:加密算法只是一种算法(可视作一套逻辑),通常为大家所知,比如DES。如果一段报文,通过大家熟知的逻辑加密,那么其他人也能通过相应的逻辑解密,这样意义不大。所以就有密钥,相当于算法的密码,算法逻辑加上密钥公共将报文加密成密文,相应的,需通过算法逻辑和密钥才能正确解密。

危险

最常见的破解加密算法的手段是枚举攻击。由于大家都知道算法的逻辑,通过枚举密钥的所有可能性尝试解码。所以,密钥的位数决定了枚举攻击的难度,密钥位数越多,越难枚举出所有的可能性破解,当然,我们加解密的计算速度也有相应的影响。随着现代计算机计算速度提升,密钥的位数也在提升。

简单的例子

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import org.junit.Test;

public class DESUtils {
	
	/**
	 * 加密
	 * @param data 加密的数据
	 * @param key 密钥
	 * @return 加密后的数据
	 */
	public static byte[] encrypt(byte[] data, byte[] key) {
		try {
			DESKeySpec desKeySpec = new DESKeySpec(key);
			SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
			Cipher cipher = Cipher.getInstance("DES");
			cipher.init(Cipher.ENCRYPT_MODE, secretKey);
			return cipher.doFinal(data);
			
		} catch (InvalidKeyException e) {
			throw new RuntimeException("无效的Key值");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException("无DES算法");
		} catch (InvalidKeySpecException e) {
			throw new RuntimeException("无效的KeySpec");
		} catch (NoSuchPaddingException e) {
			throw new RuntimeException("无Padding");
		} catch (IllegalBlockSizeException e) {
			throw new RuntimeException(e);
		} catch (BadPaddingException e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 解密
	 * @param data 解密前的数据
	 * @param key 密钥
	 * @return 解密后的数据
	 */
	public static byte[] decrypt(byte[] data, byte[] key) {
		try {
			DESKeySpec desKeySpec = new DESKeySpec(key);
			SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec);
			Cipher cipher = Cipher.getInstance("DES");
			cipher.init(Cipher.DECRYPT_MODE, secretKey);
			return cipher.doFinal(data);
			
		} catch (InvalidKeyException e) {
			throw new RuntimeException("无效的Key值");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException("无DES算法");
		} catch (InvalidKeySpecException e) {
			throw new RuntimeException("无效的KeySpec");
		} catch (NoSuchPaddingException e) {
			throw new RuntimeException("无Padding");
		} catch (IllegalBlockSizeException e) {
			throw new RuntimeException(e);
		} catch (BadPaddingException e) {
			throw new RuntimeException(e);
		}
	}
	
	@Test
	public void encryptTest() {
		System.out.println(Base64.getEncoder().encodeToString(DESUtils.encrypt("hello".getBytes(), "12345678".getBytes())));
	}
	
	@Test
	public void decryptTest() {
		System.out.println(new String(DESUtils.decrypt(Base64.getDecoder().decode("uhbGoCVxJa8="), "12345678".getBytes())));
	}
	
}