前言
不多bb,直接上图
RSA加密库实现
有一说一,这个题目刚拿到手被吓到了,作为咸鱼的我慌得很
)
正好前几节课大佬正好讲了pycryptodoom这个库,赶紧看看
导入库之后漫长的读代码时间,不要误会,不是读这个库,是读大佬写好的代码,因为不需要签名,我主要读了这三个函数
def generate_key(bits):
return RSA.generate(bits)
def encrypt(message, pk, hasher=Hash.SHA1):
cipher_obj = cipher.new(RSA.importKey(pk))
org_bytes = message.encode()
length_en = RSA.RsaKey.size_in_bytes(RSA.importKey(pk)) - 2 * hasher.digest_size - 2
res_en = b''
for i in range(0, len(org_bytes), length_en):
res_en += cipher_obj.encrypt(org_bytes[i: i + length_en])
cipher_text = res_en
return cipher_text
def decrypt(cipher_text, sk):
cipher_obj = cipher.new(RSA.importKey(sk))
length_de = RSA.RsaKey.size_in_bytes(RSA.importKey(sk))
res_de = b''
for i in range(0, len(cipher_text), length_de):
#res_de += cipher_obj.decrypt(cipher_text[i:i + length_de], 'DecryptError') # for pkcs
res_de += cipher_obj.decrypt(cipher_text[i:i + length_de]) # for oaep
plaint_text = res_de.decode()
return plaint_text
运行时先创建公私钥,然后调用加密解密函数就可以了,这是RSA库的功能。没啥可说的,先读库的说明,里边有举例(主要大佬例子明显),懂得都懂
自己实现的RSA加密
RSA算法大家都懂,基本计算机上过带学的都知道
参数 | 参数说明 | |
---|---|---|
公钥 | n,e | n=p*q,e和(p-1)(q-1)互质 |
私钥 | n,d | d·e=1mod[(p-1)(q-1))] |
加密 | C,M,e | C = M e m o d ( n ) C=M^emod(n) C=Memod(n) |
解密 | M,C,d | M = C d m o d ( n ) M=C^dmod(n) M=Cdmod(n) |
看起来很简单吧,感觉主要简单数论知识就明白了原理,我开始也是这么想的,实现起来被RSA狠狠暴打一顿,RSA算法实现的几个重要的点:
- 产生两个随机的质数p,q,要是不查表只能手搓了
- E和乘积互质,听起来简单吧,算起来也挺要命
- 求d,其实是在求e的逆,多亏刚考了数论,还能hold住
- 在加密时 M e M^e Me时 模指数运算问题,正常算太慢
这次是真的学到了,每次考试的小素数分解式多么简单,这些问题属实要命,没招,只能回炉重造(百度),找到了一些解决方法
-
产生随机质数的方法:米勒罗宾算法,
这算法的原理如下:
(1).若p是素数,则 a 2 m o d p = 1 a^2mod p=1 a2modp=1当且仅当 a m o d p = 1 或 a m o d p = − 1 amodp=1或a mod p=-1 amodp=1或amodp=−1成立;
(2).若p是素数,有 p − 1 = 2 k q , p-1=2^kq, p−1=2kq,设a为整数且1<a<p-1,则 a q m o d p = 1 a^qmodp=1 aqmodp=1即费马小定理
证明如下:
代码实现:def montgomery(a, q, k, n): if quick_power_mod(a, q, n) == 1: return False else: for i in range(0, k): if quick_power_mod(a, 2 ** i * q, n) == n - 1: return False return True
2.e和乘积互质解决方法:判断最大公因数是不是1,用欧几里得算法,不多说了上代码;
def GCD(a, b): while b != 0: temp = b b = a % b a = temp return a
3.求逆,用扩展欧几里得算法,也不多说了上代码;
def exgcd(e, phi_n): a = phi_n b = e x0, y0 = 1, 0 x1, y1 = 0, 1 x, y = 0, 1 r = a % b q = (a - r) // b while r != 0: x = x0 - q * x1 y = y0 - q * y1 x0, y0 = x1, y1 x1, y1 = x, y a = b b = r r = a % b q = (a - r) // b return y
4.快速求模指数,利用模除的性质,代码如下
def quick_power_mod(alpha, plpha, nlpha): b = alpha p = plpha n = nlpha a = 1 b = b % n while(p): if p & 1 == 1: a = a * b % n p = p >> 1 a = a b = (b * b) % n return a
除此之外别的就好说了 剩下的关键代码如下:
def RSA_Encrypt(string, e, n):
bit = 0
tempn = n
while tempn > 0:
bit += 1
tempn = tempn >> 1
s = random.randint(2, bit - 1)
string = string.encode('utf-8')
bit64 = _bytes_2_64bit_(string)
P = _64bit_2_sbit(bit64, s)
C = []
for i in range(len(P)):
tempC = quick_power_mod(P[i], e, n)
C.append(tempC)
return C,s
def RSA_Decrypt(C, d, n,s):
P = []
for i in range(len(C)):
tempP = quick_power_mod(C[i], d, n)
P.append(tempP)
P = _sbit_2_64bit(P, s)
P = _64bit_2_bytes(P)
return P.decode('utf-8')
至此RSA两大块完成
LFSR反馈多项式库+自己实现
要求前边已经提过,这部分实现起来原理很简单,但过程很困难,主要难点在类型转换,比如np数组和list;2,10,16进制和字符串等格式转换等;还有个问题是pythonClass的使用,在实体化一个class的时候,我的参数有一个无法调用,最终被迫使用函数完成(代码行数少了,但写的很难看).
有个小技巧,在字符串不好调用时可以输出,输出再读取,可能有奇效,也可能是我会改格式,哈哈
不多说了,上代码:
def LFSR_self_fankui(state,seq):
fpoly1 = [13, 12, 6, 5, 4, 3]
b = np.logical_xor(state[fpoly1[0] - 1], state[fpoly1[1] - 1]) # 异或最后一位和第一位
if len(fpoly1) > 2:
for i in range(2, len(fpoly1)):
b = np.logical_xor(state[fpoly1[i] - 1], b) # 反馈多项式启动
state = np.roll(state, 1) # 沿着给定轴滚动数组元素。超出最后位置的元素将会滚动到第一个位置。
state[0] = b * 1 # 反馈位填入第一位 # if self.verbose: # 输出每轮的值
if seq.size==0:
seq = state[1]
seq = np.append(seq, state[4])
seq = np.append(seq, state[8])
seq = np.append(seq, state[7])
seq = np.append(seq, state[17])
seq = np.append(seq, state[99])
seq = np.append(seq, state[137])
seq = np.append(seq, state[221])
else:
seq = np.append(seq, state[1])
seq = np.append(seq, state[4])
seq = np.append(seq, state[8])
seq = np.append(seq, state[7])
seq = np.append(seq, state[17])
seq = np.append(seq, state[99])
seq = np.append(seq, state[137])
seq = np.append(seq, state[221]) # 过滤密钥流
return (state,seq)
def LFSR_self():
state_1 = np.array(sha_1)
state1 = state_1.astype(int)
state_2 = np.array(sha_1)
state2 = state_2.astype(int)
state_3 = np.array(sha_1)
state3 = state_3.astype(int)
state_4 = np.array(sha_1)
state4 = state_4.astype(int)
# 初始化4个LFSR verbose 控制是否显示每轮结果,测试时改为true
seq=np.zeros(1)
# L1首先进行一轮操作
state1,seq=LFSR_self_fankui(state1,seq) # 过滤的密钥值放入总的密钥流中
for i in range(255): # 轮换执行n-1次
state2,seq=LFSR_self_fankui(state2,seq)
state2[0] = state2[0] ^ state1[0]
state3, seq = LFSR_self_fankui(state3, seq)
state3[0] = state3[0] ^ state2[0]
state4,seq=LFSR_self_fankui(state4,seq)
state4[0] = state4[0] ^ state3[0]
state1,seq=LFSR_self_fankui(state1,seq)
state1[0] = state1[0] ^ state4[0]
state2, seq = LFSR_self_fankui(state2, seq)
state2[0] = state2[0] ^ state1[0]
state3, seq = LFSR_self_fankui(state3, seq)
state3[0] = state3[0] ^ state2[0]
state4, seq = LFSR_self_fankui(state4, seq)
state4[0] = state4[0] ^ state3[0]
hex_num = hex_change(seq) # 将产生的二进制密钥流转为16进制字符
text_save("seq_self.txt", hex_num) # 保存生成的密钥流字符串到文件中
q = open("seq_self.txt", "rb")
seq = q.read(1024)
q.close()
mingwen = "mingwen.txt"
miwen = "jiami_self.txt"
jiemip = "jiemi_self.txt"
jiami(mingwen, miwen, seq)
jiemi(miwen, jiemip, seq)
基本就这了,学到了很多,学哭了都.
最后附上一张友情赞助的可爱小图:
我感觉蛮不错的,很喜欢这种黑白画风,大家品一品,欢迎留言