Block-Cipher
大塊密碼作為記憶硬函式
我想知道,如果像塊密碼這樣大塊大小的東西是一個很好的記憶硬功能?
我見過的所有記憶硬鍵派生函式看起來都比這更複雜,這讓我質疑我對記憶硬性的理解。
以下函式對我來說看起來很難記憶(記憶體權衡看起來很昂貴):
size = 16MB / (F() word size in bytes) rounds = 1024 state = constants ⊕ (key || salt) for (i = 0; i < rounds * size; i++) state[i mod size] = state[i mod size] ⊕ F(state[i + 1 mod size]) result = state ⊕ key
這種類型 I 的廣義 Feistel 網路密鑰推導函式有多難記憶?
我一直在玩弄你的功能,我得出的結論是它並不難記憶。所需的記憶體量最多可以減少到
digestsize * 3 * rounds
.第一個問題是熵不會在整個州內雪崩,而是保持局部化。例如,在 1 輪之後,第 2 塊的狀態僅取決於第 3 塊的狀態。在 2 輪之後,它(間接地)僅取決於第 3 塊和第 4 塊的初始狀態。這意味著攻擊者可以在常量的大部分上預先計算 1024 輪,並且不需要每個密碼的記憶體。
一個可能的改進是將混合轉向,
state[i mod size] = state[i mod size] ⊕ F(state[i - 1 mod size])
以便每個塊都依賴於前一個而不是下一個,但是您以相同的順序生成和散列的事實將始終使權衡成為可能。更改該順序,最好以與數據無關的方式(例如通過在每一輪之後顛倒塊的順序),將使該方式更加困難。為了說明我的觀點,這裡有 2 個程式碼:1 個有,1 個沒有對你的函式進行記憶體權衡:
#!/usr/bin/env python3 from hashlib import sha512 blocks = 1000 rounds = 100 # pseudorandom constants created by hashing the literals "0", "1", ... "1000" constants = [sha512(str(i).encode()).digest() for i in range(0, blocks)] def mix(a, b): global operations operations += 1 # statistics b = sha512(b).digest() return bytearray(a ^ b for (a, b) in zip(a, b)) def more_memory(constant): state = list(constant) for i in range(0, rounds * blocks): state[i % blocks] = mix(state[i % blocks], state[(i + 1) % blocks]) # Make a checksum for the entire state state_hash = sha512() for s in state: state_hash.update(s) return state_hash.hexdigest()[:32] def less_memory(constant): def perform_round(sequence): first = None cur = next(sequence) try: while True: after = next(sequence) result = mix(cur, after) yield result if not first: first = result cur = after except StopIteration: pass yield mix(cur, first) current = (s for s in constant) for _ in range(0, rounds): current = perform_round(current) # Make a checksum for the entire state state_hash = sha512() for s in current: state_hash.update(s) return state_hash.hexdigest()[:32] operations = 0 print('Using a lot of memory: {} ({} mixing-operations)'.format(more_memory(constants), operations)) operations = 0 print('Using little memory: {} ({} mixing-operations)'.format(less_memory(constants), operations)) # Prints: # Using a lot of memory: e58f5665a2c388fc1420d4d1667f83df (100000 mixing-operations) # Using little memory: e58f5665a2c388fc1420d4d1667f83df (100000 mixing-operations)