python實現RSA算法

#!/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可以查看幫助信息:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章