前段時間寫了一個python程序,涉及http請求和數據的加密解密,終于完成了,雖然經歷很長的時間,填了很多坑,但是值得記錄一下,分享出來。由于是在簡書的第一篇文章,理應是滿滿的干貨。
這個需求的背景是這樣的,需要把公司的用戶加以區分,分為內部用戶和外部用戶,通過什么來區分的,當然是通過手機號比較簡單容易了,所以就定下來用手機號區分。但是獲取手機號對于公司的高層來說,可能覺得有點安全隱患,為了保險就對數據進行加密解密,方法就是請求方發送請求的時候,把公鑰發過去,同時也有其他的一些參數,對方根據公鑰加密,返回數據,請求方再根據私鑰解密。【后來和其他同事說起這個事情的時候,他說這樣好像并沒有什么卵用,因為是自己發送公鑰,收到數據自己再解密,如果其他人知道了這個方法和傳輸的參數,他也可以獲取到數據,我感覺真的是這么回事啊。】
現在來說一下這個曲折的過程。
1、調用java接口
2、確定使用加密的算法
3、分段解密
具體過程是這樣的:
1、對于http請求來說,相對簡單一些,在網上可以找到現成的例子,需要注意的就是把header里面的內容寫對,Content-type,Accept要注意,我這邊接收的是json格式的數據,所以accept是application/json,下面是我在網上搜的一個例子。
#!/usr/bin/env python
#coding=utf8
import httplib, urllib
httpClient = None
try:
params = urllib.urlencode({'name': 'tom', 'age': 22})
headers = {"Content-type": "application/x-www-form-urlencoded"
, "Accept": "text/plain"}
httpClient = httplib.HTTPConnection("localhost", 80, timeout=30)
httpClient.request("POST", "/test.php", params, headers)
response = httpClient.getresponse()
print response.status
print response.reason
print response.read()
print response.getheaders() #獲取頭信息
except Exception, e:
print e
finally:
if httpClient:
httpClient.close()
如果接口可以調通,那么status應該是200,reason是OK,如果出現其他的狀態碼,就要具體分析了。
2、一般很快就可以調通了,之后就是處理返回的數據。對于加密解密有的說了,我在網上搜了一下,對于python有很多的模塊可以操作,但是最后選擇了M2Crypto進行操作。【由于服務器python版本的限制吧,本地可以使用的,在服務器上卻不可以使用】之前嘗試使用RSA來操作,但是由于我給接口傳的PublicKey的類型、長度有問題,導致一直無法返回數據,接口接受的PublicKey是一串字符串,而我曾經把RSA生成的Publickey整體傳給了對方,后來一起調的時候,各自測試發現了參數類型不一致,以及PublicKey的長度不一致,這個時候我覺得可能是參數key的算法不一致導致的長度不一致,中間也換了其他的模塊,不過失敗了,最后選擇用openssl產生PublicKey,PrivateKey,這個時候的PublicKey和對方java產生的長度一樣了,終于可以看到返回的數據了。
下面是在python中使用openssl產生公鑰和私鑰
os.system('rm ./privatekey.pem ./publickey.pem')
os.system('openssl genrsa -out ./privatekey.pem')
os.system('openssl rsa -pubout -in ./privatekey.pem -out ./publickey.pem')
不過,我還是高興的太早了,數據是返回了,但是還沒有解密啊。解密也是很頭疼的,本以為用函數就可以解密了,結果還是調了半天,中間還有一個環節,就是用base64進行編碼,這又涉及了解碼的過程。所以,我拿到數據之后先進行解碼,解碼之后再解密。
當然獲取的數據需要轉換一下格式,json字符串轉換為python可以處理的字典
data = = json.loads(response.read())
base64這個庫不需要安裝,引入就可以了,我最開始還傻乎乎的安裝
data = base64.b64decode(data)
你以為現在就可以解密了么,too young too simple,你知道對方是根據什么模式進行填充加密塊么,也就是padding參數是什么,這個參數有四個值:no_padding,pkcs1_padding,sslv23_padding,pkcs1_oaep_padding,當我問對方的時候,對方一臉懵B的看著我,我只能挨個試一下了,反正也就四個么,試下來是pkcs1_padding,可能默認的就是這個吧,具體沒有深究。
3、確定好這個參數之后,就是激動人心的時刻了,運行之后終于可以看到人類可以看懂的數據了,可是依然有一個問題,當我修改了一個參數之后,竟然又報錯了,錯誤沒有記下來,反正就是數據比較大的意思,這其實是超過解密算法的能力了,對于1024位的秘鑰,加密字節最長為117,解密字節最長為128,所以需要分段解密才可以。接下來就是分段解密了,這個網上也可以搜到。
def decodeSplit(message,clientPriKey):
"""
消息在傳送過來之前是經過base64加密的,所以要先進行base64解密后才進行RSA分段解密
64為key.size/8,密鑰長度為512
"""
message = base64.b64decode(base64.b64decode(message))
count = len(message)
if count>64:
jiemi=""
index=0
while index<count:
i = 64 if count-index>64 else count-index
submsg = message[index:index+i]
index+=i
j = rsa.decrypt(submsg,clientPriKey)
jiemi+=j
return jiemi
else:
jiemi = rsa.decrypt(message,clientPriKey)
return jiemi
這個弄好了就可以看到完整的數據了,終于大功告成。
以下為參考資料,可能不完整,如果遺漏請諒解,如有侵權,請聯系。
參考資料:
1、http://hgoldfish.com/blogs/article/57/
2、http://betazk.github.io/2014/10/python%E8%BF%9E%E6%8E%A5.net%E7%AB%AF%E9%81%87%E5%88%B0%E7%9A%84%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98%E5%9B%9E%E9%A1%BE/
3、http://blog.csdn.net/nyist327/article/details/48352253