AI五子棋_05 公鑰加解密 10進制轉256進制


AI 五子棋 第五步

恭喜你到達第五步!

我想你一定很艱難,前一步的問題需要大數運算,因為這個算法依賴於質因數分解的復雜度,只有數字相當大時才能保證這個算法難於破解。

這是服務器使用的公鑰:

  • 65537,
    135261828916791946705313569652794581721330948863485438876915508683244111694485850733278569559191167660149469895899348939039437830613284874764820878002628686548956779897196112828969255650312573935871059275664474562666268163936821302832645284397530568872432109324825205567091066297960733513602409443790146687029
    `
    你需要把你的密碼使用公鑰加密后交給服務器,當然在真正這么做之前,我們先做些准備:
  1. 驗證:將數字31415926使用公鑰加密后作為num字段提交到http://2**.2**.**.1**:9012/step_05
    如果沒有錯誤,我們進行下一步。我們這里加密的是數字,而密碼是個字符串,因此需要把字符串轉換為數字。轉換規則是這樣的:把所有字符轉換為ASCII,之后把字符串看作一個256進制的數,比如:
'abc'
'a' = 97, 'b' = 98, 'c' = 99
'abc' = 97*256^2 + 98*256^1 + 99*256^0 = 6382179
  1. 驗證:將字符串hello, world!轉換為數字后作為str2num字段提交到http://2**.2**.**.1**:9012//step_05
    如果沒有錯誤,我們進行下一步。轉換后的字符串可以加密了。

  2. 驗證:將字符串hello, world!轉換為數字,使用公鑰加密后作為str字段提交到http://2**.2**.**.1**:9012/step_05
    如果沒有錯誤,我們進行下一步。加密后的數字可以用16進制表示,這樣會短一點,我們秘鑰長度為1024字節,使用16進制,一位16進制數可以表示4個字節,生成的加密數據有256位長,可以節省一點網絡流量。

  3. 驗證:將字符串hello, world!轉換為數字,使用公鑰加密后轉換為16進制,作為hex字段提交到http://2**.2**.**.1**:9012/step_05
    如果沒有錯誤,我們進行下一步。你可以把你的密碼加密了。

任務 5

把你的用戶名作為user字段,加密后的密碼作為password字段,提交到.http://2**.2**.**.1**:9012/step_05

不要急着找下一步的地址。作為一個確定性的程序,你的密碼每次加密得到的結果都是一樣的,我們可以為密碼加噪,擾亂竊密者。在加密時,我們可以編碼的信息不大於公鑰中的第二個數字,這個數字很大,因此我們可以編碼很長的信息。

在c/c++中字符串以字符\0作為結束標志,\0以后的所有數據都會被忽略掉,因此我們可以在密碼后面添加一個字符\0,之后連接上一個隨機生成的沒用的字符串。這樣每次都會產生不同的密文,就能更有效的保護你的密碼了。去試試吧!

回到我們得到的信息,它也是被加密的,你需要解密,服務器使用它自己的私鑰加密了數據,因為秘鑰是對稱的,你可以用公鑰解密它。

待處理信息

無,提交用戶名密碼即可。

Python代碼實現

import requests as re

def fastModular(x):		# 快速冪模實現 也就是加解密算法
	"""x[0] = base """
	"""x[1] = power"""
	"""x[2] = modulus"""
	result = 1
	while(x[1] > 0):
		if(x[1] & 1):
			result = result * x[0] % x[2]
		x[1] = int(x[1]/2)		# 可用 x[1] >>= 2 位運算代替 更快
		x[0] = x[0] * x[0] % x[2]
	return result

def str_to_num(strings):
	"""將字符看作數字,以256進制的進位做加法"""
	"""返回一個十進制數字"""
	sum = 0
	lens = len(strings)
	for i in range(0,lens):
		sum += ord(strings[i])*256**(lens-i-1)
	return sum

def num_to_str(num):
        messageList = []
        while num != 0 :
                messageList.append(num%256)
                num = num // 256	# 整數除符號 不能用 int(num // 256)
        messageList.reverse()	# 返回None 同時列表本身被倒置修改
        decodeString = ''
        for i in messageList:
                decodeString += chr(i)
        return decodeString
        
# 公鑰
power = 65537
modulus = 135261828916791946705313569652794581721330948863485438876915508683244111694485850733278569559191167660149469895899348939039437830613284874764820878002628686548956779897196112828969255650312573935871059275664474562666268163936821302832645284397530568872432109324825205567091066297960733513602409443790146687029
password = 'XXXXX'
myHex = hex(fastModular([str_to_num(password),power,modulus]))		# 加密后的密碼
print(f"My encryption code is { myHex }")

param = {
        'user' : '1414081721',
        'password': myHex
        }

getHtml = re.get('http://2**.2**.**.1**:9012/step_05/', params = param)

prefix = '0x'		# 16進制前綴 后面int()用到
# 服務器返回的16進制字符串沒有前綴,加上前綴,將他轉化為數字,這個數字是經過加密的
# 將得到的數字用公鑰解密,得到字符串變為的數字,用逆方法解出
num = fastModular([int(prefix + getHtml.json()['message'],16),power,modulus])

print(num_to_str(num))

直接運行即可得到結果。

解題tips

通過 十進制轉 256進制的函數后,得到的結果只有 Hi 0191 t中間一堆空格。

用的是 num = int( num /256) 因為不加int會變成小數,這個方法將256進制的低位去除掉。可是得到一堆 0 的中間結果 可是還是能解出幾個字符。

一開始以為是密碼輸錯了,服務器回的信息是錯的。就拿QQ號注冊了一個賬號。這回是代碼的問題了。

那怎么改呢?這轉換函數可是一點錯都沒有 ,按照以前 C++的經驗。

如果有不一樣的地方

可能就在 int(num / 256) , 以前c++ 直接寫 num/256就可以得到。這個也不敢改,到晚上十點多,還是沒想出來。

想到程序員黃金法則,我就把它扔一遍去了。

第二天突然人來瘋,Python的進制轉換是怎么來的?

網上一搜,全是函數。根本沒有自己去實現的............

又搜 Python 十進制轉八進制 這是一個亮點。終於找到一個自己寫函數的大哥。

他寫的和c++差不多,但是 迭代的時候用的是 // 而不是那種int。

上網再搜 // 是整除 /是浮點除 立刻毛色頓開。

完善 10 -256 函數。得到答案~~~~~~

公鑰加密-密鑰交換算法

如何能在別人可以直接接觸我們的通信時,保護我們的傳遞的信息呢?類似郵遞員郵遞一張明信片。他們可以看到我們任何的通信內容。

實話說現在的網絡技術還真就是這樣,包括http傳輸,都是明擺着的信息,別人能看到為什么不看?所以現在基本都變成https加密形式了。

我們想到讓信息變成加密的形式。可這個加解密的一致性的協商過程也是可以被人看到的。

公鑰加密-密鑰交換算法就是通過公鑰私鑰來來進行協商

使看到整個協商過程的人,也不知道怎么去破解。

這篇文章講的使 運用冪和鍾算混合數字。這個機制是由 Martin Hellman and Whitfield Diffie於1976年首次發表的。只有協商雙方可以獲得到共享密鑰的數字。KEA

第一步:協商雙方各自單獨選擇一個私人數字。

第二步:對鍾的大小11 基數2達成一致 兩個公開數字。

第三步:通過使用冪符號和鍾算,雙方將各自的私人數字和公開數字混合,分別得到一個公開私人數字。public-private number PPN

  • PPN = base ^ 私人數字 mod 鍾大小。

第四步: 將對方公開的PPN和自己的私人數字混合。可以得到共享密鑰。雙方得到的共享密鑰是一致的。

  • 共享密鑰 = 其他人的PPN ^ 自己的私人數字 mod 鍾大小

可以建立一個等式

(base ^ A私人數字 mod 鍾大小) ^ B私人數字 mod 鍾大小 = (base ^ B私人數字 mod 鍾大小) ^ A私人數字 mod 鍾大小

利用模運算的引理

(base ^ A私人數字 ) ^ B私人數字 mod 鍾大小 = (base ^ B私人數字 ) ^ A私人數字 mod 鍾大小

這個方法要求鍾(模數)的大小使必須是一個素數,而基數必須是鍾(模數)大小的本源根。本原根是數學內的一種術語。

如果使得a^m≡1 mod n成立的最小正冪m滿足m=φ(n),則稱a是n的本原根。 其中φ(n)為歐拉函數

加油吧少年,根據這個博客你也可以寫出一個相對智能的五子棋程序,甚至更強的AI算法!

文章會隨時改動,注意到博客里去看。一些網站會爬取本文章,但是可能會有出入。
https://www.cnblogs.com/asmurmur/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM