題目來自:Python 練習(xí)冊(cè)。題目1.9: 通常递鹉,登陸某個(gè)網(wǎng)站或者 APP盟步,需要使用用戶名和密碼。密碼是如何加密后存儲(chǔ)起來的呢躏结?請(qǐng)使用 Python 對(duì)密碼加密却盘。
查看更多于本人博客:iii.run
思路:salt 加 hash 來單向轉(zhuǎn)換密碼明文
參考代碼
以下給出Py2和Py3兩段代碼,輸出的內(nèi)容是一樣的。因?yàn)榧用苤蟮膬?nèi)容不是unicode代碼谷炸,所以存儲(chǔ)可能不方便北专,可以使用base64.b64encode(hashed)
轉(zhuǎn)化為base64編碼格式。
Python2代碼
import os,base64
from hashlib import sha256
from hmac import HMAC
def encrypt_password(password, salt=None):
"""Hash password on the fly."""
if salt is None:
salt = os.urandom(8) # 64 bits.
assert 8 == len(salt)
assert isinstance(salt, str)
if isinstance(password, unicode):
password = password.encode('UTF-8')
assert isinstance(password, str)
result = password
for i in xrange(10):
result = HMAC(result, salt, sha256).digest()
return salt + result
def validate_password(hashed, input_password):
return hashed == encrypt_password(input_password, salt=hashed[:8])
if __name__=="__main__":
hashed = encrypt_password('secret password')
assert validate_password(hashed, 'secret password')
print (hashed)
print (base64.b64encode(hashed))
print (base64.b64decode(base64.b64encode(hashed)))
Python3代碼
import os, base64
from hashlib import sha256
from hmac import HMAC
def encrypt_password(password, salt=None):
"""Hash password on the fly."""
if salt is None:
salt = os.urandom(8) # 64 bits.
assert 8 == len(salt)
assert isinstance(salt, bytes)
assert isinstance(password, str)
if isinstance(password, str):
password = password.encode('UTF-8')
assert isinstance(password, bytes)
result = password
for i in range(10):
result = HMAC(result, salt, sha256).digest()
return salt + result
def validate_password(hashed, input_password):
return hashed == encrypt_password(input_password, salt=hashed[:8])
if __name__ == "__main__":
hashed = encrypt_password('secret password')
assert validate_password(hashed, 'secret password')
print (hashed)
print (base64.b64encode(hashed))
print (base64.b64decode(base64.b64encode(hashed)))
Python編碼問題
一開始直接在Python3環(huán)境運(yùn)行第一段代碼的時(shí)候旬陡,總會(huì)報(bào)錯(cuò)NameError: global name 'unicode' is not defined
拓颓,百思不得其解。
查了資料描孟,才發(fā)現(xiàn)是因?yàn)镻ython更新的時(shí)候驶睦,Python 3 renamed the unicode type to str, the old str type has been replaced by bytes。在Python升級(jí)文檔內(nèi)可以查到相關(guān)內(nèi)容匿醒,也就是unicode直接改名str场航,str改名成bytes。
Python2和Python3廉羔,在編碼方面挖下太多的坑
舉個(gè)簡(jiǎn)單的例子:
isinstance(u'中文', unicode) #python2內(nèi)是正確的
isinstance(u'中文', str) #python3內(nèi)是正確的
Python3內(nèi)的unicode和bytes
Python 3最重要的新特性大概要算是對(duì)文本和二進(jìn)制數(shù)據(jù)作了更為清晰的區(qū)分溉痢。文本總是Unicode,由str類型表示憋他,二進(jìn)制數(shù)據(jù)則由bytes類型表示孩饼。
在將字符串存入磁盤和從磁盤讀取字符串的過程中,Python 自動(dòng)地幫你完成了編碼和解碼的工作竹挡,你不需要關(guān)心它的過程镀娶,例如你能把一個(gè)中文賦值給字符串。而使用 bytes 類型揪罕,實(shí)質(zhì)上是告訴 Python梯码,不需要它幫你自動(dòng)地完成編碼和解碼的工作,而是用戶自己手動(dòng)進(jìn)行好啰,并指定編碼格式轩娶。
參考鏈接:
http://zhuoqiang.me/password-storage-and-python-example.html
http://www.ituring.com.cn/article/61192