1. 程式人生 > 其它 >【專題】Python加密模組hashlib的使用

【專題】Python加密模組hashlib的使用

技術標籤:Python基礎與進階python

Python加密模組hashlib的使用

一、加密演算法介紹

  • 什麼是加密演算法呢?加密演算法又稱雜湊演算法、雜湊演算法。它通過一個函式,把任意長度的資料轉換為一個長度固定的資料串(通常用16進位制的字串表示)。
  • 加密演算法就是通過加密演算法f()對任意長度的資料data計算出固定長度的密文hexdigest,目的是為了發現原始資料是否被人篡改過。
  • 加密演算法之所以能指出資料是否被篡改過,就是因為摘要函式是一個單向函式,計算f(data)很容易,但通過digest反推data卻非常困難。而且,對原始資料做一個bit的修改,都會導致計算出的摘要完全不同。

二、MD5加密演算法

以常見的加密演算法MD5為例,計算一個字串的MD5值:

import hashlib

md5 = hashlib.md5()
# update函式的加密文字:英文必須是ASCII的二進位制格式
md5.update(b'how are you?I fine, and you?')
print(md5.hexdigest())

輸出結果:c61e87d5b1883b97428e02df773ba377

md5 = hashlib.md5()
# update函式如果不是ASCII格式,則必須對文字進行編碼,否則會報錯
md5.update("天王蓋地虎"
.encode('utf-8')) print(md5.hexdigest())

輸出結果:151df4d2ddbdd1ad6a64c2c18b294828

統一上述的寫法,將待加密的漢字或者英文content都可以直接先按照utf-8格式編碼。即:

import hashlib

md5 = hashlib.md5()
content= input('請輸入待加密的文字內容:')
md5.update(content.encode('utf-8'))
print(md5.hexdigest())

如果資料量很大,可以分塊多次呼叫update(),最後計算的結果是一樣的:

import hashlib

md5 =
hashlib.md5() md5.update(b'how are you?') md5.update(b'I fine, and you?') print(md5.hexdigest())

輸出的結果也是c61e87d5b1883b97428e02df773ba377

可以看到和上面的加密結果一模一樣。一般稍微改動一個字母或者字元,該演算法計算出來的結果完全不同。MD5是最常見的摘要演算法,速度很快,生成結果是固定的128 bit位元組,通常用一個32位的16進位制字串表示。

三、sha1加密演算法

除了MD5摘要演算法外,比較常用的摘要演算法還有SHA1,呼叫SHA1和呼叫MD5完全類似:

import hashlib

sha1 = hashlib.sha1()
sha1.update(b'how are you?')
sha1.update(b'I fine, and you?')
print(sha1.hexdigest())

輸出結果:3782065e98449054afc40c8dc23de53778703982
SHA1的結果是160 bit位元組,通常用一個40位的16進位制字串表示。

有沒有可能兩個不同的資料通過某個加密演算法得到了相同的密文?完全有可能,因為任何摘要演算法都是把無限多的資料集合對映到一個有限的集合中。這種情況稱為碰撞。

四、加密演算法應用場景

任何允許使用者登入的網站都會儲存使用者登入的使用者名稱和密碼。如何儲存使用者名稱和密碼呢?方法是存到資料庫表中:

usernamepassword
Chimu123456
TrainingLabc123
Daimaoabcdef

如果以明文儲存使用者密碼,如果資料庫洩露,所有使用者的密碼就落入黑客的手裡。此外,網站運維人員是可以訪問資料庫的,也就是能獲取到所有使用者的密碼。這樣對使用者資訊或者資料而言是極不安全的,我們往往希望的是,只有使用者自己知道自己的密碼。

import hashlib

md5 = hashlib.md5()
password = input("待加密的明文密碼:")
md5.update(password.encode('utf-8'))
print(md5.hexdigest())

在這裡插入圖片描述
正確的儲存密碼的方式是不儲存使用者的明文密碼,而是儲存使用者密碼的密文,比如MD5:

usernamepassword
Chimue10adc3949ba59abbe56e057f20f883e
TrainingLe99a18c428cb38d5f260853678922e03
Daimaoe80b5017098950fc58aad83c8c14978e
  • 當用戶登入時,首先計算使用者輸入的明文密碼的MD5,然後和資料庫儲存的MD5對比,如果一致,說明密碼輸入正確,如果不一致,密碼肯定錯誤。
  • 儲存MD5的好處是即使運維人員能訪問資料庫,也無法獲知使用者的明文口令。

設計一個驗證使用者登入的函式,根據使用者輸入的口令是否正確,返回True或False:

import hashlib

# 儲存使用者資訊的資料表:db.user
db = {
    'Chimu':'e10adc3949ba59abbe56e057f20f883e',
    'TrainingL':'e99a18c428cb38d5f260853678922e03',
    'Daimao':'e80b5017098950fc58aad83c8c14978e'
}

def login(username,password):
    md5 = hashlib.md5()
    md5.update(password.encode('utf-8'))
    if username in db.keys():
        if md5.hexdigest() == db[username]:
            print("歡迎登陸!")
        else:
            print('密碼錯誤,請重試!')
    else:
        print("使用者不存在,先註冊!")

username = input("請輸入使用者名稱:")
password = input("請輸入密碼:")
login(username,password)

執行效果截圖:
在這裡插入圖片描述
由於常用口令的MD5值很容易被計算出來,所以,要確保儲存的使用者口令不是那些已經被計算出來的常用口令的MD5,這一方法通過對原始口令加一個複雜字串來實現,俗稱“加鹽”:

經過Salt處理的MD5口令,只要Salt不被黑客知道,即使使用者輸入簡單口令,也很難通過MD5反推明文口令。

將上述的加密驗證需求改進之後如下:

import hashlib,random

def get_md5(s):
    return hashlib.md5(s.encode('utf-8')).hexdigest()
    
class User(object):
    def __init__(self,username,password):
        self.username = username
        self.salt = ''.join([chr(random.randint(48,122)) for i in range(20)])
        self.password = get_md5(password + self.salt)

db = {
    'chimu': User('michael', '123456'),
    'trainingl': User('bob', 'abc123'),
    'daimai': User('alice', 'abcdef')
}

def login(username,password):
    user = db[username]
    pwd = get_md5(password + user.salt)
    return user.password == pwd

print(login('bob',"abc999"))

五、小結

摘要演算法在很多地方都有廣泛的應用。要注意摘要演算法不是加密演算法,不能用於加密(因為無法通過摘要反推明文),只能用於防篡改,但是它的單向計算特性決定了可以在不儲存明文口令的情況下驗證使用者口令。

參考廖雪峰老師的Python教程