#!/usr/bin/env python3
#coding:utf-8
#by spwpun
import random
import binascii
import argparse #導入讀取命令行參數的模塊
import sys
sys.setrecursionlimit(100000) #設置迭代次數限制
def main():
Build_key() #生成公鑰、密鑰
parser = argparse.ArgumentParser(description="This is a description, it includes the whole file's loactions of RSA algorithm.")
parser.add_argument('-p', required = True, type = argparse.FileType('r'), help = 'plainfile')
parser.add_argument('-n', required = True, type = argparse.FileType('r'), help = 'nfile')
parser.add_argument('-e', required = False, type = argparse.FileType('r'), help = 'efile') #e,d文件不是都要的,只需一個
parser.add_argument('-d', required = False, type = argparse.FileType('r'), help = 'dfile')
parser.add_argument('-c', required = True, type = argparse.FileType('w+'), help = 'cipherfile')
args = parser.parse_args() #args裏面的成員是一個文件對象,所以後面寫入文件的形式和一般的一樣
n = int(args.n.read(),16)
m = args.p.read()
if m=='':
print('No PlainText!')
else:
print("Encrypting......")
e = int(args.e.read(),16)
cipher = encrypt(m,e,n)
with args.c as f:
f.write(cipher)
print("Encrypted!\r\nThe Cipher is:",cipher)
c = cipher #讀取密文
if c=='':
print ("No Cipher!")
else:
print("Decrypting......")
d = int(args.d.read(),16)
plain = decrypt(c,d,n)
print("Decrypted!\r\nThe PlainText is:",plain)
#平方—乘法,最後返回結果
def MRF(b,n,m):
a=1
x=b;y=n;z=m
binstr = bin(n)[2:][::-1] #通過切片去掉開頭的0b,截取後面,然後反轉
for item in binstr:
if item == '1':
a = (a*b)%m
b = (b**2)%m
elif item == '0':
b = (b**2)%m
return a
#素性檢驗
def MillerRabin(n):
"利用Miller-Rabin算法檢驗生成的奇數是否爲素數"
m=n-1
k=0
while(m%2==0):
m=m//2
k=k+1
a=random.randint(2,n)
#b=a**m%n
b = MRF(a,m,n)
if(b==1):
return 1
for i in range(k):
if(b==n-1):
return 1
else:
b=b*b%n
return 0
#生成大素數,20次MillerRabin算法縮小出錯的概率
def BigPrime():
Min = 10**11;Max = 10**15;p = 0
while(1):
p = random.randrange(Min,Max,1)
for i in range(20):
if MillerRabin(p)==0:
break
elif i==19:
return p
#加密,傳入公鑰,通過讀取明文文件進行加密
def encrypt(m,e,n):
cipher = ""
nlength = len(str(hex(n))[2:]) #計算n的16進制長度,以便分組
message = m #讀取明文
for i in range(0,len(message),8):
if i==len(message)//8*8:
m = int(a2hex(message[i:]),16) #最後一個分組
m = int(a2hex(message[i:i+8]),16)
c = MRF(m,e,n)
cipher1 = str(hex(c))[2:]
if len(cipher1)!=nlength:
cipher1 = '0'*(nlength-len(cipher1))+cipher1 #每一個密文分組,長度不夠,高位補0
cipher += cipher1
return cipher
#解密,傳入私鑰,通過文件讀寫進行解密
def decrypt(c,d,n):
#加密之後每一個分組的長度和n的長度相同
cipher = c
message = ""
nlength = len(str(hex(n))[2:])
for i in range(0,len(cipher),nlength):
c = int(cipher[i:i+nlength],16) #得到一組密文的c
m = MRF(c,d,n)
info = hex2a(str(hex(m))[2:])
message += info
f_write("RSA_decrypted.txt",message)
return message
#求最大公因子
def gcd(a,b):
if a%b == 0:
return b
else :
return gcd(b,a%b)
#求逆元
def Ex_Euclid(x,n):
r0=n
r1=x%n
if r1==1:
y=1
else:
s0=1
s1=0
t0=0
t1=1
while (r0%r1!=0):
q=r0//r1
r=r0%r1
r0=r1
r1=r
s=s0-q*s1
s0=s1
s1=s
t=t0-q*t1
t0=t1
t1=t
if r==1:
y = (t+n)%n
return y
#寫入文件
def f_write(filename,message):
f = open(filename,'w')
f.write(message)
f.close()
return 0
#ascii_to_hex
def a2hex(raw_str):
hex_str = ''
for ch in raw_str:
hex_str += hex(ord(ch))[2:]
return hex_str
#hex_to_ascii
def hex2a(raw_str):
asc_str = ''
for i in range(0,len(raw_str),2):
asc_str += chr(int(raw_str[i:i+2],16))
return asc_str
def Build_key():
#產生p,q,n,e,d
p = BigPrime()
q = BigPrime()
n = p*q
_n = (p-1)*(q-1) #n的歐拉函數
e = 0
while(1):
e = random.randint(1,_n+1)
if gcd(e,_n)==1:
break
d = Ex_Euclid(e,_n)
#寫入文件
f_write('p.txt',str(hex(p))[2:])
f_write('q.txt',str(hex(q))[2:])
f_write('n.txt',str(hex(n))[2:])
f_write('e.txt',str(hex(e))[2:])
f_write('d.txt',str(hex(d))[2:])
if __name__ == "__main__":
main()
每一次運行都會重新生成公鑰、密鑰參數,這些參數分別以16進制的格式寫入文件中,代碼中還加入了對命令行參數的使用,主要用到了python的argparse模塊。一個簡單的示例如下:通過-h可以查看幫助信息: