iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 19
0
Modern Web

慢慢帶你了解Flask系列 第 19

慢慢帶你了解Flask - Day19 Secret Talk(1):前言 + RSA實作(python to exe)

  • 分享至 

  • xImage
  •  

大家好,我是長風青雲。今天是第十九天,我們要進入的實例是Secret Talk。
先來說說前言和一些基本概念的部分吧。

前言

在我大三的時候我修了一堂課叫做網路程式設計,與此同時我們也上了一堂叫做網路安全的課。
那個時候期末project我就一直在思考著要做什麼,如果我沒記錯……似乎是在上雲端運算概論的時候,我開始想著如果能在網路程式設計的期末project做出public key的聊天室就好了。
那個時候想的還不仔細,畢竟後來我做的是連線五子棋,但其實內心就一直想將所學到的東西放到現實裡來看看。
時隔……也沒多年,時隔一年多一些,我才打算將他做出來。
我以前想的是某個程式,他會是開機程式,然後如果有人希望能與你聊天,會傳送相應的port給你,同時你那邊會跳出通知。這個port會經過你的publickey加密過,所以只有你看的到他的port到底是多少,接著再開啟putty到相應的位置開始進行聊天。
看著就很亂吧XD,但現在我是打算用網頁的形式了。畢竟已經學了嘛~
那我們就來說什麼是public key吧!

public key

網安不算學的好的我,在這我就簡單說明一些概念就好。

在密碼學我們擁有兩種加密模式,一個是對稱式加密,一個則稱為非對稱式加密。
對稱式加密意義是指加密與解密是使用同一把鑰匙,類似於你家的大門,打開和關上都是用同一個鑰匙。這意味著,A和B都必須知道這一把鑰匙,只要使用這把鑰匙別人就不知道你們互相傳遞的內容是什麼了。
但最初一開始,A和B要怎麼知道這把鑰匙是什麼呢?一定會有第一次A告訴B這把鑰匙內容的那一次吧?那如果這第一次就被C給攔截下來,C知道這把鑰匙那A和B的秘密不就都被知道了嗎?
所以後來衍生出了非對稱式加密。他的意義就代表是加密與解密的鑰匙是不同的。我來上個圖來方便解釋。
https://ithelp.ithome.com.tw/upload/images/20230606/20120116tKNEfDszHp.jpg
在這張圖裡面我看到Alice傳訊息給Bob,她是使用Bob的公鑰進行上鎖,而Bob在收到密文後再使用自己的私鑰解密。
那什麼是公鑰和私鑰呢?
私鑰很好理解,就是自己的鑰匙,自己需要好好保管。
而公鑰則是公布給大家知道的鑰匙,這樣他人要傳訊給自己時只要拿自己的公要進行上鎖,等密文到自己這裡再使用私鑰打開就好。

這樣說明大家應該會理解了吧~
至於算法部分我會之後在程式碼內部的時候跟大家說明,接下來我要說一下自己的想法。
我原先的想法……其實是當一個用戶註冊時,伺服器,也就是我們的Flask會順便算出你的公鑰私鑰,並將你的公鑰寫進我們的資料庫中。
但我發現這是不對的。
我這個主題是私密聊天室,資安問題需要放在優先考慮,倘若有人一直在監控著我們的網站,網路之間傳輸訊息被有心人攔截成功,那這公鑰、私鑰不就大白於天下了嗎?
所以我決定將我們的公私鑰寫成單機小程式,不連網的產生,這樣就不會有這方面的困擾了~
我網安學的不好,幸好自己有突然想到這一層……以前想的真的是太簡單了。那現在就先來寫我們的生成公鑰小程式吧~

加密過程

  1. 選擇兩個極大的質數p、q
  2. 計算 n = p x q
  3. 計算 f(n) = (p-1) x (q-1)
  4. 找到一個與 f(n) 互質的 e
  5. 計算d ,使得 d x e ≡ 1 mod f(n)
  6. Public key=(e,n),Private key=(d,n)
  7. 加密前先將明文轉數字化
  8. 加密:C≡(M^e) mod n
  9. 解密:M=(C^d) mod n

公私鑰生成器

我們採用tkinter這個module來設計我們的GUI
所以我們首先要pip install tkinter,但是我不知道是因為我已經裝過還是我現在的python版本已經跟著下載下來了,反正先在cmd打就對了。
程式碼我擷取解釋。

from tkinter import Tk, Label, Entry, Button,StringVar
import tkinter.font as tkFont
import random

mainWin = Tk()
mainWin.title("RSA生成器")
mainWin.geometry("250x200")

跟我們的Flask相同,我們要先創建一個實例。
接著將我們的title和UI大小進行設定

