Java 实现非对称加密

文章目录

  • Java 实现非对称加密
    • DH(Diffie-Hellman)密钥交换算法
    • RSA 基于因子分解
    • ElGamal 基于离散对数
    • 参考

Java 实现非对称加密

DH(Diffie-Hellman)密钥交换算法

密钥长度 默认 实现方
512~1024(64倍数) 1024 JDK

Java 实现非对称加密_第1张图片

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Objects;

/**
 * 基于 DH 算法的非对称加密工具类
 *
 * @Author LeifChen
 * @Date 2018-11-30
 */
public class DhUtils {

    static final String DH = "DH";
    static final String DES = "DES";
    static final String STR = "Hello LeifChen";

    public static void jdkDH() {
        try {
            // 1.发送方构建公钥私钥
            KeyPair senderKeyPair = generateSenderPublicKey();
            // 2.发送方发布公钥
            byte[] senderPublicKeyBytes = senderKeyPair.getPublic().getEncoded();
            // 3.接收方构建公钥私钥->接收方通过发送方公钥构建公钥私钥
            KeyPair receiverKeyPair = generateReceiverPublicKey(senderPublicKeyBytes);
            // 4.接收方发布公钥
            byte[] receiverPublicKeyBytes = receiverKeyPair.getPublic().getEncoded();
            // 5.接收方构建对称加密秘钥->依据发送方公钥和接收方公钥私钥构建
            SecretKey receiverDESKey = generateSecretKey(receiverKeyPair, senderPublicKeyBytes);
            // 6.发送方构建对称加密秘钥->依据接收方公钥和发送方公钥私钥构建
            SecretKey senderDESKey = generateSecretKey(senderKeyPair, receiverPublicKeyBytes);

            if (Objects.equals(receiverDESKey, senderDESKey)) {
                System.out.println("双方密钥相同");
            }

            // 7.发送方加密
            Cipher cipher = Cipher.getInstance(DES);
            cipher.init(Cipher.ENCRYPT_MODE, senderDESKey);
            byte[] result = cipher.doFinal(STR.getBytes());
            System.out.println("JDK DH Encrypt: " + Base64.encodeBase64String(result));
            // 8.接收方解密
            cipher.init(Cipher.DECRYPT_MODE, receiverDESKey);
            result = cipher.doFinal(result);
            System.out.println("JDK DH Decrypt: " + new String(result));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送方构建密钥
     *
     * @return 构建完的公钥私钥
     * @throws NoSuchAlgorithmException
     */
    private static KeyPair generateSenderPublicKey() throws NoSuchAlgorithmException {
        KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance(DH);
        senderKeyPairGenerator.initialize(512);
        return senderKeyPairGenerator.generateKeyPair();
    }

    /**
     * 依据发送方公钥构建接收方公钥私钥
     *
     * @param senderPublicKey 发送方公钥
     * @return 接收方公钥私钥
     * @throws Exception
     */
    private static KeyPair generateReceiverPublicKey(byte[] senderPublicKey) throws Exception {
        KeyFactory receiverKeyFactory = KeyFactory.getInstance(DH);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKey);
        PublicKey receiverPublicKey = receiverKeyFactory.generatePublic(x509EncodedKeySpec);
        DHParameterSpec dhParameterSpec = ((DHPublicKey) receiverPublicKey).getParams();
        KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance(DH);
        receiverKeyPairGenerator.initialize(dhParameterSpec);
        return receiverKeyPairGenerator.generateKeyPair();
    }

    /**
     * 使用自己的公钥私钥与对方的公钥构建 对称密钥
     *
     * @param keyPair        自己的公钥私钥
     * @param publicKeyBytes 对方的公钥
     * @return 本地对称加密密钥
     * @throws Exception
     */
    private static SecretKey generateSecretKey(KeyPair keyPair, byte[] publicKeyBytes) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(DH);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        KeyAgreement keyAgreement = KeyAgreement.getInstance(DH);
        keyAgreement.init(keyPair.getPrivate());
        keyAgreement.doPhase(publicKey, true);
        return keyAgreement.generateSecret(DES);
    }
}
  • java.security.NoSuchAlgorithmException: Unsupported secret key algorithm: DES 错误
    由于 JDK 版本不同,在 Java 8 update 161 版本以后就会出现此问题,根本原因还是 DH 密钥长度至少为 512 位,而 DES 算法密钥没有这么长,密钥长度不一致引起的。
    解决方法:配置JVM的系统变量:-Djdk.crypto.KeyAgreement.legacyKDF=true

Java 实现非对称加密_第2张图片

RSA 基于因子分解

  1. 支持公钥加密、私钥解密
  2. 支持私钥加密、公钥解密
