非对称加密算法之ElGamal算法

1. 算法概述

ElGamal算法和ECC算法基于离散对数问题建立。与典型非对称加密算法RSA算法相比,ElGamal算法则被称为常用非对称加密算法。

ElGamal既可用于加密,又可用于数字签名,是除RSA算法外最具代表性的公钥加密算法之一。

ElGamal算法就有较好的安全性,被广发应用。著名的美国数字签名标准(Digital Signature Standard, DSS)就是采用ElGamal签名方案的一种变形——DSA(Digital Signature Algorithm)。

缺点:
ElGamal的密文会成倍扩张。

2. 模型分析

Java6中没有提供ElGamal算法, 但是Bouncy Castle中对ElGamal算法进行了实现。ElGamal算法在构建密钥时的操作流程几乎和RSA算法完全一致。所不同的是RSA中是Alice构建密钥, 而在ElGamal中,Bob成了密钥构建方。假设的消息模型如下:
Alice为消息发送方,Bob为消息接收方,双方在消息发送前已将ElGamal算法作为消息传递的加密算法。

ElGamal加密算法流程图
在这里插入图片描述

  1. 构建并发布密钥

1、2步骤为构建密钥流程

  1. 使用密钥进行加密消息的交互

3、4、5为使用密钥进行加密消息交互

Bouncy Castle提供的ElGamal算法实现遵循 “公钥加密, 私钥解密”的加密/解密方式。

3. 代码实现

Bouncy Castle对ElGamal算法具体实现细节如下:

算法密钥长度密钥默认长度工作模式填充模式备注
ElGamal160~16384位(密钥长度为8的整数倍)1024ECB、NONENoPadding、PKCS1Padding、OAEPWithMD5AndMGF1Padding、OAEPWithSHA1AndMGF1Padding、OAEPWithSHA224AndMGF1Padding、OAEPWithSHA256AndMGF1Padding、OAEPWithSHA384AndMGF1Padding、OAEPWithSHA512AndMGF1Padding、ISO9796-1PaddingBouncy Castle实现

3.1 算法实现

package com.calvin.android.demo2.secrity;

import android.util.Log;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

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

/**
 * Author:cl
 * Email:lhzheng@grandstream.cn
 * Date:20-10-20
 */
public class ElGamalCoder {
    //非对称加密密钥算法
    public static final String KEY_ALGORITHM = "ElGamal";

    private static final int KEY_SIZE = 256;
    private static final String PUBLIC_KEY = "ElGamalPublicKey";
    private static final String PRIVATE_KEY = "ElGamalPrivateKey";

