非對稱加密
1 定義
非對稱加密算法需要兩個密鑰:公開密鑰(publickey:簡稱公鑰)和私有密鑰(privatekey:簡稱私鑰)。公鑰與私鑰是一對,如果用公鑰對數(shù)據(jù)進行加密,只有用對應(yīng)的私鑰才能解密。因為加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。
2 特點
- 也稱公開密鑰加密,算法需要兩個密鑰,其中一個可以公開,并且通過公開的密鑰無法推導(dǎo)出對應(yīng)的私鑰
- 算法復(fù)雜度相對對稱加密算法高,所以計算相對較慢
- 密鑰的保密性較好,因為公鑰可以公開,免去了交換密鑰的需求
3 使用場景
由于安全性較好,并且密鑰可以公開,無交換過程泄密的風(fēng)險,因此非對此密鑰算法被廣泛使用,比如SSH、HTTPS、電子證書、數(shù)字簽名、加密通訊等領(lǐng)域。
公鑰既可以進行加密,也可以解密,私鑰也是一樣,用于支持不同場景:
- 使用私鑰加密,公鑰解密
這種就是數(shù)字簽名的原理,用于讓所有公鑰所有者驗證私鑰所有者的身份并且用來防止私鑰所有者發(fā)布的內(nèi)容被篡改(只有唯一的一方持有私鑰,加密者一定是唯一確定的,除非私鑰泄露了),但是不用來保證內(nèi)容不被他人獲得(公鑰是公開的,所有持有公鑰的一方都能解密這段密文) - 用公鑰加密,私鑰解密
這種就是數(shù)據(jù)加密,用于公鑰所有者向私鑰所有者發(fā)布信息,這個信息可能被他人篡改(因為持有公鑰的一方都能生成一段新的密文,可以替換掉原始密文),但是無法被他人獲得(只有私鑰所有者一人能夠解密這段密文) - 甲方用公鑰-乙加密,私鑰-甲加密,乙方用公鑰-甲解密,私鑰-乙解密
如果甲想給乙發(fā)一個安全的保密的數(shù)據(jù),那么應(yīng)該甲乙各自有一個私鑰,甲先用乙的公鑰加密這段數(shù)據(jù),再用自己的私鑰加密這段加密后的數(shù)據(jù),最后再發(fā)給乙,這樣確保了內(nèi)容即不會被讀取,也不會被篡改。
4 常用的非對稱加密算法
1977年,三位數(shù)學(xué)家Rivest、Shamir 和 Adleman 設(shè)計了一種算法,可以實現(xiàn)非對稱加密。這種算法用他們?nèi)齻€人的名字命名,叫做RSA算法,RSA算法從被發(fā)明至今一直是最廣為使用的"非對稱加密算法"。其他場景的算法還有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 算法調(diào)用示例
下面的代碼將JDK提供的幾種RSA加密算法用枚枚舉類進行了封裝,調(diào)用encrypt()和decrypt()方法可以實現(xiàn)加密和解。encrypt()和decrypt()的幾個重載方法分別支持了不同秘鑰生成方式(秘鑰字符串,隨機種子生成秘鑰,從文件讀取密鑰字符串,從數(shù)字證書讀取公鑰,從密鑰庫讀取公鑰,從密鑰庫讀取私鑰),設(shè)置算法參數(shù)的類型(AlgorithmParameterSpec)。文章來源:http://www.zghlxwxcb.cn/news/detail-499224.html
首先使用ktool生成密鑰庫,并導(dǎo)出公鑰證書:文章來源地址http://www.zghlxwxcb.cn/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 使用隨機數(shù)種子字符串加密和指定的隨機數(shù)算法加密
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 使用隨機數(shù)種子字符串加密和指定的隨機數(shù)算法解密
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 使用隨機數(shù)種子字符串加密和默認(rèn)的隨機數(shù)算法加密
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 使用隨機數(shù)種子字符串加密和默認(rèn)的隨機數(shù)算法解密
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);
// 根據(jù)參數(shù)決定使用密鑰字符串還是隨機數(shù)生成密鑰
Key secretKey = getPublicKey(secretKeyStr, randomSeedStr, ngAlgorithm);
// 根據(jù)模式?jīng)Q定是否設(shè)置向量
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());
}
}
}
到了這里,關(guān)于Java加解密(四)非對稱加密的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!