CryptoAlgor 项目地址 (四个实验完整源码)
该项目的目录:
1.四个古典密码 /classcipher
2.DES分组密码 /descipher
3.RSA公钥密码 /rsacipher
4.ECC公钥体制(Elgamal加密) /ellipticc
至此,四个加密实验完毕,均以Python实现。
四种加密都已经封装成Pyhon模块,直接调用即可。
目录
1.关于 ECC 的依赖算法
1. 判断是否有平方剩余,并求解平方剩余的根
2.求分式模p的正整数同余式
# 本文件名为 __util.py
from fractions import Fraction
def gcd(x, y):
""" 欧几里德算法 """
while x > 0:
x, y = y % x, x
return y
def extendGcd(a, b):
""" 扩展欧几里德算法 求同余式
求 a*x +b*y = gcd(a,b) 解
"""
if b == 0:
return a, b
else:
x, y = extendGcd(b, a % b)
x, y = y, x - (a//b) * y
return x, y
def isQuadricReside(a, p):
""" 判断 a 是否为 素数p 的`平方剩余`
---------------------------
* return 0 : a 被 p 整除
* return 1 : a 是模 p 的平方剩余
* return-1 : a 不是模 p 的平方剩余
"""
legendre = (a**int((p - 1) / 2)) % p
if legendre > 1: legendre -= p
return legendre
def calcResideRoot(a, p):
""" 求模 p 的平方剩余 a 的两个平方根
---------------------------
即方程 x^2 = a mod p 的解
* retrun : 元组解(x1, x2)⛄
"""
for i in range(1, p):
if (i**2) % p == a:
return (i, p - i)
def calcCongruence(n, p):
""" 计算 a mod p 的同余正整数
----------------------
* n : 分数、负数等
* p : 素数
* retrun : 同余的正整数
"""
if isinstance(n, int):
# 若a为整数, 则直接得到正整数同余式
return n % p
# 若n为分数b/a, 则计算得到正整数同余式
# 即求不定 a*x + p*y = b 的解 x
a, b = n.denominator, n.numerator
coef = b // gcd(a, p)
x, _ = extendGcd(a, p)
return (coef * x) % p
2. ECC椭圆曲线类
1.创建 ECC 类,实现生成 交换群 Ep(a,b),
2.并实现群的基本算术运算。
# 本文件名为: ecc.py
from fractions import Fraction
from __util import *
class ECC():
""" 椭圆曲线密码体制
实现椭圆曲线点的运算, 消息的加密等
可应用于 Elgamal 加密
------------------------------
此 ECC类 用到运算符重载, 代码较复杂
可以参看简化版:`ecc2.py`中的 ECC类
曲线方程: y^2 = x^3 + ax - b
* a : Ep(a, b) 中的 a
* b : Ep(a, b) 中的 b
* p : GF(p), y^2 mod p 中的 p
"""
def __init__(self, a, b, p):
if 4 * a**3 + 27 * b**2 == 0:
print("非法椭圆曲线,请重新输入")
self.__class__.a = a # __class__表示设为类成员属性
self.__class__.b = b # 以便内部类point访问
self.__class__.p = p
def genEset(self):
""" 生成椭圆曲线的坐标点集 Ep(a, b)
* return : 坐标点集 [(x1,y1), (x2,y2), ··· ]
"""
a, b, p = self.a, self.b, self.p
Eset = [EO.point] # 定义一个`点集Ep(a,b)`的加法幺元
for x in range(0, p):
sqr = (x**3 + a*x + b) % p # 计算待开方的值
if isQuadricReside(sqr, p) == 1:
# 若 sqr 是 p 的平方剩余, 则求 sqr 的根
solution = calcResideRoot(sqr, p)
Eset.append((x, solution[0]))
Eset.append((x, solution[1]))
return Eset
class point():
""" Ep(a,b)中`坐标点(x, y)`实例化为`point对象`
--------------------------------------
实例化后的point对象可做 + - * 等运算
"""
def __init__(self, *point):
""" 获取实例对象ECC()中的 a, p, `坐标点point`
* a, p : Ep(a, b) 中的 a, p
* point : 椭圆曲线上的坐标点(x, y)
"""
# 继承外部类成员属性 ECC.a, ECC.p
self.a, self.p, self.point = ECC.a, ECC.p, point
def __add__(self, other):
""" 重载运算符`+`: 定义椭圆上点的加法
* self : point对象 P:(x1, y1)
* other : point对象 Q:(x2, y2)
* retrun: point对象 P+Q:(x3,y3)
"""
a, p, P, Q = self.a, self.p, self, other
(x1, y1), (x2, y2) = self.point, other.point
if P.point == EO.point: return Q # EO+Q=Q
if Q.point == EO.point: return P # P+EO=P
if x1==x2 and y1!=y2: return EO # P+Q=EO
if x1!=x2: lamb = Fraction(y2-y1, x2-x1)
if x1==x2: lamb = Fraction(3*x1*x1+a, 2*y1)
lamb = calcCongruence(lamb, p)
x3 = lamb**2 - x1 - x2
x3 = calcCongruence(x3, p)
y3 = lamb * (x1 - x3) - y1
y3 = calcCongruence(y3, p)
return ECC.point(x3, y3)
def __mul__(self, coef):
""" 重载运算符`*`: 椭圆上点的数乘 例如Point*3 """
sums = self
for _ in range(1, coef): sums += self
return sums
def __rmul__(self, other):
""" 重载运算符`*`: 椭圆上点的数乘 例如3*Point """
return self * other
def __neg__(self):
""" 重载运算符`-`: 椭圆上点的加法逆元 """
x, y = (self.point[0], ECC.p-self.point[1])
y = 0 if y == ECC.p else y
return ECC.point(x, y)
def __sub__(self, other):
""" 重载运算符`-`: 椭圆上点的减法 """
other = - other # 返回加法逆元 则 P-Q = P+(-Q)
return self + other
def __repr__(self):
""" 重载函数`print`: 打印对象point的点(x,y) """
# 获取point对象的坐标点point (0,0)打印字母O
disp = self.point
disp = 'O' if disp==EO.point else disp
return str(disp)
# 全局变量: 自定义加法幺元, 即 EO.point = (0, 0)
# ECC()中数字随便, point(x,0)中 x随便, y必须是 0 或 p
EO = ECC(1,1,1).point('O', 'O')
""" 幺元为什么取('O', 'O') ?
因为('O', 'O')连坐标都不是, 自然不在曲线 y^3=x^3+ax+b上
它只是一个符号, 写成('O', 'O')只是因为坐标(x,y)有两个分量
仅仅是为了方便运算, 它只是一个符号
"""
if __name__ == '__main__':
ellip = ECC(1, 1, 23) # 实例化一个 Ep(a,b) 对象
P = ellip.point(3, 10) # 实例化Ep(a,b)上的point对象
Q = ellip.point(9, 7) # 实例化Ep(a,b)上的point对象
print("P+Q:", P + P)
3.基于 ECC 实现 Elgamal 加密方法
1.以《现代密码学 杨波》例题4-36,验证 Elgaml 加密过程,
2.并且基于 密文、明文 破解 Alice 的私钥。
# 本代码基于 ECC类 实现 Elgamal 加密
from ellipticc import ECC
import time
def takeTime(func):
""" 装饰器: 计算函数运行耗时"""
def decorated(*args):
startime = time.time()
func(*args)
endtime = time.time()
taketime = round((endtime - startime)*10**3)
print(f"->运算耗时: {taketime} 毫秒")
return func
return decorated
@takeTime
def Elgamal_exam436():
# 利用ECC椭圆密码, 实现 Elgamma 加密
# 公开椭圆曲线 ECC 的参数 Ep(a,b)、G
# Alice 选择一整数私钥 Nk4
# Alice 公开自己的公钥 PA=NA*G
ellip = ECC(-1, 188, 751)
G = ellip.point(0, 376)
PA = ellip.point(201, 5)
# Bob 选择随机数 k, 对消息 PM 进行加密得到密文
# Bob 发送密文 C = [(676, 558), (385, 328)]
k = 386
PM = ellip.point(562, 201)
C = [k*G, PM + k*PA]
print("\n密文为:", C)
@takeTime
def crackElgamal():
""" 破解例题中 Alice 的私钥 """
ellip = ECC(-1, 188, 751)
PM = ellip.point(562, 201)
C1 = ellip.point(676, 558)
C2 = ellip.point(385, 328)
for i in range(1, 1000):
tmp = C2 - i*C1
if tmp.point == PM.point:
print("\nAlice选择的密钥为:", i)
return i
print("\n未破解成功, 请加大迭代次数")
return 0
if __name__ == '__main__':
Elgamal_exam436()
crackElgamal()