对称加密算法有加密和解密两个过程,而且加密和解密使用的是相同一把秘钥,对称加密算法主要是DES和AES两种,其中AES算法更加安全。
在JDK中,DES与AES算法都提供了实现。
此类加密算法与对称加密有所不同,此类算法通常是将原文加密后生成一个固定长度的密文,注意,这里是固定长度的,也就是不管原文有多长,密文总是固定长度的,这里是和对称加密算法有区别的。同时此类加密算法是不可逆的,也就是无法解密。消息摘要类算法主要有 MD5,SHA1,SHA256,SHA512等。
Base64算法不是一种加密算法,而是一种可读性算法,用于将非字符编码类型的字节,转为0-63内的ASCII编码,由A-Z,a-z,0-9, + /这64个字符填充。Base64算法原理是 将带转码的原文按字节拆成多个组,每个组有3个字节,不够的用等号填充。
然后将每个组的3个字节,拆成4个字节,3 * 8 = 4 * 6,拆成4个字节后,每个字节还少2位,此时需要在最高位补0,这样,整个字节的长度就能控制在0-63之间。
public class DESUtil {
private static final String ALGORITHM = "DES";
private static final String TRANSFORMATION = "DES/ECB/PKCS5Padding";
public static String encrypt(String data, String key) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String decrypt(String data, String key) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(data));
return new String(decryptedBytes, "UTF-8");
}
public static void main(String[] args) throws Exception {
String s = "Hello World!";
String secretKey = "12345678";
String encrypt = encrypt(s, secretKey);
System.out.println("加密后:" + encrypt);
System.out.println("解密后:" + decrypt(encrypt,secretKey));
}
}
public class AESUtil {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
public static String encrypt(String data, String key) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String decrypt(String data, String key) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(data));
return new String(decryptedBytes, "UTF-8");
}
public static void main(String[] args) throws Exception {
String s = "Hello World!Hello World!Hello World!Hello World!Hello World!";
String secretKey = "1234567812345679";
String encrypt = encrypt(s, secretKey);
System.out.println("加密后:" + encrypt);
System.out.println("解密后:" + decrypt(encrypt,secretKey));
}
}
除了基本的加密算法外,JDK中还实现了加密模式与填充模式,加密模式有两种,分别是 ECB与CBC,前者是块加密,每个块使用相同的秘钥,而CBC是每个块使用不同的秘钥,还需要用到IV向量。填充模式也有两种,为NoPadding和PKCS5Padding。NoPadding不填充,但是对原文的长度有要求,字节数必须是8的倍数。而PKCS5Padding为当原文长度不够时,会自动填充字节。
两种算法的对比:
@Test
public void testHash() throws Exception {
String s = "Hello World!";
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] digest = md5.digest(s.getBytes(StandardCharsets.UTF_8));
print("md5", digest);
//SHA-1算法
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
byte[] sha1Digest = sha1.digest(s.getBytes(StandardCharsets.UTF_8));
print("sha1", sha1Digest);
//SHA-256算法
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] sha256Digest = sha256.digest(s.getBytes(StandardCharsets.UTF_8));
print("sha256", sha256Digest);
//SHA-512算法
MessageDigest sha512 = MessageDigest.getInstance("SHA-512");
byte[] sha512Digest = sha512.digest(s.getBytes(StandardCharsets.UTF_8));
print("sha512", sha512Digest);
}
private void print(String type, byte[] digest) {
String s = "";
for (byte b : digest) {
s = s + String.format("%02x", b);
}
System.out.println(type + "(" + s.length() + ")" + " ==> " + s);
}
通过运行程序发现,此类算法的结果确实和原文长度无关,且无法解密。
持续更新中…