ft = tkFont.Font(family='Fixdsys', size=20, weight=tkFont.BOLD)
firstNumLabel = Label(mainWin, text="公鑰",font=ft)
secondNumLabel = Label(mainWin, text="私鑰",font=ft)
public_key=StringVar()
private_key=StringVar()
firstNum = Entry(mainWin, text=public_key)
secondNum = Entry(mainWin, text=private_key)

這一段是將我們會使用的類別顯現出來。
我們需要用到兩個提醒我們此方框內容是什麼的Label(公鑰私鑰)
還需要兩個文字框,這樣到時候公鑰私鑰生成後我們可以直接複製貼上。
StringVar就放入我們的文字框內

def factor(n):
	divisor = 2
	factors = []
	while divisor * divisor <= n:
		if n % divisor:
			divisor += 1
		else:
			n //= divisor
			factors.append(divisor)

	if n > 1:
		factors.append(n)
	if len(factors)==1:
		factors=[1,1]
	return factors

這是計算質因數的函式,此為此網站提供。

def cal():
	prime=[10000000~9999999999的質數]
	
	p,q=random.sample(prime,k=2)
	n = p * q
	fn = (p-1) * (q-1)
	e,d=random.sample(factor(fn+1),k=2)
	while e==d :
		p,q=random.sample(prime,k=2)
		n = p * q
		fn = (p-1) * (q-1)
	e,d=random.sample(factor(fn+1),k=2)
	
	public_key.set("("+str(e)+","+str(n)+")")
	private_key.set("("+str(d)+","+str(n)+")")

這就是我們計算公私鑰的程式碼,算式方法取自RSA計算器
prime部分太長,所以我就略減了。

Btn = Button(mainWin, text="生成",command=cal,font=ft)

接著不要忘記我們要生成公私鑰的按鈕,之所以不是放在上方跟大家一啟生出類別是因為上方無cal函式。

firstNumLabel.grid(row=0,column=0)
firstNum.grid(row=0,column=2)
secondNumLabel.grid(row=1,column=0)
secondNum.grid(row=1,column=2)
Btn.place(x=120,y=120)

mainWin.mainloop()

此部分為版面配置,配置好後就可以執行囉~

接著我要說另外一件事,雖然會來到it邦的……應該都是已經學會程式,並且能力非常厲害(我除外)的人,但是我寫這個的時候想的是 能不能讓完全不懂程式碼的人使用呢?
那要怎麼將程式碼打包成exe檔呢?
就要使用pyinstaller啦~首先要pip install pyinstaller
等它安裝完就直接又在cmd下pyinstaller -F rsa.py -w
他就會生成你想要的exe檔囉~
pyinstaller -F rsa.py 是將程式打包成exe,rsa.py是我們剛剛計算rsa的檔案名。
-w則可以將背景執行的console不顯示~
^w^來看看影片吧~

那明天就到了我們的MySQL和Python連接囉~
是說雖然我沒上過資料庫程式設計只上過概論(而且還完全不知道發生什麼的過了XD)但是實際操作後可能是因為用的很粗淺~感覺有點有趣XD
終於碰了自己一直規避的問題~感謝鐵人賽~

事隔四天_
我今天才發現原來……別人已經幫我們寫好RSA。
所以讓我們來修整我們的公私鑰生成器吧。

from tkinter import Tk, Label, Entry, Button,StringVar
import tkinter.font as tkFont
import rsa

mainWin = Tk()
mainWin.title("RSA生成器")
mainWin.geometry("250x200")

ft = tkFont.Font(family='Fixdsys', size=20, weight=tkFont.BOLD)
firstNumLabel = Label(mainWin, text="公鑰",font=ft)
secondNumLabel = Label(mainWin, text="私鑰",font=ft)
public_key=StringVar()
private_key=StringVar()
firstNum = Entry(mainWin, text=public_key)
secondNum = Entry(mainWin, text=private_key)

def cal():
	(pubkey, privkey) = rsa.newkeys(1024)
	public_key.set(pubkey)
	private_key.set(privkey)

firstNumLabel.grid(row=0,column=0)
firstNum.grid(row=0,column=2)
secondNumLabel.grid(row=1,column=0)
secondNum.grid(row=1,column=2)
Btn.place(x=120,y=120)

mainWin.mainloop()

我覺得以我目前的狀態就是……啞口無言
想講話,可是又悲傷QAQ 蠢的一批
自己寫個毛線啊寫!


上一篇
慢慢帶你了解Flask - Day18 個人單字書(5):簽到
下一篇
慢慢帶你了解Flask - Day20 Secret Talk(2):MySQL安裝和Python操作MySQL
系列文
慢慢帶你了解Flask30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言