非对称加密
1 定义
非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
2 特点
- 也称公开密钥加密,算法需要两个密钥,其中一个可以公开,并且通过公开的密钥无法推导出对应的私钥
- 算法复杂度相对对称加密算法高,所以计算相对较慢
- 密钥的保密性较好,因为公钥可以公开,免去了交换密钥的需求
3 使用场景
由于安全性较好,并且密钥可以公开,无交换过程泄密的风险,因此非对此密钥算法被广泛使用,比如SSH、HTTPS、电子证书、数字签名、加密通讯等领域。
公钥既可以进行加密,也可以解密,私钥也是一样,用于支持不同场景:
- 使用私钥加密,公钥解密
这种就是数字签名的原理,用于让所有公钥所有者验证私钥所有者的身份并且用来防止私钥所有者发布的内容被篡改(只有唯一的一方持有私钥,加密者一定是唯一确定的,除非私钥泄露了),但是不用来保证内容不被他人获得(公钥是公开的,所有持有公钥的一方都能解密这段密文) - 用公钥加密,私钥解密
这种就是数据加密,用于公钥所有者向私钥所有者发布信息,这个信息可能被他人篡改(因为持有公钥的一方都能生成一段新的密文,可以替换掉原始密文),但是无法被他人获得(只有私钥所有者一人能够解密这段密文) - 甲方用公钥-乙加密,私钥-甲加密,乙方用公钥-甲解密,私钥-乙解密
如果甲想给乙发一个安全的保密的数据,那么应该甲乙各自有一个私钥,甲先用乙的公钥加密这段数据,再用自己的私钥加密这段加密后的数据,最后再发给乙,这样确保了内容即不会被读取,也不会被篡改。
4 常用的非对称加密算法
1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法,RSA算法从被发明至今一直是最广为使用的"非对称加密算法"。其他场景的算法还有Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)。
5 JDK支持的非对称加密算法
JDK8原生算法列表,可参第一篇博文: https://blog.csdn.net/yunyun1886358/article/details/128592503#311_JDK_Provider_63
6 Bouncy Castle 支持的非对称加密算法
Bouncy Castle算法列表,可参第一篇博文:
https://editor.csdn.net/md/?articleId=128592503#323_Bouncy_Castle_Provider_568
7 算法调用示例
下面的代码将JDK提供的几种RSA加密算法用枚枚举类进行了封装,调用encrypt()和decrypt()方法可以实现加密和解。encrypt()和decrypt()的几个重载方法分别支持了不同秘钥生成方式(秘钥字符串,随机种子生成秘钥,从文件读取密钥字符串,从数字证书读取公钥,从密钥库读取公钥,从密钥库读取私钥),设置算法参数的类型(AlgorithmParameterSpec)。文章来源:https://www.toymoban.com/news/detail-499224.html
首先使用ktool生成密钥库,并导出公钥证书:文章来源地址https://www.toymoban.com/news/detail-499224.html
keytool -genkeypair -alias testing-keys -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore testing-keystore.p12 -validity 36500
keytool -list -v -keystore testing-keystore.p12
keytool -export -keystore testing-keystore.p12 -alias testing-keys -file testing-ca.cer -rfc
package com.qupeng.crypto.algorithm.oop;
import com.qupeng.crypto.util.CryptoUtils;
import com.qupeng.crypto.util.DigitalCertificationUtilsTest;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
public class AsymmetricEncryptionAlgorithmTest {
private static Path keyStorePath;
private static Path certificatePath;
@BeforeClass
public static void setUp() throws Exception {
keyStorePath = Paths.get(DigitalCertificationUtilsTest.class.getClassLoader().getResource("testing-keystore.p12").toURI());
certificatePath = Paths.get(DigitalCertificationUtilsTest.class.getClassLoader().getResource("testing-ca.cer").toURI());
}
@Test
public void encryptByRandomSeed() throws Exception {
// RSA 1024 bits secret
String cipherText = AsymmetricEncryptionAlgorithm.RSA_ECB_PKCS1_PADDING_1024.encrypt("a", "12345", NumberGenerationAlgorithm.SHA1_PRNG);
Assert.assertEquals("a", AsymmetricEncryptionAlgorithm.RSA_ECB_PKCS1_PADDING_1024.decrypt(cipherText, "12345", NumberGenerationAlgorithm.SHA1_PRNG));
// RSA 2048 bits secret
cipherText = AsymmetricEncryptionAlgorithm.RSA_ECB_PKCS1_PADDING_2048.encrypt("a", "12345", NumberGenerationAlgorithm.SHA1_PRNG);
Assert.assertEquals("a", AsymmetricEncryptionAlgorithm.RSA_ECB_PKCS1_PADDING_2048.decrypt(cipherText, "12345", NumberGenerationAlgorithm.SHA1_PRNG));
cipherText = AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_1_AND_MGF1_PADDING_1024.encrypt("a", "12345", NumberGenerationAlgorithm.SHA1_PRNG);
Assert.assertEquals("a", AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_1_AND_MGF1_PADDING_1024.decrypt(cipherText, "12345", NumberGenerationAlgorithm.SHA1_PRNG));
cipherText = AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_1024.encrypt("a", "12345", NumberGenerationAlgorithm.SHA1_PRNG);
Assert.assertEquals("a", AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_1024.decrypt(cipherText, "12345", NumberGenerationAlgorithm.SHA1_PRNG));
}
@Test
public void encryptByPublicKeyStr() throws IllegalAccessException, NoSuchAlgorithmException, InstantiationException, NoSuchMethodException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException, BadPaddingException, InvocationTargetException, IOException, InvalidKeySpecException, IllegalBlockSizeException {
String cipherText = AsymmetricEncryptionAlgorithm.RSA_ECB_PKCS1_PADDING_1024.encrypt("a", "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiMkwWmWUG4DkC/1mIgL0BSBOLbQWgGL7XnaolDQbpKP5QZFCbWQqj2/Gvmhhk5QQAYoNAdfz1OXzZAJj2Zbp+/QtFWJhemV3ivSvBTXCVyhg39kGkUjniensW8oOwQiyNsXERDYeafXlahYRvFKgOj9BvUo1wDGuD4ESyAl89XLQOgez65J+kJhjh0vQCyPbMkNxp3qZ3vJ/OoA07OOsIOxoR15wdxTS5pvI8jZ+A8/LlFqUNaryv3kt/IBezn0DRnfwRx5Wl4RXZQpxeLleUX2HwhxBCA2ZZtTAYR/VX3fDI5MIC1kmZGfDLjnlOAPOVpJyxWN6yeWiDnkNNE6t1QIDAQAB");
Assert.assertEquals("a", AsymmetricEncryptionAlgorithm.RSA_ECB_PKCS1_PADDING_1024.decrypt(cipherText, "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCIyTBaZZQbgOQL/WYiAvQFIE4ttBaAYvtedqiUNBuko/lBkUJtZCqPb8a+aGGTlBABig0B1/PU5fNkAmPZlun79C0VYmF6ZXeK9K8FNcJXKGDf2QaRSOeJ6exbyg7BCLI2xcRENh5p9eVqFhG8UqA6P0G9SjXAMa4PgRLICXz1ctA6B7Prkn6QmGOHS9ALI9syQ3Gnepne8n86gDTs46wg7GhHXnB3FNLmm8jyNn4Dz8uUWpQ1qvK/eS38gF7OfQNGd/BHHlaXhFdlCnF4uV5RfYfCHEEIDZlm1MBhH9Vfd8MjkwgLWSZkZ8MuOeU4A85WknLFY3rJ5aIOeQ00Tq3VAgMBAAECggEAduHc24QTUEAac2092euVJ+tm5wPw1o6wh+47H+uV5ub4mIrmH+sBrn5oTk6sF7aEnsHcAjEtY2iju9Tz8UXfgLI8iKxjqhwL5MI6Zx3NFTEr2QFnWtfxHIUpfrFDV3P2Z/JEXUBn+JHVXPlnWrS5O0aFHT4lLzA+Zo04xJCygSON47XjHakAZdFV1EXVic523Rof2/G67NyG2FJOhytz6dh0S94KevLCbYm1FQbLNVIQkat6dGgzz7ahyiubWt9B/EQU3HgLgT5KDLUWzW57VFCZOAoHYxUKJ2UafaXYEAMMe4mh3ZPAOPpNYpPEcww09zFOFg9e7cpxi7ydSl42lQKBgQDCNqniS90UqNZMOJwHuO5vfRHNIwWpXNIpehAmfITECyJlChMJR0Y2ytN0KdTAUz6tK9v+gYhKE4cHpb/bj4qwqsWyQ7e9QgTq1U2ZH7lhIiRmux6E0ILf4O2JnYRl5HoHSt9efZ4yxFTQrcX2JENTDK17alYvwn9h1aoilfRZewKBgQC0TXH34fvCv4U81VjB0brheBd+edoJ2ZPW5W95CVOJBFXhMB2CMaqsxcxkMgidYOa9H01NbcIXA/s9Yyn2vzPGsqBvQthSillay32sVMBcq7JdOACL/atXBmYOnuUYs7hAbjIwRi9HOA+TJdgGgfLYsfr7vHMHnaJTqgS99Qos7wKBgQCJnkB9GTK8W/MWKZruoe1a1O4TRTjSzPIi79qX2u4dGKKzpBLfJUEsvEZf7vBRo+sqvIRz8IeJrhKlqZ6szycAjtHtwqxlEG35lVIaKe+rU40lunwisrm6OGE5fYN+zApoNnbXNv4tjQ9om2pGQ2XtaHNZm30c9J5czhFz1nxCFwKBgAR+HYXgsqZCoW5HnqONt0tg86zqGl2+dymWo/VvHw699enbihCxbiBJ+XLRsFdDj9xMiF+SiZCLP9piuyvzzbV4w/ihwMQlwF47zdDad8SXXqVl/NWAJ6HOfgKFQQ4hhEjOth9v0EPFCNZQzhYzbLqrjKZzJqac7euJw/57uZovAoGAdi57B+aHkK42Odb0l9q+u7Nu8C8v5A7j8LvycKY48QJKxP7GiztTAX/qEcfiVl3HvdOP1kECePxGX1ix3aAmmzJWnrrI5UVdzkXevrJSqEJkbCi0YwVPs26gHGfCVfNkX6jdCv4PrsPwUzNr0ld+Oi4T0Dmv2bi4/wuyLGumfuM="));
}
@Test
public void encryptByPublicKeyFromFile() throws IllegalAccessException, NoSuchAlgorithmException, InstantiationException, NoSuchMethodException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException, BadPaddingException, InvocationTargetException, IOException, InvalidKeySpecException, IllegalBlockSizeException {
String cipherText = AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_1024.encrypt("a", CryptoUtils.RSA_PUBLIC_KEY_FILE_PATH);
Assert.assertEquals("a", AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_1024.decrypt(cipherText, CryptoUtils.RSA_PRIVATE_KEY_FILE_PATH));
}
@Test
public void encryptByPublicKeyFromCert() throws Exception {
String cipherText = AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_1024.encryptByPublicKeyFromCert("a", certificatePath);
Assert.assertEquals("a", AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_1024.decryptByPrivateKeyFromKeyStore(cipherText, keyStorePath));
}
@Test
public void encryptByPublicKeyFromKeyStore() throws Exception {
String cipherText = AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_1024.encryptByPublicKeyFromKeyStore("a", keyStorePath);
Assert.assertEquals("a", AsymmetricEncryptionAlgorithm.RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_1024.decryptByPrivateKeyFromKeyStore(cipherText, keyStorePath));
}
}
package com.qupeng.crypto.algorithm.oop;
import com.qupeng.crypto.util.CryptoUtils;
import com.qupeng.crypto.util.DigitalCertificationUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.OAEPParameterSpec;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Path;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public enum AsymmetricEncryptionAlgorithm {
RSA_ECB_PKCS1_PADDING_1024("RSA", "ECB", "PKCS1Padding", 1024, 128, TlsRsaPremasterSecretParameterSpec.class),
RSA_ECB_PKCS1_PADDING_2048("RSA", "ECB", "PKCS1Padding", 2048, 256, TlsRsaPremasterSecretParameterSpec.class),
RSA_ECB_OAEP_WITH_SHA_1_AND_MGF1_PADDING_1024("RSA", "ECB", "OAEPWithSHA-1AndMGF1Padding", 1024, 128, OAEPParameterSpec.class),
RSA_ECB_OAEP_WITH_SHA_1_AND_MGF1_PADDING_2048("RSA", "ECB", "OAEPWithSHA-1AndMGF1Padding", 2048, 256, OAEPParameterSpec.class),
RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_1024("RSA", "ECB", "OAEPWithSHA-256AndMGF1Padding", 1024, 128, OAEPParameterSpec.class),
RSA_ECB_OAEP_WITH_SHA_256_AND_MGF1_PADDING_2048("RSA", "ECB", "OAEPWithSHA-256AndMGF1Padding", 2048, 256, OAEPParameterSpec.class);
private String transformation = "";
private String algorithm = "";
private String mode = "";
private String padding = "";
private int secretKeyStrLength = -1;
private int secretKeyBitLength = -1;
private Class<? extends AlgorithmParameterSpec> algorithmParameterSpecClass;
AsymmetricEncryptionAlgorithm(String algorithm, String mode, String padding, int secretKeyBitLength, int secretKeyStrLength, Class<? extends AlgorithmParameterSpec> algorithmParameterSpecClass) {
this.algorithm = algorithm;
this.mode = mode;
this.padding = padding;
this.transformation = String.format("%s/%s/%s", algorithm, mode, padding);
this.secretKeyStrLength = secretKeyStrLength;
this.secretKeyBitLength = secretKeyBitLength;
this.algorithmParameterSpecClass = algorithmParameterSpecClass;
}
// 1 使用秘钥字符串加密
public String encrypt(String plainText, String secretKeyStr) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InvalidKeySpecException, IOException {
return encrypt(plainText, secretKeyStr, null, null);
}
// 1 使用秘钥字符串解密
public String decrypt(String base64Content, String secretKeyStr) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InvalidKeySpecException, IOException {
return decrypt(base64Content, secretKeyStr, null, null);
}
// 2 使用随机数种子字符串加密和指定的随机数算法加密
public String encrypt(String plainText, String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InvalidKeySpecException, IOException {
return encrypt(plainText, null, randomSeedStr, ngAlgorithm);
}
// 2 使用随机数种子字符串加密和指定的随机数算法解密
public String decrypt(String base64Content, String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InvalidKeySpecException, IOException {
return decrypt(base64Content, null, randomSeedStr, ngAlgorithm);
}
// 3 使用随机数种子字符串加密和默认的随机数算法加密
public String encryptByKeyGenerator(String plainText, String randomSeedStr) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InvalidKeySpecException, IOException {
return encrypt(plainText, null, randomSeedStr, null);
}
// 3 使用随机数种子字符串加密和默认的随机数算法解密
public String decryptByKeyGenerator(String base64Content, String randomSeedStr) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InvalidKeySpecException, IOException {
return decrypt(base64Content, null, randomSeedStr, null);
}
// 4 从文件从获取公钥并加密
public String encrypt(String plainText, Path publicKeyFilePath) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InvalidKeySpecException, IOException {
String publicKeyStr = CryptoUtils.readKeyStrFromFile(publicKeyFilePath);
return encrypt(plainText, publicKeyStr, null, null);
}
// 4 从文件中获取私钥并解密
public String decrypt(String base64Content, Path privateKeyFilePath) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, InvalidKeySpecException, IOException {
String privateKeyStr = CryptoUtils.readKeyStrFromFile(privateKeyFilePath);
return decrypt(base64Content, privateKeyStr, null, null);
}
// 5 从公钥证书中获取公钥并加密
public String encryptByPublicKeyFromCert(String plainText, Path publicKeyCertPath) throws Exception {
PublicKey publicKey = CryptoUtils.getPublicKeyFromCA(publicKeyCertPath, "X.509");
return encrypt(plainText, new BASE64Encoder().encode(publicKey.getEncoded()), new BASE64Encoder().encode(publicKey.getEncoded()), null);
}
// 6 从文件从获取公钥并加密
public String encryptByPublicKeyFromKeyStore(String plainText, Path keyStorePath) throws Exception {
PublicKey publicKey = CryptoUtils.getPublicKeyFromKeyStore(keyStorePath, "testing-keys", "123456", "PKCS12");
return encrypt(plainText, new BASE64Encoder().encode(publicKey.getEncoded()), null, null);
}
// 6 从文件中获取私钥并解密
public String decryptByPrivateKeyFromKeyStore(String base64Content, Path keyStorePath) throws Exception {
PrivateKey privateKey = CryptoUtils.getPrivateKeyFromKeyStore(keyStorePath, "testing-keys", "123456", "PKCS12");;
return decrypt(base64Content, new BASE64Encoder().encode(privateKey.getEncoded()), null, null);
}
private String encrypt(String plainText, String secretKeyStr, String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvalidKeySpecException, IOException {
validateParameters(secretKeyStr);
Cipher cipher = Cipher.getInstance(this.transformation);
// 根据参数决定使用密钥字符串还是随机数生成密钥
Key secretKey = getPublicKey(secretKeyStr, randomSeedStr, ngAlgorithm);
// 根据模式决定是否设置向量
setAlgorithmParameterSpec(cipher, secretKey, Cipher.ENCRYPT_MODE);
// 如果是无填充,需要自行填充
byte[] plainTextBytes = setPadding(cipher, plainText);
byte[] encrypted = cipher.doFinal(plainTextBytes);
String cipherText = new BASE64Encoder().encode(encrypted);
System.out.println(String.format("%s(%d) plain text: %s -> cipher text: %s", this.transformation, this.secretKeyBitLength, plainText, cipherText));
return cipherText;
}
private String decrypt(String base64CipherText, String secretKeyStr, String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvalidKeySpecException, IOException {
validateParameters(secretKeyStr);
Cipher cipher = Cipher.getInstance(transformation);
Key secretKey = getPrivateKey(secretKeyStr, randomSeedStr, ngAlgorithm);
setAlgorithmParameterSpec(cipher, secretKey, Cipher.DECRYPT_MODE);
byte[] content = new BASE64Decoder().decodeBuffer(base64CipherText);
byte[] encrypted = cipher.doFinal(content);
String plainText = new String(encrypted).trim();
System.out.println(String.format("%s(%d) cipher text: %s -> plain text: %s", this.transformation, this.secretKeyBitLength, base64CipherText, plainText));
return plainText;
}
private void validateParameters(String secretKeyStr) {
}
private Key getPublicKey(String secretKeyStr, String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
Key secretKey;
if (null == secretKeyStr || secretKeyStr.isEmpty()) {
secretKey = getPublicKeyByGenerator(randomSeedStr, null == ngAlgorithm ? NumberGenerationAlgorithm.SHA1_PRNG : ngAlgorithm);
} else {
secretKey = getPublicKeyByStr(secretKeyStr);
}
return secretKey;
}
private Key getPrivateKey(String secretKeyStr, String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
Key secretKey = null;
if (null == secretKeyStr || secretKeyStr.isEmpty()) {
secretKey = getPrivateKeyByGenerator(randomSeedStr, null == ngAlgorithm ? NumberGenerationAlgorithm.SHA1_PRNG : ngAlgorithm);
} else {
secretKey = getPrivateKeyByStr(secretKeyStr);
}
return secretKey;
}
private byte[] setPadding(Cipher cipher, String plainText) {
byte[] plainTextBytes = plainText.getBytes();
if ("NoPadding".equals(this.padding)) {
byte[] plainTextBytesNoPadding = plainTextBytes;
int blockSize = cipher.getBlockSize();
int length = plainTextBytes.length;
//计算需填充长度
length = length + (blockSize - (length % blockSize));
plainTextBytes = new byte[length];
//填充
System.arraycopy(plainTextBytesNoPadding, 0, plainTextBytes, 0, plainTextBytesNoPadding.length);
}
return plainTextBytes;
}
private void setAlgorithmParameterSpec(Cipher cipher, Key secretKey, int decryptMode) throws InvalidKeyException, InvalidAlgorithmParameterException {
if (OAEPParameterSpec.class == this.algorithmParameterSpecClass) {
cipher.init(decryptMode, secretKey, OAEPParameterSpec.DEFAULT);
} else {
cipher.init(decryptMode, secretKey);
}
}
private Key getPublicKeyByStr(String secretKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
byte[] keyBytes = new BASE64Decoder().decodeBuffer(secretKeyStr);
X509EncodedKeySpec encPubKeySpec = new X509EncodedKeySpec(keyBytes);
PublicKey publicKey = KeyFactory.getInstance(this.algorithm).generatePublic(encPubKeySpec);
return publicKey;
}
private Key getPrivateKeyByStr(String secretKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
byte[] keyBytes = new BASE64Decoder().decodeBuffer(secretKeyStr);
PKCS8EncodedKeySpec encPriKeySpec = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey privateKey = KeyFactory.getInstance(this.algorithm).generatePrivate(encPriKeySpec);
return privateKey;
}
private Key getPublicKeyByGenerator(String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchAlgorithmException {
return getKeyPair(randomSeedStr, ngAlgorithm).getPublic();
}
private Key getPrivateKeyByGenerator(String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchAlgorithmException {
return getKeyPair(randomSeedStr, ngAlgorithm).getPrivate();
}
private KeyPair getKeyPair(String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(this.algorithm);
SecureRandom random = SecureRandom.getInstance(ngAlgorithm.getAlgorithmName());
random.setSeed(randomSeedStr.getBytes());
keyPairGenerator.initialize(this.secretKeyBitLength, random);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
try {
CryptoUtils.writeKeyPairToFile(keyPair, this.algorithm);
} catch (IOException e) {
e.printStackTrace();
}
return keyPair;
}
}
package com.qupeng.crypto.util;
import com.qupeng.crypto.algorithm.oop.NumberGenerationAlgorithm;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.stream.Collectors;
public class CryptoUtils {
public final static Path RSA_PUBLIC_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "rsa-public-key.txt");
public final static Path RSA_PRIVATE_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "rsa-private-key.txt");
public final static Path DSA_PUBLIC_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "dsa-public-key.txt");
public final static Path DSA_PRIVATE_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "dsa-private-key.txt");
static {
Security.addProvider(new BouncyCastleProvider());
}
public static void printAllSecurityProviders() {
for (Provider provider : Security.getProviders())
{
System.out.println("Provider: " + provider.getName() + " (ver " + provider.getVersion() + ")");
}
}
public static void printAllAlgorithmsOfProviders() {
for (Provider provider : Security.getProviders())
{
System.out.println("Provider: " + provider.getName() + " (ver " + provider.getVersion() + ")");
System.out.print(" Algorithms: ");
ArrayList<String> algos = new ArrayList<String>();
for (Provider.Service service : provider.getServices())
{
algos.add(String.format( "%s (%s)", service.getAlgorithm(), service.getType()));
}
java.util.Collections.sort(algos);
String algorsStr = algos.toString();
algorsStr = algorsStr.substring(1, algorsStr.length()-1);
System.out.println(algorsStr);
System.out.println();
}
}
public static String printAllSecurityProvidersInMdTable() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Provider Name|Provider Version|Algorithm Type|Algorithm Name\r\n");
stringBuilder.append("|:-|:-|:-|:-\r\n");
Map<String, Map<String, String>> providers2Algorithms = Arrays.stream(Security.getProviders())
.collect(Collectors.toMap(provider -> provider.getName() + "@" + provider.getVersion(), provider -> provider.getServices().stream().collect(Collectors.toMap(service -> service.getType(), service -> service.getAlgorithm(), (algorithm1, algorithm2) -> algorithm1 + "@" + algorithm2))));
providers2Algorithms.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).forEachOrdered(entryProvider -> {
String[] provider = entryProvider.getKey().split("@");
Map<String, String> algoType2AlgoName = entryProvider.getValue();
int[] rowNumber = {0};
algoType2AlgoName.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).forEachOrdered(entryAlgorithm -> {
StringBuilder algorithmCellStr = new StringBuilder();
int[] numberOfAlgorithm = {1};
Arrays.stream(entryAlgorithm.getValue().split("@")).sorted(String::compareTo).forEachOrdered(algorithm -> {
algorithmCellStr.append(algorithm);
if (0 == numberOfAlgorithm[0] % 1) {
algorithmCellStr.append("<br>");
}
numberOfAlgorithm[0]++;
});
stringBuilder.append(String.format("|%s|%s|%s|%s\r\n", 0 == rowNumber[0] ? provider[0] : "", 0 == rowNumber[0] ? provider[1] : "", entryAlgorithm.getKey(), algorithmCellStr.toString()));
rowNumber[0]++;
});
});
return stringBuilder.toString();
}
public static void writeKeyPairToFile(KeyPair keyPair, String algorithm) throws IOException {
writeKeyPairToFile(keyPair, "DSA".equalsIgnoreCase(algorithm) ? DSA_PUBLIC_KEY_FILE_PATH : RSA_PUBLIC_KEY_FILE_PATH, "DSA".equalsIgnoreCase(algorithm) ? DSA_PRIVATE_KEY_FILE_PATH : RSA_PRIVATE_KEY_FILE_PATH);
}
public static void writeKeyPairToFile(KeyPair keyPair, Path publicKeyFilePath, Path privateKeyFilePath) throws IOException {
writeKeyToFile(keyPair.getPublic(), publicKeyFilePath);
writeKeyToFile(keyPair.getPrivate(), privateKeyFilePath);
}
public static String readPublicKeyFromFile(String algorithm) throws IOException {
return readKeyStrFromFile("DSA".equalsIgnoreCase(algorithm) ? DSA_PUBLIC_KEY_FILE_PATH : RSA_PUBLIC_KEY_FILE_PATH);
}
public static String readPrivateKeyFromFile(String algorithm) throws IOException {
return readKeyStrFromFile("DSA".equalsIgnoreCase(algorithm) ? DSA_PRIVATE_KEY_FILE_PATH : RSA_PRIVATE_KEY_FILE_PATH);
}
public static String readKeyStrFromFile(Path keyFilePath) throws IOException {
try (FileChannel keyFileChannel = FileChannel.open(keyFilePath, StandardOpenOption.READ)) {
byte[] bytes = new byte[0];
ByteBuffer byteBuffer = ByteBuffer.allocate(128);
int readCount = keyFileChannel.read(byteBuffer);
while (0 < readCount) {
byteBuffer.flip();
int length = bytes.length;
bytes = Arrays.copyOf(bytes, bytes.length + readCount);
System.arraycopy(byteBuffer.array(), 0, bytes, length, readCount);
byteBuffer.clear();
readCount = keyFileChannel.read(byteBuffer);
}
String keyStr = new String(bytes);
return keyStr;
}
}
public static void writeKeyToFile(Key key, Path filePath) throws IOException {
byte[] keyBytes = key.getEncoded();
String keyStr = new BASE64Encoder().encode(keyBytes);
if (Files.notExists(filePath)) {
Files.createFile(filePath);
}
try(FileChannel keyFileChannel = FileChannel.open(filePath, StandardOpenOption.WRITE)) {
ByteBuffer byteBuffer = ByteBuffer.allocate(keyStr.getBytes().length);
byteBuffer.put(keyStr.getBytes());
byteBuffer.flip();
keyFileChannel.write(byteBuffer);
}
}
public static PublicKey getPublicKeyByStr(String algorithm, String secretKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
byte[] keyBytes = new BASE64Decoder().decodeBuffer(secretKeyStr);
X509EncodedKeySpec encPubKeySpec = new X509EncodedKeySpec(keyBytes);
PublicKey publicKey = KeyFactory.getInstance(algorithm).generatePublic(encPubKeySpec);
return publicKey;
}
public static PrivateKey getPrivateKeyByStr(String algorithm, String secretKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
byte[] keyBytes = new BASE64Decoder().decodeBuffer(secretKeyStr);
PKCS8EncodedKeySpec encPriKeySpec = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey privateKey = KeyFactory.getInstance(algorithm).generatePrivate(encPriKeySpec);
return privateKey;
}
public static KeyPair getKeyPair(String algorithm, int secretKeyBitLength, String randomSeedStr, NumberGenerationAlgorithm ngAlgorithm) throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
SecureRandom random = SecureRandom.getInstance(ngAlgorithm.getAlgorithmName());
random.setSeed(randomSeedStr.getBytes());
keyPairGenerator.initialize(secretKeyBitLength, random);
return keyPairGenerator.generateKeyPair();
}
public static String wrapSecretKey(String keyString) throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, new SecureRandom("123456".getBytes()));
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.WRAP_MODE, secretKey);
SecretKeySpec key = new SecretKeySpec(keyString.getBytes(), "AES");
byte[] bytes = cipher.wrap(key);
return Hex.encodeHexString(bytes);
}
public static String unwrapSecretKey(String keyString) throws Exception {
byte[] rawKey = Hex.decodeHex(keyString);
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, new SecureRandom("123456".getBytes()));
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.UNWRAP_MODE, secretKey);
SecretKey key = (SecretKey) cipher.unwrap(rawKey, "AES", Cipher.SECRET_KEY);
return new String(key.getEncoded());
}
public static String wrapPrivateKey() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException {
SecureRandom secureRandom = SecureRandom.getInstance(NumberGenerationAlgorithm.SHA1_PRNG.getAlgorithmName());
secureRandom.setSeed("12345".getBytes());
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.WRAP_MODE, secretKey, secureRandom);
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024, secureRandom);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
System.out.println(Hex.encodeHexString(keyPair.getPrivate().getEncoded()));
byte[] keyBytes = cipher.wrap(keyPair.getPrivate());
String wrappedKeyStr = Hex.encodeHexString(keyBytes);
System.out.println(wrappedKeyStr);
return wrappedKeyStr;
}
public static String unwrapPrivateKey(String keyStr) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, DecoderException {
SecureRandom secureRandom = SecureRandom.getInstance(NumberGenerationAlgorithm.SHA1_PRNG.getAlgorithmName());
secureRandom.setSeed("12345".getBytes());
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.UNWRAP_MODE, secretKey, secureRandom);
byte[] keyBytes = Hex.decodeHex(keyStr);
PrivateKey privateKey = (PrivateKey) cipher.unwrap(keyBytes, "RSA", Cipher.PRIVATE_KEY);
return Hex.encodeHexString(privateKey.getEncoded());
}
public static PublicKey getPublicKeyFromCA(Path certificatePath, String certificationType) throws Exception {
CertificateFactory certificateFactory = CertificateFactory.getInstance(certificationType);
try (FileInputStream in = new FileInputStream(certificatePath.toFile())) {
Certificate certificate = certificateFactory.generateCertificate(in);
return certificate.getPublicKey();
}
}
public static PublicKey getPublicKeyFromKeyStore(Path keyStorePath, String alias, String password, String keyStoreType) throws Exception {
try (FileInputStream is = new FileInputStream(keyStorePath.toFile())) {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(is, password.toCharArray());
return keyStore.getCertificate(alias).getPublicKey();
}
}
public static PrivateKey getPrivateKeyFromKeyStore(Path keyStorePath, String alias, String password, String keyStoreType) throws Exception {
try (FileInputStream is = new FileInputStream(keyStorePath.toFile())) {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(is, password.toCharArray());
return (PrivateKey) keyStore.getKey(alias, password.toCharArray());
}
}
}
到了这里,关于Java加解密(四)非对称加密的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!