Java加解密(四)非对称加密

这篇具有很好参考价值的文章主要介绍了Java加解密(四)非对称加密。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

非对称加密

1 定义

非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

2 特点

  1. 也称公开密钥加密,算法需要两个密钥,其中一个可以公开,并且通过公开的密钥无法推导出对应的私钥
  2. 算法复杂度相对对称加密算法高,所以计算相对较慢
  3. 密钥的保密性较好,因为公钥可以公开,免去了交换密钥的需求

3 使用场景

由于安全性较好,并且密钥可以公开,无交换过程泄密的风险,因此非对此密钥算法被广泛使用,比如SSH、HTTPS、电子证书、数字签名、加密通讯等领域。
公钥既可以进行加密,也可以解密,私钥也是一样,用于支持不同场景:

  1. 使用私钥加密,公钥解密
    这种就是数字签名的原理,用于让所有公钥所有者验证私钥所有者的身份并且用来防止私钥所有者发布的内容被篡改(只有唯一的一方持有私钥,加密者一定是唯一确定的,除非私钥泄露了),但是不用来保证内容不被他人获得(公钥是公开的,所有持有公钥的一方都能解密这段密文)
  2. 用公钥加密,私钥解密
    这种就是数据加密,用于公钥所有者向私钥所有者发布信息,这个信息可能被他人篡改(因为持有公钥的一方都能生成一段新的密文,可以替换掉原始密文),但是无法被他人获得(只有私钥所有者一人能够解密这段密文)
  3. 甲方用公钥-乙加密,私钥-甲加密,乙方用公钥-甲解密,私钥-乙解密
    如果甲想给乙发一个安全的保密的数据,那么应该甲乙各自有一个私钥,甲先用乙的公钥加密这段数据,再用自己的私钥加密这段加密后的数据,最后再发给乙,这样确保了内容即不会被读取,也不会被篡改。

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)。

首先使用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模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • PHP非对称与对称双向加密解密的方式

    目录 RSA非对称加密解密: 什么是RSA非对称加密解密解析: 解析: 为什么使用: 有什么优点: DEMO: AES、DES、3DES等对称加密解密: 解析: 为什么使用: 有什么优点: DEMO: 什么是RSA非对称加密解密解析: 解析: RSA非对称加密解密算法是一种广泛应用于信息安全领域的加密算法。它不同于

    2024年02月07日
    浏览(74)
  • 几种PHP对称加密解密源码

    最近搞一点东西要用到对称加密,于是在网上找到一个不错的对称加密方法,分享给大家。 安全URL编码 UTF8字符串加密 别的方法 auth_code优化版

    2024年01月18日
    浏览(61)
  • 使用非对称加密(RSA) 实现前端加密后端解密

    数据加密方式有: 单向加密、对称加密、非对称加密、加密盐、散列函数、数字签名。 1、单向加密 单向加密通过对数据进行摘要计算生成密文,密文不可逆推还原。只能加密,不能解密,常用于提取数据的指纹信息以此来验证数据的完整性。但是会引发雪崩效应(雪崩效应

    2024年02月08日
    浏览(64)
  • AES对称加密实战——前端js加密后端python解密

    高级加密标准(AES, Advanced Encryption Standard),是一种最常见的对称加密算法 。其加密流程如下图所示,发送方通过密钥对明文加密后进行网络传输,接收方用同样的密钥将密文解密。在前后端通讯场景中,可利用AES算法对用户密码进行加密后传输,防止被抓包而造成密码泄露。

    2024年02月04日
    浏览(59)
  • Java代码实现RSA算法加密解密文件功能

    底层算法不做赘述,想要了解自行百度。 RSA属于非对称加密,非对称加密有公钥和私钥两个概念,私钥自己拥有,不能给别人,公钥公开。根据应用的不同,我们可以选择使用不同的密钥加密: 签名:使用私钥加密,公钥解密。用于让所有公钥所有者验证私钥所有者的身份

    2024年02月12日
    浏览(56)
  • uni-app和springboot完成前端后端对称加密解密流程

    概述 使用对称加密的方式实现。 前端基于crypto-js。 uni-app框架中是在uni.request的基础上,在拦截器中处理的。 springboot在Filter中完成解密工作。 uni-app 项目中引入crypto-js。 加密方法 解密方法 request拦截器 备注 使用encodeURIComponent方法是为了处理 字符“+”,这个对应java解密的

    2024年02月13日
    浏览(52)
  • 基于JAVA的RC4加密解密算法循环实现

           RC4算法是一种对称加密算法,所谓对称加密,就是加密和解密的过程是一样的,加密和解密均采用同一把密钥。RC4算法的特点是算法简单,执行速度快安全性比较高并且密钥长度是可变的,可变范围为1-256字节(8-2048比特)。让它如此广泛分布和使用的主要因素是它不可

    2024年02月04日
    浏览(52)
  • 国密SM2算法(JS加密,C#、Java解密)

    常见的渗透测试会将网站登录时密码使用明文传输视为风险。推荐使用国密算法或者RSA算法对密码进行加密传输。 RSA加密(JS加密,C#、Java解密)请参考《RSA对称加密(JS加密,C#、Java解密)》​​​​​​ 本文描述国密SM2算法的实现。 一、工作原理 前端js使用公钥进行加密

    2024年02月02日
    浏览(52)
  • C# 实现 国密SM4/ECB/PKCS7Padding对称加密解密

    C# 实现 国密SM4/ECB/PKCS7Padding对称加密解密,为了演示方便本问使用的是Visual Studio 2022 来构建代码的 1、新建项目,之后选择 项目 鼠标右键选择  管理NuGet程序包管理,输入  BouncyCastle 回车 添加BouncyCastle程序包 2、代码如下:CBC模式 代码如下:ECB模式 3、运行 4、SM4密码算法

    2024年02月11日
    浏览(58)
  • 从加密到签名:如何使用Java实现高效、安全的RSA加解密算法?

    目录 1. 接下来让小编给您们编写实现代码!请躺好 ☺ 1.1 配置application.yml文件 1.2 RSA算法签名工具类 1.3  RSA算法生成签名以及效验签名测试 1.4 RSA算法生成公钥私钥、加密、解密工具类 1.5 RSA算法加解密测试 我们为什么要使用RSA算法来进行加解密?  RSA 加密算法是一种非对

    2024年02月12日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包