• ElGamal算法进行加密和解密的基本原理及实现


    1、准备步骤

    1)取大素数 p 和 g(g < p,g 最好是 p 的素根)

    注解:若 g 是素数 p 的一个素根,则 g mod p, g^2 mod p , …, g^p-1 mod p 是 1 到 p - 1 的排列

    2)随机选取一整数 x (2 <= x <= (p - 2),(p,g,x) 是私钥)

    3)计算 y = g^x (mod p) ( (p,g,y) 是公钥)

    2、加密过程

    1)随机选取一整数 k (2 <= k <= (p - 2) 且 k 与 (p - 1) 互素)

    2)计算 a = g^k mod p,b = m*y^k mod p(m 为要加密的明文)

    3)密文 C = (a, b)

    3、解密过程

    1)m = b * a^(-x) mod p

    注解:b * a^(-x) mod p Ξ m * y^k * g^(-xk) Ξ m * g^(xk) * g^(-xk) Ξ m

    加密及解密的实现(Java):

    import java.util.ArrayList;
    
    public class Main {
        static ArrayList<Integer> suArr = new ArrayList<>();
        public static void main(String[] args) {
            int max = 8096, p, g, x, y, k, a, b, buffer_data;
            char[] m = "abc".toCharArray(); // 加密字符串"abc"
            ArrayList<Integer> C = new ArrayList<>();   // 加密后的密文
            int size1;
            suArr.add(2);
    
            // 随机取一个小于2048的素数g
            for (int i = 3; i <= 2048; i++) {
                if (isSuShu(i)) suArr.add(i);
            }
            size1 = suArr.size();
            g = getRanNum(size1);
    
            // 随机取一个大素数p
            for (int i = 2049; i <= max; i++) {
                if (isSuShu(i)) suArr.add(i);
            }
            p = getRanNum(suArr.size() - size1, size1);
    
            // x的范围是[2,p-2]
            x = (int)(Math.random() * (p-3))+2;
            // k的范围是[2,p-2]且k与p-1互素
            k = (int)(Math.random() * (p-3))+2;
            while (isHuZhi(k, p-1) != 1) {
                k = (int)(Math.random() * (p-3))+2;
            }
    
            // y = g^x mod p
            y = myPow(g, x, p);
    
            // a = g^k mod p
            a = myPow(g, k, p);
            C.add(a);
    
            // 特殊数据test
            // a = 1434;
            // g=1117;
            // k=2403;
            // p=6101;
            // x=714;
            // y=2271;
    
            // 加密过程,即计算b = m*y^k mod p (m是明文)
            for (char c : m) {
                C.add((int)c*myPow(y, k, p) % p);
            }
    
            buffer_data = myPow(a, x, p);
            buffer_data = exGcd(buffer_data, p)[0]; // 求(a^x)^(-1) mod p等价于求a^(-x) mod p
            if (buffer_data < 0) buffer_data += p;
    
            // 将解密后的明文输出
            for (int i = 1; i < C.size(); i++) {
                System.out.print((char)(C.get(i) * buffer_data % p));
            }
        }
    
        // 判断一个数是否为素数
        public static boolean isSuShu(int num) {
            int max = (int) Math.sqrt(num);
            for (int i = 2; i <= max; i++) {
                if (num % i == 0)
                    return false;
            }
            return true;
        }
    
        // 在素数数组中随机取一个数
        public static int getRanNum(int size) {
            return suArr.get((int) (Math.random() * (size)));
        }
    
        // 在素数数组中的(left, arr.size())之间随机取一个数
        public static int getRanNum(int size, int left) {
            return suArr.get((int) (Math.random() * (size)) + left);
        }
    
        // 判断两个数是否互质
        public static int isHuZhi(int a, int b) {
            return b == 0 ? a : isHuZhi(b, a % b);
        }
    
        public static int myPow(int a, int b, int m) {
            int res = 1;
            a %= m;
            while (b != 0) {
                if ((b & 1) == 1)
                    res = (res * a) % m;
                a = (a * a) % m;
                b >>= 1;
            }
            return res;
        }
    
        public static int getSuGen(int p) {
            boolean isSuGen;
            for (int g : suArr) {
                isSuGen = true;
                for (int i = 1; i < p; i++) {
                    if (myPow(g, i, p) != i) isSuGen = false;
                }
                if (isSuGen) return g;
            }
            return 2; // 如果在素数数组中找不到p的素根,则返回一个默认值
        }
    
        // 扩展欧几里得算法求a模b的逆元
        public static int[] exGcd(int a, int b) {
            if (b == 0) {
                int[] arr = new int[]{1, 0};
                return arr;
            } else {
                int[] arr = exGcd(b, a % b);
                int x = arr[0];
                arr[0] = arr[1];
                arr[1] = x - (a / b) * arr[1];
                return arr;
            }
        }
    }
    
    /*
     * 参考:
     * 素根的定义:a是素数p 的一个素根,如果a mod p, a^2 mod p , …, a^p-1 mod p 是1到p-1的排列,称a是P的一个素根
     * 加密时x和k的选取:https://blog.csdn.net/qq_34490018/article/details/79758620
     */
  • 相关阅读:
    从汇编的角度看待const与#define
    从汇编的角度看待变量类型与sizeof的机制
    按字节对齐分析
    堆内存和栈内存的探索
    string源码实现分析
    string源码分析 ——转载 http://blogs.360.cn/360cloud/2012/11/26/linux-gcc-stl-string-in-depth/
    开始了
    atoi函数的实现——面试
    new与malloc的区别,以及内存分配浅析
    [C]C语言中EOF是什么意思?
  • 原文地址:https://www.cnblogs.com/GjqDream/p/11543367.html
Copyright © 2020-2023  润新知