AI五子棋_05 公钥加解密 10进制转256进制
AI 五子棋 第五步
恭喜你到达第五步!
我想你一定很艰难,前一步的问题需要大数运算,因为这个算法依赖于质因数分解的复杂度,只有数字相当大时才能保证这个算法难于破解。
这是服务器使用的公钥:
- 65537,
135261828916791946705313569652794581721330948863485438876915508683244111694485850733278569559191167660149469895899348939039437830613284874764820878002628686548956779897196112828969255650312573935871059275664474562666268163936821302832645284397530568872432109324825205567091066297960733513602409443790146687029
`
你需要把你的密码使用公钥加密后交给服务器,当然在真正这么做之前,我们先做些准备:
- 验证:将数字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
-
验证:将字符串
hello, world!
转换为数字后作为str2num
字段提交到http://2**.2**.**.1**:9012//step_05
如果没有错误,我们进行下一步。转换后的字符串可以加密了。 -
验证:将字符串
hello, world!
转换为数字,使用公钥加密后作为str
字段提交到http://2**.2**.**.1**:9012/step_05
如果没有错误,我们进行下一步。加密后的数字可以用16进制表示,这样会短一点,我们秘钥长度为1024字节,使用16进制,一位16进制数可以表示4个字节,生成的加密数据有256位长,可以节省一点网络流量。 -
验证:将字符串
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/
如果我的工作对您有帮助,您想回馈一些东西,你可以考虑通过分享这篇文章来支持我。我非常感谢您的支持,真的。谢谢!
作者:Dba_sys (Jarmony)
转载以及引用请注明原文链接:https://www.cnblogs.com/asmurmur/p/15170420.html
本博客所有文章除特别声明外,均采用CC 署名-非商业使用-相同方式共享 许可协议。