Mayx's Home Page https://mabbs.github.io
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
10 KiB

  1. ---
  2. layout: post
  3. title: 加密传输Demo V2
  4. tags: [加密, Demo]
  5. ---
  6. 太业余总感觉不太好啊<!--more-->
  7. # 前言
  8. 在上个月我写了一个[加密传输的Demo](/2020/05/29/encrypt.html),相当的业余,这个东西只能做到从客户端向服务端的单向传输,而且因为只有一次请求,所以中间人攻击也非常的容易。
  9. 虽然我觉得那个应该足够我完成作业了,但是我想了想,太业余总显得我很菜 ~~(难道不是吗?)~~ ,所以我打算还是努力一下把完整的握手也做出来吧。
  10. # 实现思路
  11. 和上次差不多,同样我打算通过RSA加密一个随机数作为AES的密钥,但是和上次不同,这次的这个密钥将在通信建立之后密钥就不再变化,传入传出都是这个密钥。
  12. 之前觉得握手阶段可能很麻烦,不过我画了一下图稍微理了理思路发现其实也没多复杂,也就是客户端生成密钥然后加密传输过来让服务端保存,完成之后之间的传输只要传被加密的数据就行了。这样我觉得应该也能起到一定的防止中间人攻击的作用吧……
  13. 不过我只用了一个文件作为传输的管道,为了避免冲突,我在每次写入数据的时候也都标明了数据的来源,这样就不会因为自己刚发完然后自己又重新接收自己发的东西了。
  14. 另外老师希望我的Demo有个简单的应用,所以我又另外加了一个极其简单的登录系统在里面,这样我就不用手动操作服务端了。
  15. # 代码
  16. ## server.py
  17. ```python
  18. # -*- coding: utf-8 -*-
  19. print("加密通道服务端演示开始")
  20. from Crypto.PublicKey import RSA
  21. from Crypto.Cipher import PKCS1_v1_5
  22. from Crypto.Cipher import AES
  23. import base64
  24. import hashlib
  25. import json
  26. import time
  27. private_key = """-----BEGIN RSA PRIVATE KEY-----
  28. MIICXQIBAAKBgQDfEQ82qUrto7h4BL3TsA/DFXSdM44cbeY4kPccD7gLGhaZRClz
  29. YKIh5zYdfjBGF+0HXfMa1u9b7GNs2AjVIsx8Kx0QLnMfmtkmGWGhOXz/9IDLKJOx
  30. 0weKv61gysKItgzVKn2mbLool4R/PQBc3AjDyHw+io1KpVz+3kRTaGs1fQIDAQAB
  31. AoGAWB4kFWLA/6k6OOcemd4mC9mQ7HyuOdrMJDJX+5TWDkSrArajbTmSMrRkczgj
  32. F71h3BQn8cVQXs695ARfUNrjTbi2Y0LjN7ScK7ExzTLdoMEFw5JsHggJZ0zBQY6w
  33. mwOdGfqzA6tZPXgkn+jqEha+CD6GrwnTM1oDGJC/aKG2OmECQQDkO9IhUhFc/PSU
  34. 0zvGE6AOcqk5wlOuvMg+oAFHJHJZ9XW7+X/Nx0ZoVDFq/cZQj+46t+fiwUwhdW7l
  35. IfCvNGKFAkEA+jRQmWGKrbf1ns4S0SezJvysd5O6otRGJXr+Ex2uDhc39ZTeUsyg
  36. kjrLhp8STLMOmql+8g5fghct17EuCX1EmQJBAJz9BNnEkIrst/OSpH/nyeWGOx6u
  37. q077LaXd+2MLD9kO/O/Se3V5B9YFa4STkJCjoBMloswXd51gIGpdgSeSmd0CQQCL
  38. PrwwcGmWfo+ynqs4PajlpK9zKQMwhYS4bTejedwZOXDKOtx0Ji+i0hfcxwCPMQOK
  39. rZPZsIgUxUOdC508aLvZAkBDkHxunCzDm0w4DdTUN7S9YSpVvQEjK/xUQiWaKV12
  40. 8QgskhU2DNdYK2NxifnWrKtx3uQmqMxX5aLuJZ4493yr
  41. -----END RSA PRIVATE KEY-----"""
  42. # 公钥解密
  43. def rsa_decode(cipher_text, private_key):
  44. rsakey = RSA.importKey(private_key) # 导入读取到的私钥
  45. cipher = PKCS1_v1_5.new(rsakey) # 生成对象
  46. # 将密文解密成明文,返回的是一个bytes类型数据,需要自己转换成str
  47. text = cipher.decrypt(base64.b64decode(cipher_text), "ERROR")
  48. return text.decode()
  49. class PrpCrypt(object):
  50. def __init__(self, key):
  51. self.key = key.encode('utf-8')
  52. self.mode = AES.MODE_CBC
  53. def encrypt(self, text):
  54. text = text.encode('utf-8')
  55. cryptor = AES.new(self.key, self.mode, b'0000000000000000')
  56. # 这里密钥key 长度必须为16(AES-128),
  57. # 24(AES-192),或者32 (AES-256)Bytes 长度
  58. # 目前AES-128 足够目前使用
  59. length = 16
  60. count = len(text)
  61. if count < length:
  62. add = (length - count)
  63. # \0 backspace
  64. # text = text + ('\0' * add)
  65. text = text + ('\0' * add).encode('utf-8')
  66. elif count > length:
  67. add = (length - (count % length))
  68. # text = text + ('\0' * add)
  69. text = text + ('\0' * add).encode('utf-8')
  70. self.ciphertext = cryptor.encrypt(text)
  71. # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
  72. # 所以这里统一把加密后的字符串转化为16进制字符串
  73. return base64.b64encode(self.ciphertext)
  74. # 解密后,去掉补足的空格用strip() 去掉
  75. def decrypt(self, text):
  76. cryptor = AES.new(self.key, self.mode, b'0000000000000000')
  77. plain_text = cryptor.decrypt(base64.b64decode(text))
  78. # return plain_text.rstrip('\0')
  79. return bytes.decode(plain_text).rstrip('\0')
  80. #初始化pipe
  81. file = open('pipe.txt','w')
  82. print("",file = file)
  83. file.close()
  84. #协商密钥
  85. while True:
  86. pipe = open("pipe.txt", mode='r')
  87. data = pipe.read()
  88. if not data == "\n":
  89. data = json.loads(data)
  90. pipe.close()
  91. break
  92. pipe.close()
  93. time.sleep(1)
  94. file = open('pipe.txt','w')
  95. print("",file = file)
  96. file.close()
  97. key = rsa_decode(data["key"], private_key)
  98. akey = PrpCrypt(key)
  99. print("成功获取密钥",key)
  100. print("已建立连接")
  101. userInfo={"Name":"Mayx","Passwd":'25d55ad283aa400af464c76d713c07ad',"Book":"《会说话就多说点》,《在哪里能买到您的著作》"}
  102. #处理阶段
  103. #Waiting for Quest
  104. while True:
  105. pipe = open("pipe.txt", mode='r')
  106. data = pipe.read()
  107. if not data == "\n":
  108. data = json.loads(data)
  109. if data["from"] == "Client":
  110. pipe.close()
  111. break
  112. pipe.close()
  113. time.sleep(1)
  114. print("已收到请求")
  115. data = json.loads(akey.decrypt(data["data"]))
  116. if data["name"] == userInfo["Name"] and data["pwd"] == userInfo["Passwd"]:
  117. file = open('pipe.txt','w')
  118. print(json.dumps({"from":"Server","data":akey.encrypt("登录成功,您的书单如下:"+userInfo["Book"]).decode("utf-8")}),file = file)
  119. file.close()
  120. else:
  121. file = open('pipe.txt','w')
  122. print(json.dumps({"from":"Server","data":akey.encrypt("登录失败").decode("utf-8")}),file = file)
  123. file.close()
  124. print("请求已回应")
  125. print("加密通道服务端演示结束")
  126. ```
  127. ## client.py
  128. ```python
  129. # -*- coding: utf-8 -*-
  130. print("加密通道客户端演示开始")
  131. import random
  132. from Crypto.PublicKey import RSA
  133. from Crypto.Cipher import PKCS1_v1_5
  134. from Crypto.Cipher import AES
  135. import base64
  136. import hashlib
  137. import json
  138. import time
  139. public_key = """-----BEGIN PUBLIC KEY-----
  140. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfEQ82qUrto7h4BL3TsA/DFXSd
  141. M44cbeY4kPccD7gLGhaZRClzYKIh5zYdfjBGF+0HXfMa1u9b7GNs2AjVIsx8Kx0Q
  142. LnMfmtkmGWGhOXz/9IDLKJOx0weKv61gysKItgzVKn2mbLool4R/PQBc3AjDyHw+
  143. io1KpVz+3kRTaGs1fQIDAQAB
  144. -----END PUBLIC KEY-----
  145. """
  146. # 公钥加密
  147. def rsa_encode(message, public_key):
  148. rsakey = RSA.importKey(public_key) # 导入读取到的公钥
  149. cipher = PKCS1_v1_5.new(rsakey) # 生成对象
  150. # 通过生成的对象加密message明文,注意,在python3中加密的数据必须是bytes类型的数据,不能是str类型的数据
  151. cipher_text = base64.b64encode(cipher.encrypt(message.encode(encoding="utf-8")))
  152. # 公钥每次加密的结果不一样跟对数据的padding(填充)有关
  153. return cipher_text.decode()
  154. class PrpCrypt(object):
  155. def __init__(self, key):
  156. self.key = key.encode('utf-8')
  157. self.mode = AES.MODE_CBC
  158. # 加密函数,如果text不足16位就用空格补足为16位,
  159. # 如果大于16当时不是16的倍数,那就补足为16的倍数。
  160. def encrypt(self, text):
  161. text = text.encode('utf-8')
  162. cryptor = AES.new(self.key, self.mode, b'0000000000000000')
  163. # 这里密钥key 长度必须为16(AES-128),
  164. # 24(AES-192),或者32 (AES-256)Bytes 长度
  165. # 目前AES-128 足够目前使用
  166. length = 16
  167. count = len(text)
  168. if count < length:
  169. add = (length - count)
  170. # \0 backspace
  171. # text = text + ('\0' * add)
  172. text = text + ('\0' * add).encode('utf-8')
  173. elif count > length:
  174. add = (length - (count % length))
  175. # text = text + ('\0' * add)
  176. text = text + ('\0' * add).encode('utf-8')
  177. self.ciphertext = cryptor.encrypt(text)
  178. # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
  179. # 所以这里统一把加密后的字符串转化为16进制字符串
  180. return base64.b64encode(self.ciphertext)
  181. # 解密后,去掉补足的空格用strip() 去掉
  182. def decrypt(self, text):
  183. cryptor = AES.new(self.key, self.mode, b'0000000000000000')
  184. plain_text = cryptor.decrypt(base64.b64decode(text))
  185. # return plain_text.rstrip('\0')
  186. return bytes.decode(plain_text).rstrip('\0')
  187. #初始化阶段
  188. while True:
  189. try:
  190. pipe = open("pipe.txt", mode='r')
  191. except:
  192. time.sleep(1)
  193. else:
  194. break
  195. pipe.close()
  196. #协商密钥
  197. key = str(random.randint(1000000000000000,9999999999999999))
  198. akey = PrpCrypt(key)
  199. cipher = rsa_encode(key, public_key)
  200. data = json.dumps({"key":cipher})
  201. file = open('pipe.txt','w')
  202. print(data,file = file)
  203. file.close()
  204. while True:
  205. pipe = open("pipe.txt", mode='r')
  206. if pipe.read() == "\n":
  207. pipe.close()
  208. break
  209. pipe.close()
  210. time.sleep(1)
  211. print("成功发送密钥",key)
  212. print("已建立连接")
  213. #处理阶段
  214. #Single Quest
  215. name = input("请输入用户名:")
  216. pwd = input("请输入密码:")
  217. hash = hashlib.md5(pwd.encode(encoding='UTF-8')).hexdigest()
  218. data = json.dumps({"from":"Client","data":akey.encrypt(json.dumps({"name":name,"pwd":hash})).decode("utf-8")})
  219. file = open('pipe.txt','w')
  220. print(data,file = file)
  221. file.close()
  222. print("已发出,等待回应")
  223. while True:
  224. pipe = open("pipe.txt", mode='r')
  225. data = pipe.read()
  226. if not data == "\n":
  227. data = json.loads(data)
  228. if data["from"] == "Server":
  229. pipe.close()
  230. break
  231. pipe.close()
  232. time.sleep(1)
  233. print("已收到回应")
  234. data = akey.decrypt(data["data"])
  235. print(data)
  236. print("加密通道客户端演示结束")
  237. ```
  238. # 后记
  239. 关于SSL/TLS的具体内容我也没有好好看一遍,我打算回头有时间仔细看一看,然后再回来看这个代码是有多么的糟糕🤪。

Powered by TurnKey Linux.