ElGamal加密—python

个人理解拼凑出来的:

'''求本原元'''
# 用辗转相除求最大公因子
def gcd(a, b):
    r = a % b
    while r != 0:
        a = b
        b = r
        r = a % b
    return b

# 欧拉函数
def euler(a):
    cnt = 0
    for i in range(1, a):
        if gcd(a, i) == 1:
            cnt += 1
    return cnt

# 阶
def order(a, n, b):
    #   输出b在mod(a)中的阶
    #   n是mod(a)群的阶
    p = 1
    while p <= n and b ** p % a != 1:
        p += 1
    if p <= n:
        return p
    else:
        return -1

# 求本原元
def primitive_root(a):

    n = euler(a)
    for b in range(2, a):
        if order(a, n, b) == n:
            return b

import random
from math import pow
from Crypto.Util import *

# 扩展欧几里得求逆元
def exgcd(a, b):
    if b == 0:
        return 1, 0, a
    else:
        x, y, q = exgcd(b, a % b)
        x, y = y, (x - (a // b) * y)
        return x, y, q
# 扩展欧几里得求逆元
def ModReverse(a,p):
    x, y, q = exgcd(a,p)
    if q != 1:
        raise Exception("No solution.")
    else:
        return (x + p) % p #防止负数


def encrypt(a, k, y, p):
    xa = int(input('请输入加密的数据:'))
    y1 = (a**k)%p
    y2 = xa*(y**k) % p
    return y1, y2

def decrypt(y1, y2, d, p):
    #x= y2 / (y1**d) % p   #是求逆元的过程
    j = ModReverse(y1,y2)
    x = (y2 * j) % p
    return x



def main():
    p = int(input('请选择一个大素数p:'))  # 大素数
    a = primitive_root(p)               # 模p的原根a
    print("原根a=", a)                  # p为37 可以看到,是2

    #d = random.randint(2, 10)         #产生随机常数d作为密钥
    d = 5

    y = (a ** d) % p      #计算y
    print(y)

    #k = random.randint(2, 10)   #随机数k=7
    k=7
    y1, y2 = encrypt(a, k, y, p)
    x = decrypt(y1, y2, d, p)
    print(f"ALice的公钥:\np = {p}\na = {a}\n密文(y1, y2) = ({y1},{y2})\n解密明文x = {x}")


if __name__ == '__main__':
    main()

按照解释1的思路运行,选定37加密29是正确的,第三步解密 求x公式有误(开始没理解)(后来改进是求逆元的过程),固定随机数K和d加密正确,但是加密其他数字又出错了???跪求改正!!!

解释1:

解释2:

解释3:

解释4:

另一个解释很详细的文章链接:

ElGamal加密算法|ElGamal签名算法|公钥密码|数字签名|密码学|信息安全_Suryxin.的博客-CSDN博客

————————————————  

其中原根:

本原元

当a模n的阶为φ(n),也就是说当且仅当x是φ(n)的倍数,使得ax ≡1(mod n)成立,此时称a为n的本原元。举个例子:

这些余数构成了一个模7的完全剩余系1,2,3,4,5,6,也就是对于任意a,都可以找到x0使得:
5x0 ≡a (mod 7)。

本原元求解Python:

# 用辗转相除求最大公因子
def gcd(a, b):
    r = a % b
    while r != 0:
        a = b
        b = r
        r = a % b
    return b

# 欧拉函数
def euler(a):
    cnt = 0
    for i in range(1, a):
        if gcd(a, i) == 1:
            cnt += 1
    return cnt

# 阶
def order(a, n, b):
    #   输出b在mod(a)中的阶
    #   n是mod(a)群的阶
    p = 1
    while p <= n and b ** p % a != 1:
        p += 1
    if p <= n:
        return p
    else:
        return -1

# 求本原元
def primitive_root(a):
    n = euler(a)
    for b in range(2, a):
        if order(a, n, b) == n:
            return b

print(primitive_root(37))
# 可以看到,是2

其中求逆元:

# 扩展欧几里得求逆元
def exgcd(a, b):
    if b == 0:
        return 1, 0, a
    else:
        x, y, q = exgcd(b, a % b)
        x, y = y, (x - (a // b) * y)
        return x, y, q

# 扩展欧几里得求逆元
def ModReverse(a,p):
    x, y, q = exgcd(a,p)
    if q != 1:
        raise Exception("No solution.")
    else:
        return (x + p) % p #防止负数


def main():

    j = ModReverse(17,33)
    print(j)   #结果为2

if __name__ == '__main__':
    main()

参考实现代码:

————————————————

文章链接:ElGamal公钥密码算法(Python实现)_elgamal python_忆往昔ོ  的博客-CSDN博客

from random import randint
import sympy
import sys

sys.setrecursionlimit(10000)


def fastExpMod(a, e, m):
    a = a % m
    res = 1
    while e != 0:
        if e & 1:
            res = (res * a) % m
        e >>= 1
        a = (a * a) % m
    return res


def primitive_element(p, q):
    while True:
        g = randint(2, p - 2)
        if fastExpMod(g, 2, p) != 1 and fastExpMod(g, q, p) != 1:
            return g


def e_gcd(a, b):
    if b == 0:
        return a, 1, 0
    g, x, y = e_gcd(b, a % b)
    return g, y, x - a // b * y


def encrypt(p, g, y, m):
    while True:
        k = randint(2, p - 2)
        if e_gcd(k, p - 1)[0]:
            break
    c1 = fastExpMod(g, k, p)
    c2 = (m * fastExpMod(y, k, p)) % p
    return c1, c2


def decrypt(c1, c2, p, a):
    v = fastExpMod(c1, a, p)
    v_1 = e_gcd(v, p)[1]
    m_d = c2 * v_1 % p
    return m_d


def main():
	# 这里的路径:读者自己电脑测试文件存放的正确路径
    #m = int(open("F:\密码学实验\secret2.txt").readline())
    m = int(input('输入一个数用于加密:'))
    while True:
        q = sympy.randprime(10 ** 149, 10 ** 150 / 2 - 1)
        if sympy.isprime(q):
            p = 2 * q + 1
            if len(str(p)) == 150 and sympy.isprime(p):
                break
    g = primitive_element(p, q)
    a = randint(2, p - 2)
    y = fastExpMod(g, a, p)
    c1, c2 = encrypt(p, g, y, m)
    m_d = decrypt(c1, c2, p, a)

    if m == m_d:
        print("解密结果与明文相同!解密正确!")
    else:
        print("解密结果与明文不同!解密不正确!")
    return m, p, g, y, c1, c2, m_d


if __name__ == '__main__':
    print("m = %d\nALice的公钥:\np = %d\ng = %d\ng^a = %d\n密文(C1, C2) = (%d,\n%d)\n明文m = %d"
          % main())

 ————————————————

文章链接:Python实现ElGamal加密算法_elgamal算法python_出门左拐是海的博客-CSDN博客

import random
from math import pow

a = random.randint(2, 10) #产生小于p的随机常数a

# 用辗转相除求最大公因子
def gcd(a, b):
    if a < b:
        return gcd(b, a)
    elif a % b == 0:
        return b;
    else:
        return gcd(b, a % b)

# 生成大量随机数

def gen_key(q):
    key = random.randint(pow(10, 20), q)
    while gcd(q, key) != 1:
        key = random.randint(pow(10, 20), q)

    return key


# 模幂运算
def power(a, b, c):
    x = 1
    y = a

    while b > 0:
        if b % 2 == 0:
            x = (x * y) % c;
        y = (y * y) % c
        b = int(b / 2)

    return x % c


# 非对称加密
def encrypt(msg, p, h, r):
    en_msg = []

    b = gen_key(p)  # 得b
    K = power(h, b, p)#K=(Sa)^b mod p
    C1 = power(r, b, p) #C1=Sb=r^b mod p

    for i in range(0, len(msg)):
        en_msg.append(msg[i])

    print("C1 : ", C1)
    # print("(Sa)^b mod p used : ", K)
    for i in range(0, len(en_msg)):
        en_msg[i] = K * ord(en_msg[i])
    print("C2 : ", en_msg)
    return en_msg, C1

#解密
def decrypt(C2, C1, a, p):
    dr_msg = []
    h = power(C1, a, p)
    for i in range(0, len(C2)):
        dr_msg.append(chr(int(C2[i] / h)))

    return dr_msg


# Driver code
def main():
    msg =input('请输入加密数据:')         # 共125位数字,1000bit
    print("明文 :", msg)

    p = random.randint(pow(10, 20), pow(10, 50)) # 获得大素数q
    r = random.randint(2, p)#得r

    a = gen_key(p)  # 接收器的私钥
    h = power(r, a, p)

    C2, C1 = encrypt(msg, p, h, r)
    dr_msg = decrypt(C2, C1, a, p)
    dmsg = ''.join(dr_msg)
    print("解密后文 :", dmsg);


if __name__ == '__main__':
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值