一文带你学习主流的“加密算法”
博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌
Java知识图谱点击链接:体系化学习Java(Java面试专题)
💕💕 感兴趣的同学可以收藏关注下 ,不然下次找不到哟💕💕
1、加密算法简介
加密算法是一种将明文转换成密文的算法,主要用于数据保密和信息安全领域。加密算法可以分为对称加密算法和非对称加密算法两种类型。
加密算法的安全性主要取决于密钥的长度和算法的复杂度。一般来说,密钥越长,算法越复杂,安全性就越高。但是,密钥和算法的复杂度也会影响加密和解密的速度和性能。
在实际应用中,我们需要根据具体需求和安全要求选择合适的加密算法和密钥长度,同时结合其他技术手段如数字签名、身份认证等来保障信息安全。
2、加密算法分类
加密算法可以分为对称加密算法和非对称加密算法两种类型。
对称加密算法是指加密和解密使用同一个密钥的加密算法,常见的对称加密算法有DES、AES、SM4等。对称加密算法的优点是加密和解密速度快,缺点是密钥的管理和分配比较困难。
非对称加密算法是指加密和解密使用不同密钥的加密算法,常见的非对称加密算法有RSA、ECC等。非对称加密算法的优点是密钥的管理和分配比较方便,缺点是加密和解密速度慢。
此外,还有哈希算法,它是一种单向加密算法,常用于密码存储和数据完整性校验等场景。常见的哈希算法有MD5、SHA-1、SHA-256等。
加密算法的安全性主要取决于密钥的长度和算法的复杂度。一般来说,密钥越长,算法越复杂,安全性就越高。但是,密钥和算法的复杂度也会影响加密和解密的速度和性能。在实际应用中,我们需要根据具体需求和安全要求选择合适的加密算法和密钥长度,同时结合其他技术手段如数字签名、身份认证等来保障信息安全。
3、加密算法的应用
加密算法的应用非常广泛,主要用于以下几个方面:
- 数据保密:加密算法可以将敏感数据加密后传输,防止数据泄露和被窃取。例如,银行网站使用加密算法保护用户的账户信息和交易记录。
- 数字签名:数字签名是一种用于认证和验证数字信息的技术,常用于电子合同、电子邮件等场景。数字签名使用非对称加密算法生成数字证书,保证信息的真实性和完整性。
- 身份认证:加密算法可以用于身份认证,例如,SSL证书可以验证网站的身份,保证用户访问的是真实的网站,而不是恶意的钓鱼网站。
- 数据完整性校验:哈希算法可以用于数据完整性校验,例如,数字证书使用哈希算法生成数字指纹,验证数字证书的完整性和真实性。
加密算法在信息安全领域中有着广泛的应用,可以保护数据的机密性、完整性和可用性,保障用户的隐私和安全。
4、对称加密算法- DES
DES(Data Encryption Standard)是一种对称加密算法,是1977年由IBM公司研制的,是美国联邦政府采用的一种数据加密标准。DES算法使用64位密钥对数据进行加密,加密过程中将明文分成64位的数据块,经过16轮加密运算后得到密文。解密过程与加密过程相反,将密文输入DES算法,经过16轮解密运算后得到明文。
DES算法的优点是加密速度快、安全性较高,但随着计算机技术的发展,DES算法的密钥长度过短,易受到暴力破解和密码分析等攻击。因此,为了提高安全性,后来推出了3DES和AES等更加安全的加密算法。
DES 在 java 上的运用如下:
package com.pany.camp.encryption;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
/**
*
* @description: DES 加密算法
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-25 12:16
*/
public class DESUtil {
private static final String DES_ALGORITHM = "DES";
/**
* 加密方法
*
* @param data 待加密的数据
* @param key 密钥,8字节
* @return 加密后的数据
* @throws Exception
*/
public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
DESKeySpec desKeySpec = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(data);
}
/**
* 解密方法
*
* @param data 待解密的数据
* @param key 密钥,8字节
* @return 解密后的数据
* @throws Exception
*/
public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
DESKeySpec desKeySpec = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(data);
}
public static void main(String[] args) throws Exception {
String data = "Hello, world!";
String key = "12345678";
byte[] encryptedData = DESUtil.encrypt(data.getBytes(), key.getBytes());
byte[] decryptedData = DESUtil.decrypt(encryptedData, key.getBytes());
System.out.println("明文:" + data);
System.out.println("密文:" + new String(encryptedData));
System.out.println("解密后的明文:" + new String(decryptedData));
}
}
输出如下:
Connected to the target VM, address: '127.0.0.1:63681', transport: 'socket'
明文:Hello, world!
密文:Ic�[k���nܲ����
解密后的明文:Hello, world!
Disconnected from the target VM, address: '127.0.0.1:63681', transport: 'socket'
Process finished with exit code 0
注意:DES算法的密钥长度必须为8字节,如果密钥长度不足8字节,需要进行补位或者使用其他算法。另外,DES算法已经被认为不安全,不建议在实际应用中使用。
5、对称加密算法 - IDEA
IDEA(International Data Encryption Algorithm)是一种对称加密算法,由Xuejia Lai和James L. Massey于1991年提出。IDEA算法使用128位密钥和64位数据块,采用了多轮加密、异或运算、模运算等方法,具有高强度的安全性和较快的加解密速度。
IDEA算法的加密过程如下:
将明文分为64位一组,并将其分为左右两部分。
进行8轮加密,每轮加密包括以下步骤:
a. 将右半部分和第i个子密钥进行异或运算。
b. 将异或结果分为4个16位子块,分别进行乘法运算和模运算。
c. 将4个16位子块合并为一个64位块。
d. 将左半部分和上一轮的右半部分进行异或运算。
e. 将左右两部分交换。最后一轮加密后,将左右两部分交换,得到加密后的结果。
IDEA算法的解密过程与加密过程类似,只是将加密过程中的子密钥按逆序使用即可。
总体来说,IDEA算法是一种强度较高的加密算法,但由于其专利保护的原因,使用IDEA算法需要获得许可或使用其他替代算法。在实际应用中,常用的对称加密算法包括AES、DES、3DES等。
IDEA 在 java 上的运用如下:
package com.pany.camp.encryption;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
import java.util.Base64;
/**
*
* @description: IDEA 加密算法
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-25 12:20
*/
public class IDEAEncryptor {
private static final String ALGORITHM = "IDEA/ECB/PKCS7Padding";
private static final String CHARSET = "UTF-8";
private static final String KEY = "1234567890abcdef"; // 16字节密钥
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
String plainText = "Hello, world!";
String encryptedText = encrypt(plainText);
String decryptedText = decrypt(encryptedText);
System.out.println("Plain text: " + plainText);
System.out.println("Encrypted text: " + encryptedText);
System.out.println("Decrypted text: " + decryptedText);
}
public static String encrypt(String plainText) throws Exception {
byte[] keyBytes = KEY.getBytes(CHARSET);
SecretKeySpec key = new SecretKeySpec(keyBytes, "IDEA");
Cipher cipher = Cipher.getInstance(ALGORITHM, "BC");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(CHARSET));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String decrypt(String encryptedText) throws Exception {
byte[] keyBytes = KEY.getBytes(CHARSET);
SecretKeySpec key = new SecretKeySpec(keyBytes, "IDEA");
Cipher cipher = Cipher.getInstance(ALGORITHM, "BC");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, CHARSET);
}
}
输出结果如下:
Connected to the target VM, address: '127.0.0.1:63834', transport: 'socket'
Plain text: Hello, world!
Encrypted text: Dvmb7IKOQslhZgOOjZ5BSA==
Decrypted text: Hello, world!
Disconnected from the target VM, address: '127.0.0.1:63834', transport: 'socket'
Process finished with exit code 0
上面使用了BouncyCastle作为IDEA算法的提供者,需要将其添加到Security中。加密和解密时使用相同的密钥和算法,其中密钥需要转换为SecretKeySpec类型。加密时将明文转换为字节数组,加密后的结果使用Base64编码,解密时需要先将Base64编码的结果解码为字节数组,再进行解密并转换为字符串。
pom.xml 需要引入下面的依赖:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
6、对称加密算法 - AES
AES(Advanced Encryption Standard)是一种对称加密算法,于2001年被美国联邦政府采用为加密标准,替代了早期的DES算法。AES算法使用128位、192位或256位密钥和128位数据块,采用了高级置换、逆置换、轮密钥加等方法,具有高强度的安全性和较快的加解密速度。AES算法已经成为目前最常用的对称加密算法之一,广泛应用于各种安全领域,如网络通信、数据存储、金融交易等。
AES算法的加密过程如下:
- 将明文分为128位一组,并将其分为左右两部分。
- 进行多轮加密,每轮加密包括以下步骤:
a. 将右半部分和第i个子密钥进行异或运算。
b. 将异或结果分为4个32位子块,分别进行字节代换、行移位、列混淆和轮密钥加运算。
c. 将4个32位子块合并为一个128位块。
d. 将左半部分和上一轮的右半部分进行异或运算。
e. 将左右两部分交换。 - 最后一轮加密后,将左右两部分交换,得到加密后的结果。
AES算法的解密过程与加密过程类似,只是将加密过程中的子密钥按逆序使用即可。
在Java中,可以使用JCE(Java Cryptography Extension)提供的API来实现AES算法的加解密。常用的AES加密模式包括ECB(电子密码本模式)、CBC(密码分组链接模式)、CFB(密文反馈模式)和OFB(输出反馈模式)等。
AES 在 java 上的应用如下:
package com.pany.camp.encryption;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
/**
*
* @description: AES 加密算法
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-25 12:25
*/
public class AESUtil {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
private static final String CHARSET = "UTF-8";
/**
* 加密
*
* @param data 待加密的字符串
* @param key 密钥
* @return 加密后的字符串
*/
public static String encrypt(String data, String key) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(CHARSET), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encryptedBytes = cipher.doFinal(data.getBytes(CHARSET));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
/**
* 解密
*
* @param data 待解密的字符串
* @param key 密钥
* @return 解密后的字符串
*/
public static String decrypt(String data, String key) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(CHARSET), ALGORITHM);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(data));
return new String(decryptedBytes, CHARSET);
}
public static void main(String[] args) throws Exception {
String data = "Hello, world!";
String key = "1234567890123456";
String encryptedData = AESUtil.encrypt(data, key);
String decryptedData = AESUtil.decrypt(encryptedData, key);
System.out.println("加密前的数据:" + data);
System.out.println("加密后的数据:" + encryptedData);
System.out.println("解密后的数据:" + decryptedData);
}
}
其中, ALGORITHM 和 TRANSFORMATION 分别指定了AES算法和加密模式, CHARSET 指定了字符串编码。在加密和解密时,需要先将密钥转换为 SecretKeySpec 对象,然后使用 Cipher 类进行加解密操作。加密时,将待加密的数据转换为字节数组,调用 doFinal 方法进行加密,最后将加密结果使用Base64编码返回;解密时,将待解密的数据先使用Base64解码,然后调用 doFinal 方法进行解密,最后将解密结果转换为字符串返回。
输出结果如下:
加密前的数据:Hello, world!
加密后的数据:SyyaYH+Y+RtQID7v3kRKRA==
解密后的数据:Hello, world!
Process finished with exit code 0
7、对称加密算法 - 3DES
3DES(Triple Data Encryption Standard),也称为TDEA(Triple DEA),是一种对称加密算法,是DES算法的加强版。3DES是由三次DES算法串联而成,即将数据分别进行三次DES加密和三次DES解密,使用不同的密钥,以提高加密强度。3DES算法的密钥长度为168位,采用64位数据块,加密过程中包括加密、解密和再加密三个步骤,解密过程中包括解密、加密和再解密三个步骤。
3DES算法的加密过程如下:
- 将明文分为64位一组,并将其分为左右两部分。
- 进行3次DES加密,每次加密包括以下步骤:
a. 将右半部分和第i个子密钥进行异或运算。
b. 将异或结果作为下一轮的左半部分。
c. 将左右两部分交换。 - 最后一轮加密后,将左右两部分交换,得到加密后的结果。
3DES算法的解密过程与加密过程类似,只是将加密过程中的子密钥按逆序使用即可。
3DES算法具有较高的安全性和广泛的应用,但由于其加密过程较为复杂,加解密速度较慢。在实际应用中,常用的对称加密算法包括AES、DES、3DES等。
3DES 在 java 上的应用如下:
package com.pany.camp.encryption;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import java.security.Key;
import java.util.Base64;
/**
*
* @description: 3DES 加密算法
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-25 12:29
*/
public class TripleDesUtil {
private static final String KEY_ALGORITHM = "DESede";
private static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";
/**
* 3DES加密
*
* @param plainText 明文
* @param key 密钥
* @return 加密后的密文
* @throws Exception
*/
public static String encrypt(String plainText, String key) throws Exception {
Key desKey = getDesKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, desKey);
byte[] cipherBytes = cipher.doFinal(plainText.getBytes());
return Base64.getEncoder().encodeToString(cipherBytes);
}
/**
* 3DES解密
*
* @param cipherText 密文
* @param key 密钥
* @return 解密后的明文
* @throws Exception
*/
public static String decrypt(String cipherText, String key) throws Exception {
Key desKey = getDesKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, desKey);
byte[] cipherBytes = Base64.getDecoder().decode(cipherText);
byte[] plainBytes = cipher.doFinal(cipherBytes);
return new String(plainBytes);
}
/**
* 获取3DES密钥
*
* @param key 密钥字符串
* @return 密钥对象
* @throws Exception
*/
private static Key getDesKey(String key) throws Exception {
byte[] keyBytes = key.getBytes();
DESedeKeySpec desKeySpec = new DESedeKeySpec(keyBytes);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
return secretKey;
}
public static void main(String[] args) {
String data = "Hello, world!";
String key = "2FEADC89A8864C169B0B51F4463E7F7FA1ADD55E07A123FB";
try {
String cipherText = TripleDesUtil.encrypt(data, key);
System.out.println("加密后的密文:" + cipherText);
String decryptedText = TripleDesUtil.decrypt(cipherText, key);
System.out.println("解密后的明文:" + decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出如下:
加密后的密文:WhuSHId/zoxHVEc1yddjKA==
解密后的明文:Hello, world!
Process finished with exit code 0
注意:密钥长度必须为24字节,可以通过对字符串进行编码或哈希等方式来生成密钥。
下面我写一个生产24字节的随机秘钥:
package com.pany.camp.encryption;
import java.security.SecureRandom;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
/**
*
* @description: 3DES 的秘钥生成
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-25 12:32
*/
public class TripleDesKeyGenerator {
public static void main(String[] args) throws Exception {
// 创建一个安全的随机数生成器
SecureRandom secureRandom = new SecureRandom();
// 创建一个3DES密钥生成器
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
// 初始化密钥生成器,指定密钥长度和随机数生成器
keyGenerator.init(168, secureRandom);
// 生成一个3DES密钥
SecretKey secretKey = keyGenerator.generateKey();
// 将密钥转换为字节数组
byte[] keyBytes = secretKey.getEncoded();
// 将字节数组转换为字符串表示
String key = bytesToHexString(keyBytes);
System.out.println("生成的3DES密钥为:" + key);
}
/**
* 将字节数组转换为十六进制字符串
*/
public static String bytesToHexString(byte[] bytes) {
StringBuilder stringBuilder = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(b & 0xFF);
if (hex.length() == 1) {
stringBuilder.append('0');
}
stringBuilder.append(hex);
}
return stringBuilder.toString().toUpperCase();
}
}
8、非对称加密算法 - RSA
RSA是一种非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman三位数学家于1977年提出。RSA算法使用公钥和私钥进行加解密,公钥可以公开,任何人都可以使用公钥对数据进行加密,但只有私钥持有者才能
使用私钥进行解密。RSA算法具有以下特点:
- 安全性:RSA算法的安全性基于大整数分解的困难性,即将一个大的合数分解为其质因数的乘积是困难的。
- 非对称性:RSA算法使用公钥和私钥进行加解密,公钥和私钥是不同的,因此称为非对称加密算法。
- 数字签名:RSA算法可以用于数字签名,即使用私钥对数据进行签名,使用公钥对签名进行验证,确保数据的完整性和真实性。
- 密钥交换:RSA算法可以用于密钥交换,即通过公钥加密传输密钥,确保密钥的安全性和机密性。
RSA算法的加密过程如下: - 选择两个大素数p和q,并计算它们的乘积n=p*q。
- 计算欧拉函数φ(n)=(p-1)*(q-1)。
- 选择一个小于φ(n)且与φ(n)互质的正整数e作为公钥。
- 计算私钥d,使得d*e mod φ(n)=1。
- 将明文m转换为整数M。
- 使用公钥进行加密,计算C=M^e mod n。
- 使用私钥进行解密,计算M=C^d mod n,得到明文m。
RSA算法的解密过程与加密过程类似,只是使用私钥进行加解密。
总体来说,RSA算法是一种强大的加密算法,被广泛应用于数字证书、SSL/TLS协议、数字签名、密钥交换等领域。
RSA 在 java 上的应用如下:
package com.pany.camp.encryption;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import javax.crypto.Cipher;
/**
*
* @description: RSA 加密算法
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-25 12:35
*/
public class RSAExample {
private static final String ALGORITHM = "RSA";
private static final int KEY_SIZE = 2048;
public static void main(String[] args) throws Exception {
// 生成公钥和私钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// 加密明文
String plainText = "Hello, World!";
byte[] cipherText = encrypt(plainText.getBytes(), publicKey);
// 解密密文
byte[] decryptedText = decrypt(cipherText, privateKey);
String decryptedPlainText = new String(decryptedText);
System.out.println(decryptedPlainText);
// 签名明文
byte[] signature = sign(plainText.getBytes(), privateKey);
// 验证签名
boolean verified = verify(plainText.getBytes(), signature, publicKey);
System.out.println("Signature verified: " + verified);
}
public static byte[] encrypt(byte[] plainText, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(plainText);
}
public static byte[] decrypt(byte[] cipherText, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(cipherText);
}
public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
}
public static boolean verify(byte[] data, byte[] signature, PublicKey publicKey) throws Exception {
Signature verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(publicKey);
verifier.update(data);
return verifier.verify(signature);
}
}
我们首先生成了一个公钥和私钥对,然后使用公钥对明文进行加密,使用私钥对密文进行解密。接下来,我们对明文进行签名,然后使用公钥验证签名的有效性。在实际应用中,我们通常会将公钥和私钥保存在不同的地方,例如公钥可以公开发布,任何人都可以使用公钥进行加密,而私钥只有持有者才能使用。
输出结果如下:
加密后的密文:WhuSHId/zoxHVEc1yddjKA==
解密后的明文:Hello, world!
Process finished with exit code 0
💕💕 本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
💕💕喜欢的话记得点赞收藏啊
- 点赞
- 收藏
- 关注作者
评论(0)