Conhecer a soma de verificação de uma parte não ajuda a calcular a soma de verificação do todo, então você terá que calcular a soma de verificação de todas as permutações possíveis até encontrar a correta. Se você tem partes n , existem n ! (fatorial de n ) permutações, e se todas são igualmente prováveis você terá que processar n ! / 2 em média até encontrar o caminho certo.
Quando você precisar calcular a soma de verificação de várias seqüências com o mesmo prefixo, poderá economizar tempo armazenando o estado interno da função MD5. Por exemplo, com três partes (X, Y, Z), você precisaria calcular MD5 (X + Y + Z), MD5 (X + Z + Y), MD5 (Y + X + Z), MD5 (Y + Z + X), MD5 (Z + X + Y) e MD5 (Z + Y + X). Se você iniciar o cálculo de MD5 (X,…), duplique o estado e conclua o cálculo para os dois sufixos Y + Z e Z + Y. Mas você precisa do estado interno para isso, não para a saída, e a maioria das ferramentas não dá acesso ao estado interno.
O hashlib do Python fornece um método copy
para copiar o estado interno de uma função hash. Ele também tem um iterador para enumerar permutações em sua biblioteca padrão.
#!/usr/bin/env python2
import hashlib, itertools, sys
def look_for_permutation(goal, filenames):
n = len(filenames)
files = map(open, filenames)
previous = map(lambda _: None, filenames)
states = [hashlib.md5()] + [None] * (n-2)
for current in itertools.permutations(files):
i = 0
while current[i] == previous[i]:
i += 1
state = states[i].copy()
for f in current[i:n-2]:
state.update(f.read())
i += 1
states[i] = state.copy()
f.seek(0)
state.update(current[n-2].read())
current[n-2].seek(0)
state.update(current[n-1].read())
if state.hexdigest() == goal:
return current
current[n-1].seek(0)
previous = current
return None
if __name__ == '__main__':
result = look_for_permutation(sys.argv[1], sys.argv[2:])
if result:
for f in result: print f.name
sys.exit(0)
else:
sys.exit(1)
Este script otimiza os cálculos de hash, mas lê o conteúdo do arquivo repetidamente. Se o conteúdo dos arquivos se encaixa na memória, você pode torná-lo um pouco mais rápido, carregando os arquivos de uma vez por todas.