对称加密算法AES
对称加密算法加密和解密使用的是同一份秘钥,解密是加密的逆运算。
对称加密算法加密速度快,密文可逆,一旦秘钥文件泄露,就会导致原始数据暴露。
对称加密的结果一般使用Base64算法编码。
JDK8支持的对称加密算法主要有DES、DESede、AES、Blowfish,以及RC2和RC4等。
AES
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import org.junit.Test;
import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.Base64;
public class Demo {
@Test public void test() throws Exception { String value = "hankz"; System.out.println("待加密值:" + value); // 加密算法 String algorithm = "AES"; // 转换模式 String transformation = "AES"; // --- 生成秘钥 --- // 实例化秘钥生成器 KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm); // 初始化秘钥长度 keyGenerator.init(256); // 生成秘钥 SecretKey secretKey = keyGenerator.generateKey(); // 生成秘钥材料 SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), algorithm); System.out.println("AES秘钥:" + Base64.getEncoder().encodeToString(secretKey.getEncoded()));
// 实例化密码对象 Cipher cipher = Cipher.getInstance(transformation); // 设置模式(ENCRYPT_MODE:加密模式;DECRYPT_MODE:解密模式)和指定秘钥 cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); // 加密 byte[] encrypt = cipher.doFinal(value.getBytes()); System.out.println("AES加密结果:" + Base64.getEncoder().encodeToString(encrypt)); // 解密 // 设置为解密模式 cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); byte[] decrypt = cipher.doFinal(encrypt); System.out.println("AES解密结果:" + new String(decrypt)); } }
|
非对称加密算法RSA
公钥加密私钥解密,或者私钥加密公钥解密
该算法由美国麻省理工学院(MIT)的Ron Rivest、Adi Shamir和Leonard Adleman三位学者提出,并以这三位学者的姓氏开头字母命名,称为RSA算法。
- A构建RSA秘钥对;
- A向B发布公钥;
- A用私钥加密数据发给B;
- B用公钥解密数据;
- B用公钥加密数据发给A;
- A用私钥解密数据。
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 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 52
| import org.junit.Test;
import javax.crypto.Cipher; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Base64;
public class Demo {
@Test public void test() throws Exception { String value = "hankz"; // 加密算法 String algorithm = "RSA"; // 转换模式 String transform = "RSA/ECB/PKCS1Padding"; // 实例化秘钥对生成器 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm); // 初始化,秘钥长度512~16384位,64倍数 keyPairGenerator.initialize(512); // 生成秘钥对 KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 公钥 PublicKey publicKey = keyPair.getPublic(); System.out.println("RSA公钥: " + Base64.getEncoder().encodeToString(publicKey.getEncoded())); // 私钥 PrivateKey privateKey = keyPair.getPrivate(); System.out.println("RSA私钥: " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));
// ------ 测试公钥加密,私钥解密 ------ Cipher cipher = Cipher.getInstance(transform); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] pubEncryptBytes = cipher.doFinal(value.getBytes()); System.out.println("RSA公钥加密后数据: " + Base64.getEncoder().encodeToString(pubEncryptBytes));
cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] priDecryptBytes = cipher.doFinal(pubEncryptBytes); System.out.println("RSA私钥解密后数据: " + new String(priDecryptBytes));
// ------ 测试私钥加密,公钥解密 ------ cipher.init(Cipher.ENCRYPT_MODE, privateKey); byte[] priEncryptBytes = cipher.doFinal(value.getBytes()); System.out.println("RSA私钥加密后数据: " + Base64.getEncoder().encodeToString(priEncryptBytes));
cipher.init(Cipher.DECRYPT_MODE, publicKey); byte[] pubDecryptBytes = cipher.doFinal(priEncryptBytes); System.out.println("RSA公钥解密后数据: " + new String(pubDecryptBytes)); } }
|
现在有RSA公钥:
1
| MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKBvz9cma+hXNiv2yXg6e1PyZhHVZm3bJXDvTJP2LyXo4vs9grH36Q9kNgr6quHtuU6fEoUxUu2zbEB8dkEWB9UCAwEAAQ==
|
RSA私钥:
1
| MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAoG/P1yZr6Fc2K/bJeDp7U/JmEdVmbdslcO9Mk/YvJeji+z2CsffpD2Q2Cvqq4e25Tp8ShTFS7bNsQHx2QRYH1QIDAQABAkEAjemZXORdesz52/WVzEVepai6ZHfw/Kdl/PmPMSoIFmz7mk55rprl2Akn2V0odSiHSnMWvDmOUIAvHaHF4Re4wQIhAN5GxVeF7ndyoWasxqIOVb6baNkUrapBM0nacPS4WA8JAiEAuMcvNM2Z1rW74JagoGlSIfRkNUqa+3LTCN/fK7VR2W0CICs/+gYduVjkpSMlW0ENKQH9m1kh/Oiz5xbnujLj676BAiBVGif7wdXgtcLaJYXFW7ygNtcQVFQdCz13EOTQVKpl4QIgY2YyH3vUYI2J68qCGtYjj5iNHUEwwze+Za1R7y0V43k=
|
还原为PublicKey和PrivateKey对象
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import org.junit.Test;
import javax.crypto.Cipher; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64;
public class Demo {
@Test public void test() throws Exception { String value = "hankz"; // 加密算法 String algorithm = "RSA"; // 转换模式 String transform = "RSA/ECB/PKCS1Padding"; // RSA公钥BASE64字符串 String rsaPublicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKBvz9cma+hXNiv2yXg6e1PyZhHVZm3bJXDvTJP2LyXo4vs9grH36Q9kNgr6quHtuU6fEoUxUu2zbEB8dkEWB9UCAwEAAQ=="; // RSA私钥BASE64字符串 String rsaPrivateKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAoG/P1yZr6Fc2K/bJeDp7U/JmEdVmbdslcO9Mk/YvJeji+z2CsffpD2Q2Cvqq4e25Tp8ShTFS7bNsQHx2QRYH1QIDAQABAkEAjemZXORdesz52/WVzEVepai6ZHfw/Kdl/PmPMSoIFmz7mk55rprl2Akn2V0odSiHSnMWvDmOUIAvHaHF4Re4wQIhAN5GxVeF7ndyoWasxqIOVb6baNkUrapBM0nacPS4WA8JAiEAuMcvNM2Z1rW74JagoGlSIfRkNUqa+3LTCN/fK7VR2W0CICs/+gYduVjkpSMlW0ENKQH9m1kh/Oiz5xbnujLj676BAiBVGif7wdXgtcLaJYXFW7ygNtcQVFQdCz13EOTQVKpl4QIgY2YyH3vUYI2J68qCGtYjj5iNHUEwwze+Za1R7y0V43k=";
// ------- 还原公钥 -------- byte[] publicKeyBytes = Base64.getDecoder().decode(rsaPublicKey); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance(algorithm); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
// ------- 还原私钥 -------- byte[] privateKeyBytes = Base64.getDecoder().decode(rsaPrivateKey); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
// ------- 测试加解密 -------- Cipher cipher = Cipher.getInstance(transform); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] pubEncryptBytes = cipher.doFinal(value.getBytes()); System.out.println("RSA公钥加密数据: " + Base64.getEncoder().encodeToString(pubEncryptBytes));
cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] priDecryptBytes = cipher.doFinal(pubEncryptBytes); System.out.println("RSA私钥解密数据: " + new String(priDecryptBytes)); } }
|
一般来讲公司都有内部的工具类,不必编写如此繁琐的代码。
公钥是通过A发送给B的,其在传递过程中很有可能被截获,也就是说窃听者很有可能获得公钥。如果窃听者获得了公钥,向A发送数据,A是无法辨别消息的真伪的。因此,虽然可以使用公钥对数据加密,但这种方式还是会有存在一定的安全隐患。如果要建立更安全的加密消息传递模型,就需要AB双方构建两套非对称加密算法密钥,仅遵循“私钥加密,公钥解密”的方式进行加密消息传递;
RSA不适合加密过长的数据,虽然可以通过分段加密手段解决,但过长的数据加解密耗时较长,在响应速度要求较高的情况下慎用。一般推荐使用非对称加密算法传输对称加密秘钥,双方数据加密用对称加密算法加解密。
数字签名
- A在本地构建秘钥对,并将公钥发布给B;
- A使用私钥对数据进行签名;
- A发送签名和数据给B;
- B使用公钥对签名和数据进行验签。