密钥长度 默认 工作方式 填充方式 实现方
512~65536(64整数倍) 1024 ECB NoPadding
PKCS1Padding
OAEPWITHMD5AndMGF1Pading
OAEPWITHSHA1AndMGF1Pading
OAEPWITHSHA256AndMGF1Pading
OAEPWITHSHA384AndMGF1Pading
OAEPWITHSHA512AndMGF1Pading
JDK
512~65536(64整数倍) 2048 NONE NoPadding
PKCS1Padding
OAEPWITHMD5AndMGF1Pading
OAEPWITHSHA1AndMGF1Pading
OAEPWITHSHA224AndMGF1Pading
OAEPWITHSHA256AndMGF1Pading
OAEPWITHSHA384AndMGF1Pading
OAEPWITHSHA512AndMGF1Pading
ISO9796-1Padding
BC

Java 实现非对称加密_第3张图片

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 基于 RSA 算法的非对称加密工具类
 *
 * @Author LeifChen
 * @Date 2018-11-30
 */
public class RsaUtils {
    static final String RSA = "RSA";
    static final String STR = "Hello LeifChen";

    public static void jdkRSA() {
        try {
            // 构建密钥对
            KeyPair keyPair = generateSenderPublicKey();
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();

            // 1.私钥加密、公钥解密——加密
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] result = cipher.doFinal(STR.getBytes());
            System.out.println("私钥加密、公钥解密——加密:" + Base64.encodeBase64String(result));

            // 2.私钥加密、公钥解密——解密
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            keyFactory = KeyFactory.getInstance(RSA);
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            result = cipher.doFinal(result);
            System.out.println("私钥加密、公钥解密——解密:" + new String(result));


            // 3.公钥加密、私钥解密——加密
            x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            keyFactory = KeyFactory.getInstance(RSA);
            publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            result = cipher.doFinal(STR.getBytes());
            System.out.println("公钥加密、私钥解密——加密:" + Base64.encodeBase64String(result));

            // 4.公钥加密、私钥解密——解密
            pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
            keyFactory = KeyFactory.getInstance(RSA);
            privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            result = cipher.doFinal(result);
            System.out.println("公钥加密、私钥解密——解密:" + new String(result));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 构建密钥对
     *
     * @return 构建完的公钥私钥
     * @throws NoSuchAlgorithmException
     */
    private static KeyPair generateSenderPublicKey() throws NoSuchAlgorithmException {
        KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance(RSA);
        senderKeyPairGenerator.initialize(512);
        return senderKeyPairGenerator.generateKeyPair();
    }
}

ElGamal 基于离散对数

  • 只支持公钥加密、私钥解密
密钥长度 默认 工作方式 填充方式 实现方
160~16384(8整数倍) 1024 ECB、NONE NoPadding
PKCS1Padding
OAEPWITHMD5AndMGF1Pading
OAEPWITHSHA1AndMGF1Pading
OAEPWITHSHA224AndMGF1Pading
OAEPWITHSHA256AndMGF1Pading
OAEPWITHSHA384AndMGF1Pading
OAEPWITHSHA512AndMGF1Pading
ISO9796-1Padding
BC

Java 实现非对称加密_第4张图片

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.DHParameterSpec;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 基于 ElGamal 算法的非对称加密工具类
 *
 * @Author LeifChen
 * @Date 2018-11-30
 */
public class ElGamalUtils {

    static final String ELGAMAL = "ElGamal";
    static final String STR = "Hello LeifChen";

    public static void bcElGamal() {
        Security.addProvider(new BouncyCastleProvider());

        try {
            AlgorithmParameterGenerator algorithmParameterGenerator = AlgorithmParameterGenerator.getInstance(ELGAMAL);
            System.out.println(algorithmParameterGenerator.getProvider());
            algorithmParameterGenerator.init(256);
            AlgorithmParameters algorithmParameters = algorithmParameterGenerator.generateParameters();
            DHParameterSpec dhParameterSpec = algorithmParameters.getParameterSpec(DHParameterSpec.class);

            // 构建密钥对
            KeyPair keyPair = generateSenderPublicKey(dhParameterSpec);
            PublicKey elGamalPublicKey = keyPair.getPublic();
            PrivateKey elGamalPrivateKey = keyPair.getPrivate();

            // 公钥加密、私钥解密——加密
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(elGamalPublicKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance(ELGAMAL);
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] result = cipher.doFinal(STR.getBytes());
            System.out.println("公钥加密、私钥解密——加密:" + Base64.encodeBase64String(result));

            // 公钥加密、私钥解密——解密
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(elGamalPrivateKey.getEncoded());
            keyFactory = KeyFactory.getInstance(ELGAMAL);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            result = cipher.doFinal(result);
            System.out.println("公钥加密、私钥解密——解密:" + new String(result));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 构建密钥对
     *
     * @return 构建完的公钥私钥
     * @throws NoSuchAlgorithmException
     */
    private static KeyPair generateSenderPublicKey(DHParameterSpec dhParameterSpec) throws Exception {
        KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance(ELGAMAL);
        senderKeyPairGenerator.initialize(dhParameterSpec, new SecureRandom());
        return senderKeyPairGenerator.generateKeyPair();
    }
}

参考

  1. GitHub
  2. JAVA实现非对称加密

你可能感兴趣的:(【Java】)