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

目录
  • 非对称加密
  • * 1 定义
    
    • 2 特点
    • 3 使用场景
    • 4 常用的非对称加密算法
    • 5 JDK支持的非对称加密算法
    • 6 Bouncy Castle 支持的非对称加密算法
    • 7 算法调用示例

非对称加密

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生成密钥库,并导出公钥证书:

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());
        }
    }
}

最后

从时代发展的角度看,网络安全的知识是学不完的,而且以后要学的会更多,同学们要摆正心态,既然选择入门网络安全,就不能仅仅只是入门程度而已,能力越强机会才越多。

因为入门学习阶段知识点比较杂,所以我讲得比较笼统,大家如果有不懂的地方可以找我咨询,我保证知无不言言无不尽,需要相关资料也可以找我要,我的网盘里一大堆资料都在吃灰呢。

干货主要有:

①1000+CTF历届题库(主流和经典的应该都有了)

②CTF技术文档(最全中文版)

③项目源码(四五十个有趣且经典的练手项目及源码)

④ CTF大赛、web安全、渗透测试方面的视频(适合小白学习)

⑤ 网络安全学习路线图(告别不入流的学习)

⑥ CTF/渗透测试工具镜像文件大全

⑦ 2023密码学/隐身术/PWN技术手册大全

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

扫码领取

学习网络安全技术的方法无非三种:

第一种是报网络安全专业,现在叫网络空间安全专业,主要专业课程:程序设计、计算机组成原理原理、数据结构、操作系统原理、数据库系统、 计算机网络、人工智能、自然语言处理、社会计算、网络安全法律法规、网络安全、内容安全、数字取证、机器学习,多媒体技术,信息检索、舆情分析等。

第二种是自学,就是在网上找资源、找教程,或者是想办法认识一-些大佬,抱紧大腿,不过这种方法很耗时间,而且学习没有规划,可能很长一段时间感觉自己没有进步,容易劝退。

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

第三种就是去找培训。

image.png

接下来,我会教你零基础入门快速入门上手网络安全。

网络安全入门到底是先学编程还是先学计算机基础?这是一个争议比较大的问题,有的人会建议先学编程,而有的人会建议先学计算机基础,其实这都是要学的。而且这些对学习网络安全来说非常重要。但是对于完全零基础的人来说又或者急于转行的人来说,学习编程或者计算机基础对他们来说都有一定的难度,并且花费时间太长。

第一阶段:基础准备 4周~6周

这个阶段是所有准备进入安全行业必学的部分,俗话说:基础不劳,地动山摇
image.png

第二阶段:web渗透

学习基础 时间:1周 ~ 2周:

① 了解基本概念:(SQL注入、XSS、上传、CSRF、一句话木马、等)为之后的WEB渗透测试打下基础。
② 查看一些论坛的一些Web渗透,学一学案例的思路,每一个站点都不一样,所以思路是主要的。
③ 学会提问的艺术,如果遇到不懂得要善于提问。
image.png

配置渗透环境 时间:3周 ~ 4周:

① 了解渗透测试常用的工具,例如(AWVS、SQLMAP、NMAP、BURP、中国菜刀等)。
② 下载这些工具无后门版本并且安装到计算机上。
③ 了解这些工具的使用场景,懂得基本的使用,推荐在Google上查找。

渗透实战操作 时间:约6周:

① 在网上搜索渗透实战案例,深入了解SQL注入、文件上传、解析漏洞等在实战中的使用。
② 自己搭建漏洞环境测试,推荐DWVA,SQLi-labs,Upload-labs,bWAPP。
③ 懂得渗透测试的阶段,每一个阶段需要做那些动作:例如PTES渗透测试执行标准。
④ 深入研究手工SQL注入,寻找绕过waf的方法,制作自己的脚本。
⑤ 研究文件上传的原理,如何进行截断、双重后缀欺骗(IIS、PHP)、解析漏洞利用(IIS、Nignix、Apache)等,参照:上传攻击框架。
⑥ 了解XSS形成原理和种类,在DWVA中进行实践,使用一个含有XSS漏洞的cms,安装安全狗等进行测试。
⑦ 了解一句话木马,并尝试编写过狗一句话。
⑧ 研究在Windows和Linux下的提升权限,Google关键词:提权
image.png
以上就是入门阶段

第三阶段:进阶

已经入门并且找到工作之后又该怎么进阶?详情看下图
image.png

给新手小白的入门建议:
新手入门学习最好还是从视频入手进行学习,视频的浅显易懂相比起晦涩的文字而言更容易吸收,这里我给大家准备了一套网络安全从入门到精通的视频学习资料包免费领取哦!

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

  • 26
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值