【Java小工匠聊密码学】--非对称加密--ElGamal

时间:2022-06-06
本文章向大家介绍【Java小工匠聊密码学】--非对称加密--ElGamal,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1、什么是ElGamal

  ElGamal算法,是一种较为常见的加密算法,它是基于1985年提出的公钥密码体制和椭圆曲线加密体系。既能用于数据加密也能用于数字签名,其安全性依赖于计算有限域上离散对数这一难题。在加密过程中,生成的密文长度是明文的两倍,且每次加密后都会在密文中生成一个随机数K,在密码中主要应用离散对数问题的几个性质:求解离散对数(可能)是困难的,而其逆运算指数运算可以应用平方-乘的方法有效地计算。也就是说,在适当的群G中,指数函数是单向函数。

2、ELGamal算法实现

package lzf.cipher.bc;

import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.spec.DHParameterSpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

/**
 * @author Java小工匠
 */
public class BCElGamalUtils {

    public static final String ELGAMAL = "ElGamal";

    public static KeyPair initKey() {
        try {
            // 加入对BouncyCastle支持
            Security.addProvider(new BouncyCastleProvider());
            // 初始化参数生成器
            AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance(ELGAMAL, "BC");
            apg.init(256);
            // 生成算法参数
            AlgorithmParameters params = apg.generateParameters();
            // 构建参数
            DHParameterSpec elParams = (DHParameterSpec) params.getParameterSpec(DHParameterSpec.class);
            // 实例化密钥生成器
            KeyPairGenerator kpg = KeyPairGenerator.getInstance(ELGAMAL);
            // 初始化密钥对生成器
            kpg.initialize(elParams, new SecureRandom());
            KeyPair keyPair = kpg.generateKeyPair();
            return keyPair;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 获取公钥
    public static byte[] getPublicKey(KeyPair keyPair) {
        byte[] bytes = keyPair.getPublic().getEncoded();
        return bytes;
    }

    // 获取公钥
    public static String getPublicKeyStr(KeyPair keyPair) {
        byte[] bytes = keyPair.getPublic().getEncoded();
        return Hex.toHexString(bytes);
    }

    // 获取私钥
    public static byte[] getPrivateKey(KeyPair keyPair) {
        byte[] bytes = keyPair.getPrivate().getEncoded();
        return bytes;
    }

    // 获取私钥
    public static String getPrivateKeyStr(KeyPair keyPair) {
        byte[] bytes = keyPair.getPrivate().getEncoded();
        return Hex.toHexString(bytes);
    }

    // 公钥加密
    public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        // 实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(ELGAMAL);
        // X509转公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        // 产生公钥
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
        // 数据加密
        Cipher cipher = Cipher.getInstance(ELGAMAL);
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }

    // 私钥解密
    public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(ELGAMAL);
        // 生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        // 数据解密
        Cipher cipher = Cipher.getInstance(ELGAMAL);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    public static void main(String[] args) throws Exception {
        // 生成密钥对
        KeyPair keyPair = initKey();
        byte[] publicKey = getPublicKey(keyPair);
        byte[] privateKey = getPrivateKey(keyPair);
        System.out.println("公钥:" + Hex.toHexString(publicKey));
        System.out.println("私钥:" + Hex.toHexString(privateKey));
        String str = "JAVA小工匠";
        System.out.println("原文:" + str);
        byte[] encryptData = encrypt(str.getBytes(), publicKey);
        System.out.println("加密数据:" + Hex.toHexString(encryptData));
        byte[] decryptData = decrypt(encryptData, privateKey);
        System.out.println("解密数据:" + new String(decryptData));
    }
}

3、ELGamal 常见问题 如果上述代码出现 Illegal key size or default parameters 这样的错误。 因为某些国家的进口管制限制,Java发布的运行环境包中的加解密有一定的限制。 解决办法 (1)下载策略文件 官方网站提供了JCE无限制权限策略文件的下载,或者可以查看JRE_HOME/lib/security/policy/unlimited 是否存在 local_policy.jar 和US_export_policy.jar JDK6的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

JDK7的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html

JDK8的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html (2) 拷贝JAR 包 将US_export_policy.jar和 local_policy.jar 拷贝的 JRE_HOME/lib/security 目录中。