ELGamal密钥---最终版

上次写过一个,后来才发现那个纯属是胡扯的;前面找原根的方法是错的离谱的,这次我改进了一下方案,可以运行,但是运行时间还是有个十几秒到三十秒左右~~
题目描述

题目其实很好理解,总的来说就只有一个难点----求原根
首先来说说什么是原根,想了解什么是原根就要了解什么是阶(描述的可能不准确),还有欧拉函数,详情请自行百度~,首先我不是信息安全专业的,没学信息安全数学基础,所以请不要强求我,我只是一个码代码滴!

第一步:取一个随机的素数q,并且这个素数满足p = 2q + 1也是一个素数

第二步:随机取一个数g(在[2,p - 2]之间),判断g^2 mod p 与 g ^q mod p是否为1;只要有一个为1,说明g不是p的原根,就重新取随机数

第三步:产生公钥与私钥

第四步:利用公钥进行加密

第五步:利用私钥进行加密

第六步:输出要求要展示的数

解析:
第一步:产生素数,其实本身也是一件困难的事(素数要在150位左右),本人能力有限,没有相关筛法的知识,上网搜了搜,在csdn中借鉴了一位大佬的算法,后面自己也写了出来,但是我懒得改了,就用这个了,如果侵犯版权,立马修改!!取出素数q之后,利用费马素性检验算法检测其是不是素数,这个较简单

第二步:第一步中为什么要满足p = 2q + 1也是素数呢?这就要从欧拉函数与原根说起。首先,素数p的欧拉函数为p - 1,它有2个素因数:2,q;聪明的小伙伴已经想出来了,没错根据原根相关的知识,p有φ(φ( p)) 个原根,那么既然如此,只需检验2,q就行(至于为什么请查阅相关原根的资料,我自己一知半解,不敢在此造次);如果检验出来的结果为至少有一个为1那么就可以断言,这个g必定不是原根,若g是模p的原根那么只有当i= p - 1时,g^i mod p == 1!;只有两个检验的数都不为1时,g才是p的原根

第三步:没啥要说的,私钥a请根据要求来取

第四步:利用公钥来加密m时,请注意取的随机数K,它可不是乱取的,它是取之有理;总之k的取值是有要求的,请自行体会,到时候老师会提问的

第五步:利用私钥进行解密,就是计算

相关代码:
费马素性检验模块,其中包括快速模指数算法和求一个数的逆
模块名:Format

import random


# 定义一个函数,用来求 a**b mod c 的值
def quick_algorithm(a, b, c):  # 求a**b mod c
    a = a % c
    ans = 1
    while b != 0:
        if b & 1:
            ans = (ans * a) % c
        b >>= 1
        a = (a * a) % c
    return ans


def Isprime(p,k):
    for i in range(k):
        a = random.randint(2,p - 2)
        if quick_algorithm(a,p - 1, p) != 1:
            return 0
    return 1


def gcd(a,b):
    if b == 0:
        return a
    else:
        return gcd(b,a % b)


def get_inverse(a, m):  # 求一个数a 的逆  再模m 的值  这个函数返回的是一个值不是列表
    if gcd(a, m) != 1:
        return None
    u1, u2, u3 = 1, 0, a
    v1, v2, v3 = 0, 1, m
    while v3 != 0:
        q = u3 // v3
        v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3
    return u1 % m

取素数模块(完全借鉴的,侵删)
模块名:getprime

# 检测大整数是否是素数,如果是素数,就返回True,否则返回False

import random
def rabin_miller(num):
    s = num - 1
    t = 0
    while s % 2 == 0:
        s = s // 2
        t += 1

    for trials in range(5):
        a = random.randrange(2, num - 1)
        v = pow(a, s, num)
        if v != 1:
            i = 0
            while v != (num - 1):
                if i == t - 1:
                    return False
                else:
                    i = i + 1
                    v = (v ** 2) % num
    return True


