hashlib提供不同的安全雜湊/安全雜湊(Secure Hash Algorithm)和 資訊摘要演算法(Message Digest Algorithm),hashlib模組支援業界主流常見的一些加密演算法,如md5、sha1、sha256、sha384、sha 512、hmac加密等。
hash
雜湊(Hash)算法是一種用在資料編碼中的技術。
EX: SecTools.tw -> hash generator -> 302e5748216d79c3dc6e37bcd2eeccbf
hash function
雜湊函式(英語:Hash function)又稱雜湊演算法,是一種從任何一種資料中建立小的數字「指紋」的方法。雜湊函式把訊息或資料壓縮成摘要,使得資料量變小,將資料的格式固定下來。該函式將資料打亂混合,重新建立一個叫做雜湊值(hash values,hash codes,hash sums,或hashes)的指紋。雜湊值通常用一個短的隨機字母和數字組成的字串來代表。[1]好的雜湊函式在輸入域中很少出現雜湊衝突。在雜湊表和資料處理中,不抑制衝突來區別資料,會使得資料庫記錄更難找到。
如今,雜湊演算法也被用來加密存在資料庫中的密碼(password)字串,由於雜湊演算法所計算出來的雜湊值(Hash Value)具有不可逆(無法逆向演算回原本的數值)的性質,因此可有效的保護密碼。 – 取自維基百科
hashlib 支援演算法
sha()、sha224()、sha256()、sha384()、sha512()、blake2b()、sha3_224()、sha3_256()、sha3_384()、sha3_512()、shake_128()、shake_256()。
Hashlib現在使用來自OpenSSL 1.1.1和更高版本的SHA3和SHAKE。
訊息摘要
Secure Hash Algorithm(SHA)能計算出一個數位訊息所對應到,長度固定的字串(又稱訊息摘要)的演算法,計算出來的數位訊息是一個固定長度字串。
import hashlib
m = hashlib.sha256()
m.update(b"SecTools.tw is best platform")
print(m.digest())
得到的結果會是
b'\x05!I\xf0\xb6\x94.t\x96\xfc\xaaK\xf55\x86,>\xb2"s\xeb@\xdb\xb7\x01I\x89\xf5\x98\xe3$\x0f'
計算一下訊息摘要長度
print(m.digest_size) #32
print(m.block_size) #64
這時同時對不同的明文進行加密,會發現兩者產生的字串長度是相同的。
import hashlib
m = hashlib.sha256()
m.update(b"SecTools.tw is best platform")
print(m.digest_size)
print(m.block_size)
m = hashlib.sha256()
m.update(b"SecTools.tw is the best")
print(m.digest_size)
print(m.block_size)
方法
hashlib.new
(name, [data, ]*, usedforsecurity=True)
選擇一個演算法。
h = hashlib.new('sha512_256')
hashlib.algorithms_guaranteed
顯示平台可用的hash演算法集合。
{'blake2s', 'shake_256', 'sha224', 'md5', 'shake_128', 'sha1', 'sha384', 'sha3_384', 'sha3_512', 'sha3_256', 'sha512', 'sha256', 'sha3_224', 'blake2b'}
hashlib.algorithms_available
當前python環境可用的演算法。 SecTools.tw 寫這篇文章時的環境是 Python 3.9.2
{'sha3_512', 'sha384', 'sm3', 'blake2s', 'ripemd160', 'md4', 'mdc2', 'sha3_384', 'sha512_224', 'shake_128', 'whirlpool', 'sha3_224', 'sha1', 'sha224', 'shake_256', 'sha512', 'sha3_256', 'sha256', 'md5-sha1', 'sha512_256', 'blake2b', 'md5'}
hash的大小。
hash的內部塊大小。
屬性
hash.update
(data)
將字串更新至hash目標。 data => “要加密的字串” 、 update 可以去做字串組合。
hash.update("SecTools.tw")
hash.update(" Ryan.Chen")
#實際上的結果是 "SecTools.tw Ryan.Chen"
hash.digest()
傳回當前數據的訊息摘要。
hash.hexdigest()
傳回當前數據的16進位制訊息摘要。
更多訊息可參考 https://docs.python.org/3/library/hashlib.html
hash可以用在哪?
因為不可逆的特性,可用於儲存用戶的密碼。 ( 存明碼的密碼在資料庫的話,開發者一點意識都沒有)
username | password |
---|---|
Wuton | e10adc3949ba59abbeza6147f20f883e |
Ryan | 123ef96e86145580cxxc87f0410ad153 |
SecTools.tw | 99b1c2188dza5sd2e403b1536010c2c9 |
實戰演練
keygenme-py
| 30 pointsTags: Category: Reverse Engineering
AUTHOR: SYREAL
Description
解法
Flag只給一半,實際上是由靜態的字串組合動態變數產生。
key_full_template_trial = key_part_static1_trial + key_part_dynamic1_trial + key_part_static2_trial
動態金鑰
def check_key(key, username_trial):
global key_full_template_trial
if len(key) != len(key_full_template_trial):
return False
else:
# Check static base key part --v
i = 0
for c in key_part_static1_trial:
if key[i] != c:
return False
i += 1
# TODO : test performance on toolbox container
# Check dynamic part --v
if key[i] != hashlib.sha256(username_trial).hexdigest()[4]:
return False
else:
i += 1
if key[i] != hashlib.sha256(username_trial).hexdigest()[5]:
return False
else:
i += 1
if key[i] != hashlib.sha256(username_trial).hexdigest()[3]:
return False
else:
i += 1
if key[i] != hashlib.sha256(username_trial).hexdigest()[6]:
return False
else:
i += 1
if key[i] != hashlib.sha256(username_trial).hexdigest()[2]:
return False
else:
i += 1
if key[i] != hashlib.sha256(username_trial).hexdigest()[7]:
return False
else:
i += 1
if key[i] != hashlib.sha256(username_trial).hexdigest()[1]:
return False
else:
i += 1
if key[i] != hashlib.sha256(username_trial).hexdigest()[8]:
return False
return True
簡單來說就是檢查第一部分是否正確,長度有沒有夠。之後動態金鑰hexdigest()[x]
x是數字,是不是跟我們前面提到的hexdigest()方法一樣,所以我們記錄數字。
分別是 4,5,3,6,2,7,1,8
知道原理後,開始寫solve.py
import hashlib
import base64
key_part_static1_trial = "picoCTF{1n_7h3_|<3y_of_"
key_part_dynamic1_trial = "xxxxxxxx"
key_part_static2_trial = "}"
key_full_template_trial = key_part_static1_trial + key_part_dynamic1_trial + key_part_static2_trial
username_trial = b"PRITCHARD"
potential_dynamic_key = ""
# where our input begins:
offset = 23
# positions in username_trial
positions = [4,5,3,6,2,7,1,8]
for p in positions:
potential_dynamic_key += hashlib.sha256(username_trial).hexdigest()[p]
key = key_part_static1_trial + potential_dynamic_key + key_part_static2_trial
print(key)
print(len(key))
成果取得Flag且正確~。