    /**
     * 私钥解密
     * @param data 待解密数据
     * @param key 私钥
     * @return byte[] 解密数据
     * @throws Exception 异常
     */
    public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {

        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM );
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 私钥加密
     * @param data 待加密数据
     * @param key 私钥
     * @return byte[] 加密数据
     * @throws Exception 异常
     */
    public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {

        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥解密
     * @param data 待解密数据
     * @param key 公钥
     * @return byte[] 解密数据
     * @throws Exception 异常
     */
    public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {
        //取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成公钥
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        //对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥加密
     * @param data 待加密数据
     * @param key 公钥
     * @return byte[] 加密数据
     * @throws Exception 异常
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {
        //取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        //生成公钥
        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
        //对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    private static final String TAG = "ElGamalCoder";

    public static Map<String, Object> initKey() throws Exception {

        //实例化BC Provider, Android系统支持BC Provider, 这里将系统可能是旧的版本去掉,加入新版本的BC Provider
        Provider bcProvider = new BouncyCastleProvider();
        Security.removeProvider("BC");
        Security.addProvider(bcProvider);

		/**
        Provider[] providers = Security.getProviders();
        for (Provider provider: providers){
            Log.d(TAG, "provider name = "+provider);

            for (Map.Entry<Object, Object> entry: provider.entrySet()){
                Log.d(TAG, "\t "+entry.getKey()+", "+entry.getValue());
            }
        }
		**/

        AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM, bcProvider);
        //初始化算法参数生成器
        apg.init(KEY_SIZE);
        //生成算法参数
        AlgorithmParameters algorithmParameters = apg.generateParameters();
        //构建参数材料
        DHParameterSpec elParams = (DHParameterSpec)algorithmParameters.getParameterSpec(DHParameterSpec.class);
        //实例化密钥对生成器
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化密钥对生辰其
        keyPairGen.initialize(elParams,new SecureRandom());
        //生成密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();
        //公钥
        PublicKey publicKey = keyPair.getPublic();
        //私钥
        PrivateKey privateKey = keyPair.getPrivate();
        //封装密钥
        Map<String, Object> keyMap = new HashMap<>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    public static byte[] getPublicKey(Map<String, Object> keyMap){

        return  ((Key)keyMap.get(PUBLIC_KEY)).getEncoded();
    }

    public static byte[] getPrivateKey(Map<String, Object> keyMap){
        return  ((Key)keyMap.get(PRIVATE_KEY)).getEncoded();

    }
}

3.2 测试代码

@Test
    public void testElGamal() throws Exception {
        Map<String, Object> keyMap = ElGamalCoder.initKey();
        //公钥
         byte[] elgamalPubKey = ElGamalCoder.getPublicKey(keyMap);
        //私钥
         byte[] elgamalpriKey = ElGamalCoder.getPrivateKey(keyMap);

        System.out.println("公钥:\t"+ Base64.encodeToString(elgamalPubKey, Base64.DEFAULT));
        System.out.println("私钥:\t"+ Base64.encodeToString(elgamalpriKey, Base64.DEFAULT));
        String inputStr = "ElGamal加密";
        byte[] data = inputStr.getBytes();
        System.out.println("原文:\t"+ inputStr);
        byte[] encodedData = ElGamalCoder.encryptByPublicKey(data, elgamalPubKey);
        System.out.println("加密后:\t"+ Base64.encodeToString(encodedData,Base64.DEFAULT));
        byte[] decodedData = ElGamalCoder.decryptByPrivateKey(encodedData, elgamalpriKey);
        String outputStr = new String(decodedData);
        System.out.println("解密后:\t"+ outputStr);
        assertEquals(inputStr,outputStr);

    }

3.3 运行结果

2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: 公钥:	MHcwUAYGKw4HAgEBMEYCIQD/GaVs/HmUpVVOtSF8C0t/OcPNEHO83sjCdvdhkBM5fwIhAKkFaKSP
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: nrJIz2duJFVY+kEstf31SVuOlLmyt93MghofAyMAAiAKp+k1o2R5ZlBcUvOGwVPl4xtbNjNM6yHi
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: 4lD2+/1Omw==
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: 私钥:	MHoCAQAwUAYGKw4HAgEBMEYCIQD/GaVs/HmUpVVOtSF8C0t/OcPNEHO83sjCdvdhkBM5fwIhAKkF
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: aKSPnrJIz2duJFVY+kEstf31SVuOlLmyt93MghofBCMCIQDQXbdvrqqfhkLAfMEGvsLtbawlxsg+
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: wydVKsyJKgZpyg==
2020-10-20 17:02:17.013 11052-11067/com.calvin.android.demo2 I/System.out: 原文:	ElGamal加密
2020-10-20 17:02:17.019 11052-11067/com.calvin.android.demo2 I/System.out: 加密后:	Rx58tvdX4HHKSlAFjTAxRnB0UwZL3L2IVzeQ+KlG7MuBkNRn7hAQ4KKLi/tgTmYDmDsia7VVDEbU
2020-10-20 17:02:17.019 11052-11067/com.calvin.android.demo2 I/System.out: pLGxfKSoHw==
2020-10-20 17:02:17.021 11052-11067/com.calvin.android.demo2 I/System.out: 解密后:	ElGamal加密
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvin880828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值