def is_prime(num):
    # 排除0,1和负数
    if num < 2:
        return False

    # 创建小素数的列表,可以大幅加快速度
    # 如果是小素数,那么直接返回true
    small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
    if num in small_primes:
        return True

    # 如果大数是这些小素数的倍数,那么就是合数,返回false
    for prime in small_primes:
        if num % prime == 0:
            return False

    # 如果这样没有分辨出来,就一定是大整数,那么就调用rabin算法
    return rabin_miller(num)


# 得到大整数,默认位数为
def get_prime(key_size=500):
    while True:
        num = random.randrange(2**(key_size-1), 2**key_size)
        if is_prime(num):
            return num

获取原根模块:
模块名:Getroot

import Format,random
import getprime

def get_root():
    while True:
        list = []

        q = getprime.get_prime()  # 获取一个素数

        p = 2 * q + 1

        if not Format.Isprime(p, 5):  # 判定p是否为素数,不是就结束此次循环,开始下一次循环
            continue

        a = random.randint(2,p - 1)  # 获取一个随机整数,随机数范围为 2 ~ p - 1
        if Format.quick_algorithm(a, 2, p) == 1 or Format.quick_algorithm(a, q, p) == 1:
            # 若a**2(mod p)或a**q(mod p)等于1,那么说明,这个a不是原根
                continue

        else:
            list.append(p)
            list.append(a)
            return list

# print(get_root())

ELGamal密钥算法:

import random  # 导入random模块
import Getroot
import Format  # 导入费马检测算法

# 第二步求模p的原根列表list_g

def get_Ga():                                  # 定义一个函数,用来求取g**a mod p   a是一个随机整数,暂定为[100,1000]

    list_key = Getroot.get_root()

    a = random.randint(10**100, 10**101)                  # 获得一个随机整数a
    Ga = Format.quick_algorithm(list_key[1], a, list_key[0])      # 调用Format模块中的quick_algorithm()函数

    list_key.append(a)  # 初始化list_key
    list_key.append(Ga)

    return list_key


# 将公钥与私钥输出 公钥序数:
list_key = get_Ga()
print('公钥:\np={}\ng={}\n(g**a mod p )={}\n私钥:a={}'.format(list_key[0],list_key[1],list_key[2],list_key[3]))

# Bob用公钥对明文m进行加密
# Bob选取一个随机的整数k
# C1(mod p) = g**k(mod p)
# C2(mod p) = (m*((g**a)**k))(mod p)

with open(r'C:\Users\Acer\Desktop\实验四验收数据\secret2.txt','r',encoding = 'utf8') as file:
    m = int(file.read())


# m = int(input('请输入您要进行加密的消息:'))

k = random.randint(2,list_key[0] - 2)   # 取一个随机的整数 k
C_1 = Format.quick_algorithm(list_key[1],k,list_key[0])
C1 = C_1 % list_key[0]                                                               # 计算C1
C2 = m * Format.quick_algorithm(list_key[1] , list_key[3] * k , list_key[0]) % list_key[0] # 计算C2

print('C1 = {}\nC2 = {}'.format(C1,C2))


# Alice解过程
# V = C1**a(mod p)
# m = C2*V_inverse (mod p)
# V_inverse = Format.get_inverse(v,p)

V = Format.quick_algorithm(C1,list_key[3],list_key[0])
V_inverse = Format.get_inverse(V,list_key[0])

# print(V_inverse * C2)
messege = C2*V_inverse % list_key[0]

print(messege % list_key[0])


本文仅供自己参考
~
~
~
~
~
~
~
~
还有运行时间有些长,要有耐心,男人就是要持久,我是指写代码时能够坐下的时间;可能有些人不服气,他说我这个没用,我说我这个有用,其实根本不在于长短也不在于自己的持久能力;而在于自己的技巧------写代码的技巧,现在这个运行时间可能有些长,但以后,你如果有了一定的技巧,而且又持久,那还不是手到擒来!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值