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/

posted @ 2021-08-21 19:50  Dba_sys  阅读(1601)  评论(0编辑  收藏  举报