对称密码体制中大部分加密算法属于分组密码,而分组密码是每次只能处理特定长度的一块数据的一类密码算法,这里的“一块”就称为分组。此外,一个分组的比特数就称为分组长度。
对称密码中的DES和DESede算法的分组长度都是64比特,因此它们一次只能加密64比特的明文并生成64比特的密文。AES算法的分组长度为128比特,因此AES一次可加密128比特的明文并生成128比特的密文。
分组密码算法只能加密固定长度的分组,但是我们需要加密的明文长度可能会超过分组密码的分组长度,这时就需要对分组密码算法进行迭代,以便将一段很长的明文全部加密。而迭代的方法就称为分组密码的模式。
大家可能会有疑问:"如果明文很长,将明文分割成若干个分组再逐个加密不就好了吗?”事实上可没有那么简单。将明文分割成多个分组并逐个加密的方法称为ECB模式,这种模式具有极大的安全隐患。因此要记住千万不能使用ECB模式。
模式有很多种类,分组密码的主要模式有以下5种:
- ECB模式:Electronic CodeBook mode
- CBC模式:Cipher Block Chaining mode
- CFB模式:Cipher FeedBack mode
- OFB模式:Output FeedBack mode
- CTR模式:CounTeR mode
1973年NIST征求国家密码标准方案,IBM公司提交了自己研制的算法(Luciffer算法),1977年该算法被正式采纳,成为事实标准,即数据加密标准(Data Encryption Standard,DES),DES算法由此诞生。DES算法密钥偏短仅有56位,迭代次数偏少,后来又能被暴力破解,因此现在已经不再使用。
作为DES算法的一种改良,DESede算法针对其密钥长度偏短和迭代次数偏少等问题作了相应改进,提高了安全强度。DESede算法处理速度较慢,密钥计算时间较长,加密效率不高等问题使得也不鼓励使用。
1997年NIST发起了征集DES替代算法---AES(Advanced Encryption Standard,AES)算法的活动,最终,比利时人Daemen和Rijmen提出的Rijndael算法以其密钥设置快、存储要求低,在硬件实现和限制存储的条件下性能优异当选AES算法。
AES算法的密钥长度可为128、192、256,默认为128位。
package com.fulcrum.encrypt;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
public class AESDemo {
private static final String KEY_ALGORITHM = "AES";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static final byte[] iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
private static final IvParameterSpec ivSpec = new IvParameterSpec(iv);
public static void main(String[] args) throws Exception {
String str = "开放自由包容";
byte[] sk = initKey();
System.out.println("--原文:"+str);
byte[] input = encrypt(str.getBytes(StandardCharsets.UTF_8), sk);
System.out.println("加密后:"+ Base64.encodeBase64String(input));
byte[] output = decrypt(input, sk);
System.out.println("解密后:"+new String(output));
}
public static byte[] decrypt(byte[] data,byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, k, ivSpec);
return cipher.doFinal(data);
}
public static byte[] encrypt(byte[] data, byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, k, ivSpec);
return cipher.doFinal(data);
}
public static byte[] initKey() throws NoSuchAlgorithmException {
KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
kg.init(256);//设置密钥长度,128、192或256皆可
SecretKey secretKey = kg.generateKey();
return secretKey.getEncoded();
}
public static Key toKey(byte[] key){
SecretKey secretKey = new SecretKeySpec(key, KEY_ALGORITHM);
return secretKey;
}
}